Commit fcb10459 by Abseil Team Committed by Ashley Hedberg

Creation of LTS branch "lts_2018_12_18"

  - 44b0fafc Export of internal Abseil changes. by Abseil Team <absl-team@google.com>
  - 926bfeb9 Export of internal Abseil changes. by Abseil Team <absl-team@google.com>
  - 13327deb Export of internal Abseil changes. by Abseil Team <absl-team@google.com>
  - 3088e76c Export of internal Abseil changes. by Abseil Team <absl-team@google.com>
  - f6ae8168 Export of internal Abseil changes. by Abseil Team <absl-team@google.com>
  - a06c4a1d Export of internal Abseil changes. by Abseil Team <absl-team@google.com>
  - 7b46e1d3 Export of internal Abseil changes. by Abseil Team <absl-team@google.com>
  - 070f6e47 Export of internal Abseil changes. by Abseil Team <absl-team@google.com>
  - 7990fd45 Export of internal Abseil changes. by Abseil Team <absl-team@google.com>
  - f9517906 Export of internal Abseil changes. by Abseil Team <absl-team@google.com>
  - cc8dcd30 Export of internal Abseil changes. by Abseil Team <absl-team@google.com>
  - a705aa78 Merge pull request #194 from Mizux/windows by Xiaoyi Zhang <zhangxy988@gmail.com>
  - a4c3ffff Export of internal Abseil changes. by Abseil Team <absl-team@google.com>
  - 01174578 Merge pull request #201 from ccawley2011/fix-byteswap by Matt Calabrese <38107210+mattcalabrese-google@users.noreply.github.com>
  - f86f9413 Export of internal Abseil changes. by Abseil Team <absl-team@google.com>
  - 94c298e2 Export of internal Abseil changes. by Abseil Team <absl-team@google.com>
  - 0884a6a0 Export of internal Abseil changes. by Abseil Team <absl-team@google.com>
  - c16d5557 Export of internal Abseil changes. by Abseil Team <absl-team@google.com>
  - 45221ccc Export of internal Abseil changes. by Abseil Team <absl-team@google.com>
  - 2019e17a Export of internal Abseil changes. by Abseil Team <absl-team@google.com>
  - 5b70a891 Export of internal Abseil changes. by Abseil Team <absl-team@google.com>
  - a00bdd17 Export of internal Abseil changes. by Abseil Team <absl-team@google.com>
  - f340f773 Export of internal Abseil changes. by Abseil Team <absl-team@google.com>
  - 445998d7 Export of internal Abseil changes. by Abseil Team <absl-team@google.com>
  - e821380d Export of internal Abseil changes. by Abseil Team <absl-team@google.com>
  - f21d187b Export of internal Abseil changes. by Abseil Team <absl-team@google.com>
  - 5441bbe1 Fix code snippet in comment (#174) by Loo Rong Jie <loorongjie@gmail.com>
  - 5aae0cff Fix CMake build (#173) by Stephan Dollberg <stephan.dollberg@gmail.com>
  - 48cd2c3f Export of internal Abseil changes. by Abseil Team <absl-team@google.com>
  - e291c279 Export of internal Abseil changes. by Abseil Team <absl-team@google.com>
  - e01d9552 Export of internal Abseil changes. by Abseil Team <absl-team@google.com>
  - 8ff13740 Export of internal Abseil changes. by Abseil Team <absl-team@google.com>
  - 02451914 Export of internal Abseil changes. by Abseil Team <absl-team@google.com>
  - 921fd5cf Merge pull request #166 from rongjiecomputer/cmake-test by Gennadiy Civil <gennadiycivil@users.noreply.github.com>
  - fb462224 Export of internal Abseil changes. by Abseil Team <absl-team@google.com>
  - c075ad32 Export of internal Abseil changes. by Abseil Team <absl-team@google.com>
  - 0f4bc966 Export of internal Abseil changes. by Abseil Team <absl-team@google.com>
  - 6c7e5ffc Export of internal Abseil changes. by Abseil Team <absl-team@google.com>
  - d6df7691 Export of internal Abseil changes. by Abseil Team <absl-team@google.com>
  - 28080f5f Export of internal Abseil changes. by Abseil Team <absl-team@google.com>
  - 9c987f42 Export of internal Abseil changes. by Abseil Team <absl-team@google.com>
  - 5e7d459e Export of internal Abseil changes. by Abseil Team <absl-team@google.com>
  - bed5bd6e Export of internal Abseil changes. by Abseil Team <absl-team@google.com>
  - fefc8363 Export of internal Abseil changes. by Abseil Team <absl-team@google.com>
  - d8cfe9f2 Export of internal Abseil changes. by Abseil Team <absl-team@google.com>
  - ad5c960b Export of internal Abseil changes. by Abseil Team <absl-team@google.com>
  - 86f0fe93 Export of internal Abseil changes. by Abseil Team <absl-team@google.com>
  - f0f15c27 Export of internal Abseil changes. by Abseil Team <absl-team@google.com>
  - 29ff6d48 Removed "warning treated as error" flag from MSVC (#153) by vocaviking <vocaviking@users.noreply.github.com>
  - 083d04dd Export of internal Abseil changes. by Abseil Team <absl-team@google.com>
  - bea85b52 Export of internal Abseil changes. by Abseil Team <absl-team@google.com>
  - 8f96be6c Export of internal Abseil changes. by Abseil Team <absl-team@google.com>
  - 92e07e55 Merge pull request #152 from clnperez/fix-multi-defines-p... by Derek Mauro <761129+derekmauro@users.noreply.github.com>
  - 2125e644 Export of internal Abseil changes. by Abseil Team <absl-team@google.com>
  - 9acad869 Merge pull request #150 from OlafvdSpek/patch-2 by Jonathan Cohen <cohenjon@google.com>
  - c2e00d34 Export of internal Abseil changes. by Abseil Team <absl-team@google.com>
  - 9e060686 Export of internal Abseil changes. by Abseil Team <absl-team@google.com>
  - 7aa411ce Export of internal Abseil changes. by Abseil Team <absl-team@google.com>
  - 2c5af55e Export of internal Abseil changes. by Abseil Team <absl-team@google.com>
  - 44aa2752 Merge pull request #143 from rongjiecomputer/kernel by Xiaoyi Zhang <zhangxy988@gmail.com>
  - 42f22a28 Export of internal Abseil changes. by Abseil Team <absl-team@google.com>
  - b973bc53 Merge pull request #139 from siepkes/smartos-support by ahedberg <ahedberg@google.com>
  - e0def747 Export of internal Abseil changes. by Abseil Team <absl-team@google.com>
  - f826f1d4 Merge pull request #138 from edbaunton/remove-deprecated-... by ahedberg <ahedberg@google.com>
  - 7b50a4a9 Export of internal Abseil changes. by Abseil Team <absl-team@google.com>
  - a5030ca5 Merge pull request #144 from rongjiecomputer/winsock2 by Xiaoyi Zhang <zhangxy988@gmail.com>
  - 02687955 Export of internal Abseil changes. by Abseil Team <absl-team@google.com>
  - 8f612ebb Export of internal Abseil changes. by Abseil Team <absl-team@google.com>
  - 134496a3 Export of internal Abseil changes. by Abseil Team <absl-team@google.com>
  - ba8d6cf0 Export of internal Abseil changes. by Abseil Team <absl-team@google.com>
  - be1e84b9 Export of internal Abseil changes. by Abseil Team <absl-team@google.com>
  - 16ac2ec2 Merge pull request #134 from rongjiecomputer/cmake by Alex Strelnikov <strel@google.com>
  - 7efd8dc0 Export of internal Abseil changes. by Abseil Team <absl-team@google.com>
  - 87a4c078 Export of internal Abseil changes. by Abseil Team <absl-team@google.com>
  - 4491d606 Export of internal Abseil changes. by Abseil Team <absl-team@google.com>

GitOrigin-RevId: 44b0fafc
Change-Id: I2c427b5b41b2d34101922048b00f3d9dafcb498d
parent 6c7de165
# Ignore all bazel-* symlinks. # Ignore all bazel-* symlinks.
/bazel-* /bazel-*
# Ignore Bazel verbose explanations
--verbose_explanations
# Ignore CMake usual build directory
build
# Ignore Vim files
*.swp
# Ignore QtCreator Project file
CMakeLists.txt.user
# Ignore VS Code files
.vscode/*
# Abseil-specific compiler flags. See absl/copts.bzl for description.
# DO NOT CHANGE THIS FILE WITHOUT THE CORRESPONDING CHANGE TO absl/copts.bzl
list(APPEND GCC_FLAGS
-Wall
-Wextra
-Wcast-qual
-Wconversion-null
-Wmissing-declarations
-Woverlength-strings
-Wpointer-arith
-Wunused-local-typedefs
-Wunused-result
-Wvarargs
-Wwrite-strings
-Wno-sign-compare
)
list(APPEND GCC_TEST_FLAGS
-Wno-conversion-null
-Wno-missing-declarations
-Wno-sign-compare
-Wno-unused-function
-Wno-unused-parameter
-Wno-unused-private-field
)
list(APPEND LLVM_FLAGS
-Wall
-Wextra
-Weverything
-Wno-c++98-compat-pedantic
-Wno-conversion
-Wno-covered-switch-default
-Wno-deprecated
-Wno-disabled-macro-expansion
-Wno-double-promotion
-Wno-comma
-Wno-extra-semi
-Wno-packed
-Wno-padded
-Wno-sign-compare
-Wno-float-conversion
-Wno-float-equal
-Wno-format-nonliteral
-Wno-gcc-compat
-Wno-global-constructors
-Wno-exit-time-destructors
-Wno-nested-anon-types
-Wno-non-modular-include-in-module
-Wno-old-style-cast
-Wno-range-loop-analysis
-Wno-reserved-id-macro
-Wno-shorten-64-to-32
-Wno-switch-enum
-Wno-thread-safety-negative
-Wno-undef
-Wno-unknown-warning-option
-Wno-unreachable-code
-Wno-unused-macros
-Wno-weak-vtables
-Wbitfield-enum-conversion
-Wbool-conversion
-Wconstant-conversion
-Wenum-conversion
-Wint-conversion
-Wliteral-conversion
-Wnon-literal-null-conversion
-Wnull-conversion
-Wobjc-literal-conversion
-Wno-sign-conversion
-Wstring-conversion
)
list(APPEND LLVM_TEST_FLAGS
-Wno-c99-extensions
-Wno-missing-noreturn
-Wno-missing-prototypes
-Wno-missing-variable-declarations
-Wno-null-conversion
-Wno-shadow
-Wno-shift-sign-overflow
-Wno-sign-compare
-Wno-unused-function
-Wno-unused-member-function
-Wno-unused-parameter
-Wno-unused-private-field
-Wno-unused-template
-Wno-used-but-marked-unused
-Wno-zero-as-null-pointer-constant
-Wno-gnu-zero-variadic-macro-arguments
)
list(APPEND MSVC_FLAGS
/W3
/wd4005
/wd4018
/wd4068
/wd4180
/wd4244
/wd4267
/wd4800
/DNOMINMAX
/DWIN32_LEAN_AND_MEAN
/D_CRT_SECURE_NO_WARNINGS
/D_SCL_SECURE_NO_WARNINGS
/D_ENABLE_EXTENDED_ALIGNED_STORAGE
)
list(APPEND MSVC_TEST_FLAGS
/wd4101
/wd4503
)
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
set(ABSL_DEFAULT_COPTS "${GCC_FLAGS}")
set(ABSL_TEST_COPTS "${GCC_FLAGS};${GCC_TEST_FLAGS}")
set(ABSL_EXCEPTIONS_FLAG "-fexceptions")
elseif("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
# MATCHES so we get both Clang and AppleClang
set(ABSL_DEFAULT_COPTS "${LLVM_FLAGS}")
set(ABSL_TEST_COPTS "${LLVM_FLAGS};${LLVM_TEST_FLAGS}")
set(ABSL_EXCEPTIONS_FLAG "-fexceptions")
elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
set(ABSL_DEFAULT_COPTS "${MSVC_FLAGS}")
set(ABSL_TEST_COPTS "${MSVC_FLAGS};${MSVC_TEST_FLAGS}")
set(ABSL_EXCEPTIONS_FLAG "/U_HAS_EXCEPTIONS;/D_HAS_EXCEPTIONS=1;/EHsc")
else()
message(WARNING "Unknown compiler: ${CMAKE_CXX_COMPILER}. Building with no default flags")
set(ABSL_DEFAULT_COPTS "")
set(ABSL_TEST_COPTS "")
set(ABSL_EXCEPTIONS_FLAG "")
endif()
# This flag is used internally for Bazel builds and is kept here for consistency
set(ABSL_EXCEPTIONS_FLAG_LINKOPTS "")
if("${CMAKE_CXX_STANDARD}" EQUAL 98)
message(FATAL_ERROR "Abseil requires at least C++11")
elseif(NOT "${CMAKE_CXX_STANDARD}")
message(STATUS "No CMAKE_CXX_STANDARD set, assuming 11")
set(ABSL_CXX_STANDARD 11)
else()
set(ABSL_CXX_STANDARD "${CMAKE_CXX_STANDARD}")
endif()
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
# #
include(CMakeParseArguments) include(CMakeParseArguments)
include(AbseilConfigureCopts)
# The IDE folder for Abseil that will be used if Abseil is included in a CMake # The IDE folder for Abseil that will be used if Abseil is included in a CMake
# project that sets # project that sets
...@@ -48,7 +49,11 @@ function(absl_library) ...@@ -48,7 +49,11 @@ function(absl_library)
add_library(${_NAME} STATIC ${ABSL_LIB_SOURCES}) add_library(${_NAME} STATIC ${ABSL_LIB_SOURCES})
target_compile_options(${_NAME} PRIVATE ${ABSL_COMPILE_CXXFLAGS} ${ABSL_LIB_PRIVATE_COMPILE_FLAGS}) target_compile_options(${_NAME}
PRIVATE
${ABSL_LIB_PRIVATE_COMPILE_FLAGS}
${ABSL_DEFAULT_COPTS}
)
target_link_libraries(${_NAME} PUBLIC ${ABSL_LIB_PUBLIC_LIBRARIES}) target_link_libraries(${_NAME} PUBLIC ${ABSL_LIB_PUBLIC_LIBRARIES})
target_include_directories(${_NAME} target_include_directories(${_NAME}
PUBLIC ${ABSL_COMMON_INCLUDE_DIRS} ${ABSL_LIB_PUBLIC_INCLUDE_DIRS} PUBLIC ${ABSL_COMMON_INCLUDE_DIRS} ${ABSL_LIB_PUBLIC_INCLUDE_DIRS}
...@@ -57,12 +62,199 @@ function(absl_library) ...@@ -57,12 +62,199 @@ function(absl_library)
# Add all Abseil targets to a a folder in the IDE for organization. # Add all Abseil targets to a a folder in the IDE for organization.
set_property(TARGET ${_NAME} PROPERTY FOLDER ${ABSL_IDE_FOLDER}) set_property(TARGET ${_NAME} PROPERTY FOLDER ${ABSL_IDE_FOLDER})
set_property(TARGET ${_NAME} PROPERTY CXX_STANDARD ${ABSL_CXX_STANDARD})
set_property(TARGET ${_NAME} PROPERTY CXX_STANDARD_REQUIRED ON)
if(ABSL_LIB_EXPORT_NAME) if(ABSL_LIB_EXPORT_NAME)
add_library(absl::${ABSL_LIB_EXPORT_NAME} ALIAS ${_NAME}) add_library(absl::${ABSL_LIB_EXPORT_NAME} ALIAS ${_NAME})
endif() endif()
endfunction() endfunction()
# CMake function to imitate Bazel's cc_library rule.
#
# Parameters:
# NAME: name of target (see Note)
# HDRS: List of public header files for the library
# SRCS: List of source files for the library
# DEPS: List of other libraries to be linked in to the binary targets
# COPTS: List of private compile options
# DEFINES: List of public defines
# LINKOPTS: List of link options
# PUBLIC: Add this so that this library will be exported under absl:: (see Note).
# Also in IDE, target will appear in Abseil folder while non PUBLIC will be in Abseil/internal.
# TESTONLY: When added, this target will only be built if user passes -DABSL_RUN_TESTS=ON to CMake.
#
# Note:
# By default, absl_cc_library will always create a library named absl_internal_${NAME},
# and alias target absl::${NAME}.
# This is to reduce namespace pollution.
#
# absl_cc_library(
# NAME
# awesome
# HDRS
# "a.h"
# SRCS
# "a.cc"
# )
# absl_cc_library(
# NAME
# fantastic_lib
# SRCS
# "b.cc"
# DEPS
# absl_internal_awesome # not "awesome"!
# )
#
# If PUBLIC is set, absl_cc_library will instead create a target named
# absl_${NAME} and still an alias absl::${NAME}.
#
# absl_cc_library(
# NAME
# main_lib
# ...
# PUBLIC
# )
#
# User can then use the library as absl::main_lib (although absl_main_lib is defined too).
#
# TODO: Implement "ALWAYSLINK"
function(absl_cc_library)
cmake_parse_arguments(ABSL_CC_LIB
"DISABLE_INSTALL;PUBLIC;TESTONLY"
"NAME"
"HDRS;SRCS;COPTS;DEFINES;LINKOPTS;DEPS"
${ARGN}
)
if (NOT ABSL_CC_LIB_TESTONLY OR ABSL_RUN_TESTS)
if (ABSL_CC_LIB_PUBLIC)
set(_NAME "absl_${ABSL_CC_LIB_NAME}")
else()
set(_NAME "absl_internal_${ABSL_CC_LIB_NAME}")
endif()
# Check if this is a header-only library
if ("${ABSL_CC_LIB_SRCS}" STREQUAL "")
set(ABSL_CC_LIB_IS_INTERFACE 1)
else()
set(ABSL_CC_LIB_IS_INTERFACE 0)
endif()
if(NOT ABSL_CC_LIB_IS_INTERFACE)
add_library(${_NAME} STATIC "")
target_sources(${_NAME} PRIVATE ${ABSL_CC_LIB_SRCS} ${ABSL_CC_LIB_HDRS})
target_include_directories(${_NAME}
PUBLIC ${ABSL_COMMON_INCLUDE_DIRS})
target_compile_options(${_NAME}
PRIVATE ${ABSL_CC_LIB_COPTS})
target_link_libraries(${_NAME}
PUBLIC ${ABSL_CC_LIB_DEPS}
PRIVATE ${ABSL_CC_LIB_LINKOPTS}
)
target_compile_definitions(${_NAME} PUBLIC ${ABSL_CC_LIB_DEFINES})
# Add all Abseil targets to a a folder in the IDE for organization.
if(ABSL_CC_LIB_PUBLIC)
set_property(TARGET ${_NAME} PROPERTY FOLDER ${ABSL_IDE_FOLDER})
elseif(ABSL_CC_LIB_TESTONLY)
set_property(TARGET ${_NAME} PROPERTY FOLDER ${ABSL_IDE_FOLDER}/test)
else()
set_property(TARGET ${_NAME} PROPERTY FOLDER ${ABSL_IDE_FOLDER}/internal)
endif()
# INTERFACE libraries can't have the CXX_STANDARD property set
set_property(TARGET ${_NAME} PROPERTY CXX_STANDARD ${ABSL_CXX_STANDARD})
set_property(TARGET ${_NAME} PROPERTY CXX_STANDARD_REQUIRED ON)
else()
# Generating header-only library
add_library(${_NAME} INTERFACE)
target_include_directories(${_NAME}
INTERFACE ${ABSL_COMMON_INCLUDE_DIRS})
target_link_libraries(${_NAME}
INTERFACE ${ABSL_CC_LIB_DEPS} ${ABSL_CC_LIB_LINKOPTS}
)
target_compile_definitions(${_NAME} INTERFACE ${ABSL_CC_LIB_DEFINES})
endif()
add_library(absl::${ABSL_CC_LIB_NAME} ALIAS ${_NAME})
endif()
endfunction()
# absl_cc_test()
#
# CMake function to imitate Bazel's cc_test rule.
#
# Parameters:
# NAME: name of target (see Usage below)
# SRCS: List of source files for the binary
# DEPS: List of other libraries to be linked in to the binary targets
# COPTS: List of private compile options
# DEFINES: List of public defines
# LINKOPTS: List of link options
#
# Note:
# By default, absl_cc_test will always create a binary named absl_${NAME}.
# This will also add it to ctest list as absl_${NAME}.
#
# Usage:
# absl_cc_library(
# NAME
# awesome
# HDRS
# "a.h"
# SRCS
# "a.cc"
# PUBLIC
# )
#
# absl_cc_test(
# NAME
# awesome_test
# SRCS
# "awesome_test.cc"
# DEPS
# absl::awesome
# gmock
# gtest_main
# )
function(absl_cc_test)
if(NOT ABSL_RUN_TESTS)
return()
endif()
cmake_parse_arguments(ABSL_CC_TEST
""
"NAME"
"SRCS;COPTS;DEFINES;LINKOPTS;DEPS"
${ARGN}
)
set(_NAME "absl_${ABSL_CC_TEST_NAME}")
add_executable(${_NAME} "")
target_sources(${_NAME} PRIVATE ${ABSL_CC_TEST_SRCS})
target_include_directories(${_NAME}
PUBLIC ${ABSL_COMMON_INCLUDE_DIRS}
PRIVATE ${GMOCK_INCLUDE_DIRS} ${GTEST_INCLUDE_DIRS}
)
target_compile_definitions(${_NAME}
PUBLIC ${ABSL_CC_TEST_DEFINES}
)
target_compile_options(${_NAME}
PRIVATE ${ABSL_CC_TEST_COPTS}
)
target_link_libraries(${_NAME}
PUBLIC ${ABSL_CC_TEST_DEPS}
PRIVATE ${ABSL_CC_TEST_LINKOPTS}
)
# Add all Abseil targets to a a folder in the IDE for organization.
set_property(TARGET ${_NAME} PROPERTY FOLDER ${ABSL_IDE_FOLDER}/test)
set_property(TARGET ${_NAME} PROPERTY CXX_STANDARD ${ABSL_CXX_STANDARD})
set_property(TARGET ${_NAME} PROPERTY CXX_STANDARD_REQUIRED ON)
add_test(NAME ${_NAME} COMMAND ${_NAME})
endfunction()
# #
# header only virtual target creation # header only virtual target creation
...@@ -103,13 +295,15 @@ function(absl_header_library) ...@@ -103,13 +295,15 @@ function(absl_header_library)
# Add all Abseil targets to a a folder in the IDE for organization. # Add all Abseil targets to a a folder in the IDE for organization.
set_property(TARGET ${_NAME} PROPERTY FOLDER ${ABSL_IDE_FOLDER}) set_property(TARGET ${_NAME} PROPERTY FOLDER ${ABSL_IDE_FOLDER})
set_property(TARGET ${_NAME} PROPERTY CXX_STANDARD ${ABSL_CXX_STANDARD})
set_property(TARGET ${_NAME} PROPERTY CXX_STANDARD_REQUIRED ON)
if(ABSL_HO_LIB_EXPORT_NAME) if(ABSL_HO_LIB_EXPORT_NAME)
add_library(absl::${ABSL_HO_LIB_EXPORT_NAME} ALIAS ${_NAME}) add_library(absl::${ABSL_HO_LIB_EXPORT_NAME} ALIAS ${_NAME})
endif() endif()
endfunction() endfunction()
# #
# create an abseil unit_test and add it to the executed test list # create an abseil unit_test and add it to the executed test list
# #
...@@ -123,7 +317,7 @@ endfunction() ...@@ -123,7 +317,7 @@ endfunction()
# #
# all tests will be register for execution with add_test() # all tests will be register for execution with add_test()
# #
# test compilation and execution is disable when BUILD_TESTING=OFF # test compilation and execution is disable when ABSL_RUN_TESTS=OFF
# #
function(absl_test) function(absl_test)
...@@ -135,25 +329,32 @@ function(absl_test) ...@@ -135,25 +329,32 @@ function(absl_test)
) )
if(BUILD_TESTING) if(ABSL_RUN_TESTS)
set(_NAME ${ABSL_TEST_TARGET}) set(_NAME "absl_${ABSL_TEST_TARGET}")
string(TOUPPER ${_NAME} _UPPER_NAME) string(TOUPPER ${_NAME} _UPPER_NAME)
add_executable(${_NAME}_bin ${ABSL_TEST_SOURCES}) add_executable(${_NAME} ${ABSL_TEST_SOURCES})
target_compile_options(${_NAME}_bin PRIVATE ${ABSL_COMPILE_CXXFLAGS} ${ABSL_TEST_PRIVATE_COMPILE_FLAGS}) target_compile_options(${_NAME}
target_link_libraries(${_NAME}_bin PUBLIC ${ABSL_TEST_PUBLIC_LIBRARIES} ${ABSL_TEST_COMMON_LIBRARIES}) PRIVATE
target_include_directories(${_NAME}_bin ${ABSL_TEST_PRIVATE_COMPILE_FLAGS}
${ABSL_TEST_COPTS}
)
target_link_libraries(${_NAME} PUBLIC ${ABSL_TEST_PUBLIC_LIBRARIES} ${ABSL_TEST_COMMON_LIBRARIES})
target_include_directories(${_NAME}
PUBLIC ${ABSL_COMMON_INCLUDE_DIRS} ${ABSL_TEST_PUBLIC_INCLUDE_DIRS} PUBLIC ${ABSL_COMMON_INCLUDE_DIRS} ${ABSL_TEST_PUBLIC_INCLUDE_DIRS}
PRIVATE ${GMOCK_INCLUDE_DIRS} ${GTEST_INCLUDE_DIRS} PRIVATE ${GMOCK_INCLUDE_DIRS} ${GTEST_INCLUDE_DIRS}
) )
# Add all Abseil targets to a a folder in the IDE for organization. # Add all Abseil targets to a a folder in the IDE for organization.
set_property(TARGET ${_NAME}_bin PROPERTY FOLDER ${ABSL_IDE_FOLDER}) set_property(TARGET ${_NAME} PROPERTY FOLDER ${ABSL_IDE_FOLDER})
set_property(TARGET ${_NAME} PROPERTY CXX_STANDARD ${ABSL_CXX_STANDARD})
set_property(TARGET ${_NAME} PROPERTY CXX_STANDARD_REQUIRED ON)
add_test(${_NAME} ${_NAME}_bin) add_test(NAME ${_NAME} COMMAND ${_NAME})
endif(BUILD_TESTING) endif(ABSL_RUN_TESTS)
endfunction() endfunction()
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
# Download the latest googletest from Github master # Download the latest googletest from Github master
configure_file( configure_file(
${CMAKE_CURRENT_LIST_DIR}/CMakeLists.txt.in ${CMAKE_CURRENT_LIST_DIR}/CMakeLists.txt.in
googletest-download/CMakeLists.txt ${CMAKE_BINARY_DIR}/googletest-download/CMakeLists.txt
) )
# Configure and build the downloaded googletest source # Configure and build the downloaded googletest source
......
...@@ -17,9 +17,15 @@ ...@@ -17,9 +17,15 @@
# We require 3.0 for modern, target-based CMake. We require 3.1 for the use of # We require 3.0 for modern, target-based CMake. We require 3.1 for the use of
# CXX_STANDARD in our targets. # CXX_STANDARD in our targets.
cmake_minimum_required(VERSION 3.1) cmake_minimum_required(VERSION 3.1)
# Compiler id for Apple Clang is now AppleClang.
if (POLICY CMP0025)
cmake_policy(SET CMP0025 NEW)
endif()
project(absl) project(absl)
list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/CMake) list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR}/CMake)
include(GNUInstallDirs) include(GNUInstallDirs)
include(AbseilHelpers) include(AbseilHelpers)
...@@ -32,8 +38,16 @@ if (MSVC) ...@@ -32,8 +38,16 @@ if (MSVC)
# /wd4244 conversion from 'type1' to 'type2' # /wd4244 conversion from 'type1' to 'type2'
# /wd4267 conversion from 'size_t' to 'type2' # /wd4267 conversion from 'size_t' to 'type2'
# /wd4800 force value to bool 'true' or 'false' (performance warning) # /wd4800 force value to bool 'true' or 'false' (performance warning)
add_compile_options(/W3 /WX /wd4005 /wd4068 /wd4244 /wd4267 /wd4800) add_compile_options(/W3 /wd4005 /wd4068 /wd4244 /wd4267 /wd4800)
add_definitions(/DNOMINMAX /DWIN32_LEAN_AND_MEAN=1 /D_CRT_SECURE_NO_WARNINGS /D_SCL_SECURE_NO_WARNINGS) # /D_ENABLE_EXTENDED_ALIGNED_STORAGE Introduced in VS 2017 15.8, before the
# member type would non-conformingly have an alignment of only alignof(max_align_t).
add_definitions(
/DNOMINMAX
/DWIN32_LEAN_AND_MEAN=1
/D_CRT_SECURE_NO_WARNINGS
/D_SCL_SECURE_NO_WARNINGS
/D_ENABLE_EXTENDED_ALIGNED_STORAGE
)
else() else()
set(ABSL_STD_CXX_FLAG "-std=c++11" CACHE STRING "c++ std flag (default: c++11)") set(ABSL_STD_CXX_FLAG "-std=c++11" CACHE STRING "c++ std flag (default: c++11)")
endif() endif()
...@@ -60,6 +74,12 @@ set(CMAKE_CXX_FLAGS "${ABSL_STD_CXX_FLAG} ${CMAKE_CXX_FLAGS}") ...@@ -60,6 +74,12 @@ set(CMAKE_CXX_FLAGS "${ABSL_STD_CXX_FLAG} ${CMAKE_CXX_FLAGS}")
# -fexceptions # -fexceptions
set(ABSL_EXCEPTIONS_FLAG "${CMAKE_CXX_EXCEPTIONS}") set(ABSL_EXCEPTIONS_FLAG "${CMAKE_CXX_EXCEPTIONS}")
if("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
set(ABSL_USING_CLANG ON)
else()
set(ABSL_USING_CLANG OFF)
endif()
# find dependencies # find dependencies
## pthread ## pthread
find_package(Threads REQUIRED) find_package(Threads REQUIRED)
......
...@@ -18,6 +18,53 @@ You generally only need to submit a CLA once, so if you've already submitted one ...@@ -18,6 +18,53 @@ You generally only need to submit a CLA once, so if you've already submitted one
(even if it was for a different project), you probably don't need to do it (even if it was for a different project), you probably don't need to do it
again. again.
## Contribution Guidelines
Potential contributors sometimes ask us if the Abseil project is the appropriate
home for their utility library code or for specific functions implementing
missing portions of the standard. Often, the answer to this question is "no".
We’d like to articulate our thinking on this issue so that our choices can be
understood by everyone and so that contributors can have a better intuition
about whether Abseil might be interested in adopting a new library.
### Priorities
Although our mission is to augment the C++ standard library, our goal is not to
provide a full forward-compatible implementation of the latest standard. For us
to consider a library for inclusion in Abseil, it is not enough that a library
is useful. We generally choose to release a library when it meets at least one
of the following criteria:
* **Widespread usage** - Using our internal codebase to help gauge usage, most
of the libraries we've released have tens of thousands of users.
* **Anticipated widespread usage** - Pre-adoption of some standard-compliant
APIs may not have broad adoption initially but can be expected to pick up
usage when it replaces legacy APIs. `absl::from_chars`, for example,
replaces existing code that converts strings to numbers and will therefore
likely see usage growth.
* **High impact** - APIs that provide a key solution to a specific problem,
such as `absl::FixedArray`, have higher impact than usage numbers may signal
and are released because of their importance.
* **Direct support for a library that falls under one of the above** - When we
want access to a smaller library as an implementation detail for a
higher-priority library we plan to release, we may release it, as we did
with portions of `absl/meta/type_traits.h`. One consequence of this is that
the presence of a library in Abseil does not necessarily mean that other
similar libraries would be a high priority.
### API Freeze Consequences
Via the
[Abseil Compatibility Guidelines](https://abseil.io/about/compatibility), we
have promised a large degree of API stability. In particular, we will not make
backward-incompatible changes to released APIs without also shipping a tool or
process that can upgrade our users' code. We are not yet at the point of easily
releasing such tools. Therefore, at this time, shipping a library establishes an
API contract which is borderline unchangeable. (We can add new functionality,
but we cannot easily change existing behavior.) This constraint forces us to
very carefully review all APIs that we ship.
## Coding Style ## Coding Style
To keep the source consistent, readable, diffable and easy to merge, we use a To keep the source consistent, readable, diffable and easy to merge, we use a
......
...@@ -63,10 +63,14 @@ Abseil contains the following C++ library components: ...@@ -63,10 +63,14 @@ Abseil contains the following C++ library components:
<br /> The `algorithm` library contains additions to the C++ `<algorithm>` <br /> The `algorithm` library contains additions to the C++ `<algorithm>`
library and container-based versions of such algorithms. library and container-based versions of such algorithms.
* [`container`](absl/container/) * [`container`](absl/container/)
<br /> The `container` library contains additional STL-style containers. <br /> The `container` library contains additional STL-style containers,
including Abseil's unordered "Swiss table" containers.
* [`debugging`](absl/debugging/) * [`debugging`](absl/debugging/)
<br /> The `debugging` library contains code useful for enabling leak <br /> The `debugging` library contains code useful for enabling leak
checks. Future updates will add stacktrace and symbolization utilities. checks, and stacktrace and symbolization utilities.
* [`hash`](absl/hash/)
<br /> The `hash` library contains the hashing framework and default hash
functor implementations for hashable types in Abseil.
* [`memory`](absl/memory/) * [`memory`](absl/memory/)
<br /> The `memory` library contains C++11-compatible versions of <br /> The `memory` library contains C++11-compatible versions of
`std::make_unique()` and related memory management facilities. `std::make_unique()` and related memory management facilities.
...@@ -90,6 +94,8 @@ Abseil contains the following C++ library components: ...@@ -90,6 +94,8 @@ Abseil contains the following C++ library components:
* [`types`](absl/types/) * [`types`](absl/types/)
<br /> The `types` library contains non-container utility types, like a <br /> The `types` library contains non-container utility types, like a
C++11-compatible version of the C++17 `std::optional` type. C++11-compatible version of the C++17 `std::optional` type.
* [`utility`](absl/utility/)
<br /> The `utility` library contains utility and helper code.
## License ## License
......
workspace(name = "com_google_absl") workspace(name = "com_google_absl")
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
# Bazel toolchains # Bazel toolchains
http_archive( http_archive(
name = "bazel_toolchains", name = "bazel_toolchains",
urls = [ urls = [
"https://mirror.bazel.build/github.com/bazelbuild/bazel-toolchains/archive/287b64e0a211fb7c23b74695f8d5f5205b61f4eb.tar.gz", "https://mirror.bazel.build/github.com/bazelbuild/bazel-toolchains/archive/bc09b995c137df042bb80a395b73d7ce6f26afbe.tar.gz",
"https://github.com/bazelbuild/bazel-toolchains/archive/287b64e0a211fb7c23b74695f8d5f5205b61f4eb.tar.gz", "https://github.com/bazelbuild/bazel-toolchains/archive/bc09b995c137df042bb80a395b73d7ce6f26afbe.tar.gz",
], ],
strip_prefix = "bazel-toolchains-287b64e0a211fb7c23b74695f8d5f5205b61f4eb", strip_prefix = "bazel-toolchains-bc09b995c137df042bb80a395b73d7ce6f26afbe",
sha256 = "aca8ac6afd7745027ee4a43032b51a725a61a75a30f02cc58681ee87e4dcdf4b", sha256 = "4329663fe6c523425ad4d3c989a8ac026b04e1acedeceb56aa4b190fa7f3973c",
) )
# 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/4e4df226fc197c0dda6e37f5c8c3845ca1e73a49.zip"], urls = ["https://github.com/google/googletest/archive/b4d4438df9479675a632b2f11125e57133822ece.zip"], # 2018-07-16
strip_prefix = "googletest-4e4df226fc197c0dda6e37f5c8c3845ca1e73a49", strip_prefix = "googletest-b4d4438df9479675a632b2f11125e57133822ece",
sha256 = "d4179caf54410968d1fff0b869e7d74803dd30209ee6645ccf1ca65ab6cf5e5a", sha256 = "5aaa5d566517cae711e2a3505ea9a6438be1b37fcaae0ebcb96ccba9aa56f23a",
) )
# Google benchmark. # Google benchmark.
...@@ -25,11 +27,3 @@ http_archive( ...@@ -25,11 +27,3 @@ http_archive(
strip_prefix = "benchmark-16703ff83c1ae6d53e5155df3bb3ab0bc96083be", strip_prefix = "benchmark-16703ff83c1ae6d53e5155df3bb3ab0bc96083be",
sha256 = "59f918c8ccd4d74b6ac43484467b500f1d64b40cc1010daa055375b322a43ba3", sha256 = "59f918c8ccd4d74b6ac43484467b500f1d64b40cc1010daa055375b322a43ba3",
) )
# RE2 regular-expression framework. Used by some unit-tests.
http_archive(
name = "com_googlesource_code_re2",
urls = ["https://github.com/google/re2/archive/6cf8ccd82dbaab2668e9b13596c68183c9ecd13f.zip"],
strip_prefix = "re2-6cf8ccd82dbaab2668e9b13596c68183c9ecd13f",
sha256 = "279a852219dbfc504501775596089d30e9c0b29664ce4128b0ac4c841471a16a",
)
...@@ -18,11 +18,10 @@ package(default_visibility = ["//visibility:public"]) ...@@ -18,11 +18,10 @@ package(default_visibility = ["//visibility:public"])
licenses(["notice"]) # Apache 2.0 licenses(["notice"]) # Apache 2.0
config_setting( load(":compiler_config_setting.bzl", "create_llvm_config")
create_llvm_config(
name = "llvm_compiler", name = "llvm_compiler",
values = {
"compiler": "llvm",
},
visibility = [":__subpackages__"], visibility = [":__subpackages__"],
) )
......
...@@ -20,6 +20,7 @@ add_subdirectory(base) ...@@ -20,6 +20,7 @@ add_subdirectory(base)
add_subdirectory(algorithm) add_subdirectory(algorithm)
add_subdirectory(container) add_subdirectory(container)
add_subdirectory(debugging) add_subdirectory(debugging)
add_subdirectory(hash)
add_subdirectory(memory) add_subdirectory(memory)
add_subdirectory(meta) add_subdirectory(meta)
add_subdirectory(numeric) add_subdirectory(numeric)
......
...@@ -14,50 +14,50 @@ ...@@ -14,50 +14,50 @@
# limitations under the License. # limitations under the License.
# #
list(APPEND ALGORITHM_PUBLIC_HEADERS absl_cc_library(
"algorithm.h" NAME
"container.h"
)
#
## TESTS
#
# test algorithm_test
list(APPEND ALGORITHM_TEST_SRC
"algorithm_test.cc"
${ALGORITHM_PUBLIC_HEADERS}
${ALGORITHM_INTERNAL_HEADERS}
)
absl_header_library(
TARGET
absl_algorithm
EXPORT_NAME
algorithm algorithm
HDRS
"algorithm.h"
COPTS
${ABSL_DEFAULT_COPTS}
PUBLIC
) )
absl_test( absl_cc_test(
TARGET NAME
algorithm_test algorithm_test
SOURCES SRCS
${ALGORITHM_TEST_SRC} "algorithm_test.cc"
PUBLIC_LIBRARIES DEPS
absl::algorithm absl::algorithm
gmock_main
) )
absl_cc_library(
NAME
algorithm_container
HDRS
"container.h"
COPTS
${ABSL_DEFAULT_COPTS}
DEPS
absl::algorithm
absl::core_headers
absl::meta
PUBLIC
)
absl_cc_test(
NAME
# test container_test
set(CONTAINER_TEST_SRC "container_test.cc")
absl_test(
TARGET
container_test container_test
SOURCES SRCS
${CONTAINER_TEST_SRC} "container_test.cc"
PUBLIC_LIBRARIES DEPS
absl::algorithm absl::algorithm_container
absl::base
absl::core_headers
absl::memory
absl::span
gmock_main
) )
...@@ -27,7 +27,7 @@ ...@@ -27,7 +27,7 @@
#include <type_traits> #include <type_traits>
namespace absl { namespace absl {
inline namespace lts_2018_06_20 { inline namespace lts_2018_12_18 {
namespace algorithm_internal { namespace algorithm_internal {
...@@ -146,7 +146,7 @@ ForwardIterator rotate(ForwardIterator first, ForwardIterator middle, ...@@ -146,7 +146,7 @@ ForwardIterator rotate(ForwardIterator first, ForwardIterator middle,
ForwardIterator>()); ForwardIterator>());
} }
} // inline namespace lts_2018_06_20 } // inline namespace lts_2018_12_18
} // namespace absl } // namespace absl
#endif // ABSL_ALGORITHM_ALGORITHM_H_ #endif // ABSL_ALGORITHM_ALGORITHM_H_
...@@ -46,6 +46,8 @@ ...@@ -46,6 +46,8 @@
#include <iterator> #include <iterator>
#include <numeric> #include <numeric>
#include <type_traits> #include <type_traits>
#include <unordered_map>
#include <unordered_set>
#include <utility> #include <utility>
#include <vector> #include <vector>
...@@ -54,8 +56,7 @@ ...@@ -54,8 +56,7 @@
#include "absl/meta/type_traits.h" #include "absl/meta/type_traits.h"
namespace absl { namespace absl {
inline namespace lts_2018_06_20 { inline namespace lts_2018_12_18 {
namespace container_algorithm_internal { namespace container_algorithm_internal {
// NOTE: it is important to defer to ADL lookup for building with C++ modules, // NOTE: it is important to defer to ADL lookup for building with C++ modules,
...@@ -102,6 +103,17 @@ ContainerIter<C> c_begin(C& c) { return begin(c); } ...@@ -102,6 +103,17 @@ ContainerIter<C> c_begin(C& c) { return begin(c); }
template <typename C> template <typename C>
ContainerIter<C> c_end(C& c) { return end(c); } ContainerIter<C> c_end(C& c) { return end(c); }
template <typename T>
struct IsUnorderedContainer : std::false_type {};
template <class Key, class T, class Hash, class KeyEqual, class Allocator>
struct IsUnorderedContainer<
std::unordered_map<Key, T, Hash, KeyEqual, Allocator>> : std::true_type {};
template <class Key, class Hash, class KeyEqual, class Allocator>
struct IsUnorderedContainer<std::unordered_set<Key, Hash, KeyEqual, Allocator>>
: std::true_type {};
} // namespace container_algorithm_internal } // namespace container_algorithm_internal
// PUBLIC API // PUBLIC API
...@@ -315,7 +327,7 @@ container_algorithm_internal::ContainerDifferenceType<const C> c_count_if( ...@@ -315,7 +327,7 @@ container_algorithm_internal::ContainerDifferenceType<const C> c_count_if(
// c_mismatch() // c_mismatch()
// //
// Container-based version of the <algorithm> `std::mismatchf()` function to // Container-based version of the <algorithm> `std::mismatch()` function to
// return the first element where two ordered containers differ. // return the first element where two ordered containers differ.
template <typename C1, typename C2> template <typename C1, typename C2>
container_algorithm_internal::ContainerIterPairType<C1, C2> container_algorithm_internal::ContainerIterPairType<C1, C2>
...@@ -495,7 +507,7 @@ BidirectionalIterator c_copy_backward(const C& src, ...@@ -495,7 +507,7 @@ BidirectionalIterator c_copy_backward(const C& src,
// Container-based version of the <algorithm> `std::move()` function to move // Container-based version of the <algorithm> `std::move()` function to move
// a container's elements into an iterator. // a container's elements into an iterator.
template <typename C, typename OutputIterator> template <typename C, typename OutputIterator>
OutputIterator c_move(C& src, OutputIterator dest) { OutputIterator c_move(C&& src, OutputIterator dest) {
return std::move(container_algorithm_internal::c_begin(src), return std::move(container_algorithm_internal::c_begin(src),
container_algorithm_internal::c_end(src), dest); container_algorithm_internal::c_end(src), dest);
} }
...@@ -635,7 +647,7 @@ container_algorithm_internal::ContainerIter<C> c_generate_n(C& c, Size n, ...@@ -635,7 +647,7 @@ container_algorithm_internal::ContainerIter<C> c_generate_n(C& c, Size n,
// Note: `c_xx()` <algorithm> container versions for `remove()`, `remove_if()`, // Note: `c_xx()` <algorithm> container versions for `remove()`, `remove_if()`,
// and `unique()` are omitted, because it's not clear whether or not such // and `unique()` are omitted, because it's not clear whether or not such
// functions should call erase their supplied sequences afterwards. Either // functions should call erase on their supplied sequences afterwards. Either
// behavior would be surprising for a different set of users. // behavior would be surprising for a different set of users.
// //
...@@ -1155,7 +1167,13 @@ bool c_includes(const C1& c1, const C2& c2, Compare&& comp) { ...@@ -1155,7 +1167,13 @@ bool c_includes(const C1& c1, const C2& c2, Compare&& comp) {
// Container-based version of the <algorithm> `std::set_union()` function // Container-based version of the <algorithm> `std::set_union()` function
// to return an iterator containing the union of two containers; duplicate // to return an iterator containing the union of two containers; duplicate
// values are not copied into the output. // values are not copied into the output.
template <typename C1, typename C2, typename OutputIterator> template <typename C1, typename C2, typename OutputIterator,
typename = typename std::enable_if<
!container_algorithm_internal::IsUnorderedContainer<C1>::value,
void>::type,
typename = typename std::enable_if<
!container_algorithm_internal::IsUnorderedContainer<C2>::value,
void>::type>
OutputIterator c_set_union(const C1& c1, const C2& c2, OutputIterator output) { OutputIterator c_set_union(const C1& c1, const C2& c2, OutputIterator output) {
return std::set_union(container_algorithm_internal::c_begin(c1), return std::set_union(container_algorithm_internal::c_begin(c1),
container_algorithm_internal::c_end(c1), container_algorithm_internal::c_end(c1),
...@@ -1165,7 +1183,13 @@ OutputIterator c_set_union(const C1& c1, const C2& c2, OutputIterator output) { ...@@ -1165,7 +1183,13 @@ OutputIterator c_set_union(const C1& c1, const C2& c2, OutputIterator output) {
// Overload of c_set_union() for performing a merge using a `comp` other than // Overload of c_set_union() for performing a merge using a `comp` other than
// `operator<`. // `operator<`.
template <typename C1, typename C2, typename OutputIterator, typename Compare> template <typename C1, typename C2, typename OutputIterator, typename Compare,
typename = typename std::enable_if<
!container_algorithm_internal::IsUnorderedContainer<C1>::value,
void>::type,
typename = typename std::enable_if<
!container_algorithm_internal::IsUnorderedContainer<C2>::value,
void>::type>
OutputIterator c_set_union(const C1& c1, const C2& c2, OutputIterator output, OutputIterator c_set_union(const C1& c1, const C2& c2, OutputIterator output,
Compare&& comp) { Compare&& comp) {
return std::set_union(container_algorithm_internal::c_begin(c1), return std::set_union(container_algorithm_internal::c_begin(c1),
...@@ -1179,7 +1203,13 @@ OutputIterator c_set_union(const C1& c1, const C2& c2, OutputIterator output, ...@@ -1179,7 +1203,13 @@ OutputIterator c_set_union(const C1& c1, const C2& c2, OutputIterator output,
// //
// Container-based version of the <algorithm> `std::set_intersection()` function // Container-based version of the <algorithm> `std::set_intersection()` function
// to return an iterator containing the intersection of two containers. // to return an iterator containing the intersection of two containers.
template <typename C1, typename C2, typename OutputIterator> template <typename C1, typename C2, typename OutputIterator,
typename = typename std::enable_if<
!container_algorithm_internal::IsUnorderedContainer<C1>::value,
void>::type,
typename = typename std::enable_if<
!container_algorithm_internal::IsUnorderedContainer<C2>::value,
void>::type>
OutputIterator c_set_intersection(const C1& c1, const C2& c2, OutputIterator c_set_intersection(const C1& c1, const C2& c2,
OutputIterator output) { OutputIterator output) {
return std::set_intersection(container_algorithm_internal::c_begin(c1), return std::set_intersection(container_algorithm_internal::c_begin(c1),
...@@ -1190,7 +1220,13 @@ OutputIterator c_set_intersection(const C1& c1, const C2& c2, ...@@ -1190,7 +1220,13 @@ OutputIterator c_set_intersection(const C1& c1, const C2& c2,
// Overload of c_set_intersection() for performing a merge using a `comp` other // Overload of c_set_intersection() for performing a merge using a `comp` other
// than `operator<`. // than `operator<`.
template <typename C1, typename C2, typename OutputIterator, typename Compare> template <typename C1, typename C2, typename OutputIterator, typename Compare,
typename = typename std::enable_if<
!container_algorithm_internal::IsUnorderedContainer<C1>::value,
void>::type,
typename = typename std::enable_if<
!container_algorithm_internal::IsUnorderedContainer<C2>::value,
void>::type>
OutputIterator c_set_intersection(const C1& c1, const C2& c2, OutputIterator c_set_intersection(const C1& c1, const C2& c2,
OutputIterator output, Compare&& comp) { OutputIterator output, Compare&& comp) {
return std::set_intersection(container_algorithm_internal::c_begin(c1), return std::set_intersection(container_algorithm_internal::c_begin(c1),
...@@ -1205,7 +1241,13 @@ OutputIterator c_set_intersection(const C1& c1, const C2& c2, ...@@ -1205,7 +1241,13 @@ OutputIterator c_set_intersection(const C1& c1, const C2& c2,
// Container-based version of the <algorithm> `std::set_difference()` function // Container-based version of the <algorithm> `std::set_difference()` function
// to return an iterator containing elements present in the first container but // to return an iterator containing elements present in the first container but
// not in the second. // not in the second.
template <typename C1, typename C2, typename OutputIterator> template <typename C1, typename C2, typename OutputIterator,
typename = typename std::enable_if<
!container_algorithm_internal::IsUnorderedContainer<C1>::value,
void>::type,
typename = typename std::enable_if<
!container_algorithm_internal::IsUnorderedContainer<C2>::value,
void>::type>
OutputIterator c_set_difference(const C1& c1, const C2& c2, OutputIterator c_set_difference(const C1& c1, const C2& c2,
OutputIterator output) { OutputIterator output) {
return std::set_difference(container_algorithm_internal::c_begin(c1), return std::set_difference(container_algorithm_internal::c_begin(c1),
...@@ -1216,7 +1258,13 @@ OutputIterator c_set_difference(const C1& c1, const C2& c2, ...@@ -1216,7 +1258,13 @@ OutputIterator c_set_difference(const C1& c1, const C2& c2,
// Overload of c_set_difference() for performing a merge using a `comp` other // Overload of c_set_difference() for performing a merge using a `comp` other
// than `operator<`. // than `operator<`.
template <typename C1, typename C2, typename OutputIterator, typename Compare> template <typename C1, typename C2, typename OutputIterator, typename Compare,
typename = typename std::enable_if<
!container_algorithm_internal::IsUnorderedContainer<C1>::value,
void>::type,
typename = typename std::enable_if<
!container_algorithm_internal::IsUnorderedContainer<C2>::value,
void>::type>
OutputIterator c_set_difference(const C1& c1, const C2& c2, OutputIterator c_set_difference(const C1& c1, const C2& c2,
OutputIterator output, Compare&& comp) { OutputIterator output, Compare&& comp) {
return std::set_difference(container_algorithm_internal::c_begin(c1), return std::set_difference(container_algorithm_internal::c_begin(c1),
...@@ -1231,7 +1279,13 @@ OutputIterator c_set_difference(const C1& c1, const C2& c2, ...@@ -1231,7 +1279,13 @@ OutputIterator c_set_difference(const C1& c1, const C2& c2,
// Container-based version of the <algorithm> `std::set_symmetric_difference()` // Container-based version of the <algorithm> `std::set_symmetric_difference()`
// function to return an iterator containing elements present in either one // function to return an iterator containing elements present in either one
// container or the other, but not both. // container or the other, but not both.
template <typename C1, typename C2, typename OutputIterator> template <typename C1, typename C2, typename OutputIterator,
typename = typename std::enable_if<
!container_algorithm_internal::IsUnorderedContainer<C1>::value,
void>::type,
typename = typename std::enable_if<
!container_algorithm_internal::IsUnorderedContainer<C2>::value,
void>::type>
OutputIterator c_set_symmetric_difference(const C1& c1, const C2& c2, OutputIterator c_set_symmetric_difference(const C1& c1, const C2& c2,
OutputIterator output) { OutputIterator output) {
return std::set_symmetric_difference( return std::set_symmetric_difference(
...@@ -1243,7 +1297,13 @@ OutputIterator c_set_symmetric_difference(const C1& c1, const C2& c2, ...@@ -1243,7 +1297,13 @@ OutputIterator c_set_symmetric_difference(const C1& c1, const C2& c2,
// Overload of c_set_symmetric_difference() for performing a merge using a // Overload of c_set_symmetric_difference() for performing a merge using a
// `comp` other than `operator<`. // `comp` other than `operator<`.
template <typename C1, typename C2, typename OutputIterator, typename Compare> template <typename C1, typename C2, typename OutputIterator, typename Compare,
typename = typename std::enable_if<
!container_algorithm_internal::IsUnorderedContainer<C1>::value,
void>::type,
typename = typename std::enable_if<
!container_algorithm_internal::IsUnorderedContainer<C2>::value,
void>::type>
OutputIterator c_set_symmetric_difference(const C1& c1, const C2& c2, OutputIterator c_set_symmetric_difference(const C1& c1, const C2& c2,
OutputIterator output, OutputIterator output,
Compare&& comp) { Compare&& comp) {
...@@ -1638,7 +1698,7 @@ OutputIt c_partial_sum(const InputSequence& input, OutputIt output_first, ...@@ -1638,7 +1698,7 @@ OutputIt c_partial_sum(const InputSequence& input, OutputIt output_first,
output_first, std::forward<BinaryOp>(op)); output_first, std::forward<BinaryOp>(op));
} }
} // inline namespace lts_2018_06_20 } // inline namespace lts_2018_12_18
} // namespace absl } // namespace absl
#endif // ABSL_ALGORITHM_CONTAINER_H_ #endif // ABSL_ALGORITHM_CONTAINER_H_
...@@ -636,6 +636,21 @@ TEST(MutatingTest, Move) { ...@@ -636,6 +636,21 @@ TEST(MutatingTest, Move) {
Pointee(5))); Pointee(5)));
} }
TEST(MutatingTest, MoveWithRvalue) {
auto MakeRValueSrc = [] {
std::vector<std::unique_ptr<int>> src;
src.emplace_back(absl::make_unique<int>(1));
src.emplace_back(absl::make_unique<int>(2));
src.emplace_back(absl::make_unique<int>(3));
return src;
};
std::vector<std::unique_ptr<int>> dest = MakeRValueSrc();
absl::c_move(MakeRValueSrc(), std::back_inserter(dest));
EXPECT_THAT(dest, ElementsAre(Pointee(1), Pointee(2), Pointee(3), Pointee(1),
Pointee(2), Pointee(3)));
}
TEST(MutatingTest, SwapRanges) { TEST(MutatingTest, SwapRanges) {
std::vector<int> odds = {2, 4, 6}; std::vector<int> odds = {2, 4, 6};
std::vector<int> evens = {1, 3, 5}; std::vector<int> evens = {1, 3, 5};
......
...@@ -19,6 +19,7 @@ load( ...@@ -19,6 +19,7 @@ load(
"ABSL_DEFAULT_COPTS", "ABSL_DEFAULT_COPTS",
"ABSL_TEST_COPTS", "ABSL_TEST_COPTS",
"ABSL_EXCEPTIONS_FLAG", "ABSL_EXCEPTIONS_FLAG",
"ABSL_EXCEPTIONS_FLAG_LINKOPTS",
) )
package(default_visibility = ["//visibility:public"]) package(default_visibility = ["//visibility:public"])
...@@ -29,6 +30,7 @@ cc_library( ...@@ -29,6 +30,7 @@ cc_library(
name = "spinlock_wait", name = "spinlock_wait",
srcs = [ srcs = [
"internal/spinlock_akaros.inc", "internal/spinlock_akaros.inc",
"internal/spinlock_linux.inc",
"internal/spinlock_posix.inc", "internal/spinlock_posix.inc",
"internal/spinlock_wait.cc", "internal/spinlock_wait.cc",
"internal/spinlock_win32.inc", "internal/spinlock_win32.inc",
...@@ -73,7 +75,6 @@ cc_library( ...@@ -73,7 +75,6 @@ cc_library(
copts = ABSL_DEFAULT_COPTS, copts = ABSL_DEFAULT_COPTS,
deps = [ deps = [
":config", ":config",
":dynamic_annotations",
], ],
) )
...@@ -106,6 +107,7 @@ cc_library( ...@@ -106,6 +107,7 @@ cc_library(
"internal/identity.h", "internal/identity.h",
"internal/inline_variable.h", "internal/inline_variable.h",
"internal/invoke.h", "internal/invoke.h",
"internal/scheduling_mode.h",
], ],
copts = ABSL_DEFAULT_COPTS, copts = ABSL_DEFAULT_COPTS,
visibility = [ visibility = [
...@@ -179,13 +181,13 @@ cc_library( ...@@ -179,13 +181,13 @@ cc_library(
srcs = ["internal/throw_delegate.cc"], srcs = ["internal/throw_delegate.cc"],
hdrs = ["internal/throw_delegate.h"], hdrs = ["internal/throw_delegate.h"],
copts = ABSL_DEFAULT_COPTS + ABSL_EXCEPTIONS_FLAG, copts = ABSL_DEFAULT_COPTS + ABSL_EXCEPTIONS_FLAG,
linkopts = ABSL_EXCEPTIONS_FLAG_LINKOPTS,
visibility = [ visibility = [
"//absl:__subpackages__", "//absl:__subpackages__",
], ],
deps = [ deps = [
":base", ":base",
":config", ":config",
":core_headers",
], ],
) )
...@@ -193,6 +195,7 @@ cc_test( ...@@ -193,6 +195,7 @@ cc_test(
name = "throw_delegate_test", name = "throw_delegate_test",
srcs = ["throw_delegate_test.cc"], srcs = ["throw_delegate_test.cc"],
copts = ABSL_TEST_COPTS + ABSL_EXCEPTIONS_FLAG, copts = ABSL_TEST_COPTS + ABSL_EXCEPTIONS_FLAG,
linkopts = ABSL_EXCEPTIONS_FLAG_LINKOPTS,
deps = [ deps = [
":throw_delegate", ":throw_delegate",
"@com_google_googletest//:gtest_main", "@com_google_googletest//:gtest_main",
...@@ -225,6 +228,7 @@ cc_library( ...@@ -225,6 +228,7 @@ cc_library(
srcs = ["internal/exception_safety_testing.cc"], srcs = ["internal/exception_safety_testing.cc"],
hdrs = ["internal/exception_safety_testing.h"], hdrs = ["internal/exception_safety_testing.h"],
copts = ABSL_TEST_COPTS + ABSL_EXCEPTIONS_FLAG, copts = ABSL_TEST_COPTS + ABSL_EXCEPTIONS_FLAG,
linkopts = ABSL_EXCEPTIONS_FLAG_LINKOPTS,
deps = [ deps = [
":base", ":base",
":config", ":config",
...@@ -232,7 +236,7 @@ cc_library( ...@@ -232,7 +236,7 @@ cc_library(
"//absl/memory", "//absl/memory",
"//absl/meta:type_traits", "//absl/meta:type_traits",
"//absl/strings", "//absl/strings",
"//absl/types:optional", "//absl/utility",
"@com_google_googletest//:gtest", "@com_google_googletest//:gtest",
], ],
) )
...@@ -241,6 +245,7 @@ cc_test( ...@@ -241,6 +245,7 @@ cc_test(
name = "exception_safety_testing_test", name = "exception_safety_testing_test",
srcs = ["exception_safety_testing_test.cc"], srcs = ["exception_safety_testing_test.cc"],
copts = ABSL_TEST_COPTS + ABSL_EXCEPTIONS_FLAG, copts = ABSL_TEST_COPTS + ABSL_EXCEPTIONS_FLAG,
linkopts = ABSL_EXCEPTIONS_FLAG_LINKOPTS,
deps = [ deps = [
":exception_safety_testing", ":exception_safety_testing",
"//absl/memory", "//absl/memory",
...@@ -299,6 +304,7 @@ cc_test( ...@@ -299,6 +304,7 @@ cc_test(
size = "medium", size = "medium",
srcs = ["spinlock_test_common.cc"], srcs = ["spinlock_test_common.cc"],
copts = ABSL_TEST_COPTS, copts = ABSL_TEST_COPTS,
tags = ["no_test_wasm"],
deps = [ deps = [
":base", ":base",
":core_headers", ":core_headers",
...@@ -309,6 +315,33 @@ cc_test( ...@@ -309,6 +315,33 @@ cc_test(
) )
cc_library( cc_library(
name = "spinlock_benchmark_common",
testonly = 1,
srcs = ["internal/spinlock_benchmark.cc"],
copts = ABSL_DEFAULT_COPTS,
visibility = [
"//absl/base:__pkg__",
],
deps = [
":base",
":base_internal",
"//absl/synchronization",
"@com_github_google_benchmark//:benchmark_main",
],
alwayslink = 1,
)
cc_binary(
name = "spinlock_benchmark",
testonly = 1,
copts = ABSL_DEFAULT_COPTS,
visibility = ["//visibility:private"],
deps = [
":spinlock_benchmark_common",
],
)
cc_library(
name = "endian", name = "endian",
hdrs = [ hdrs = [
"internal/endian.h", "internal/endian.h",
...@@ -337,6 +370,9 @@ cc_test( ...@@ -337,6 +370,9 @@ cc_test(
name = "config_test", name = "config_test",
srcs = ["config_test.cc"], srcs = ["config_test.cc"],
copts = ABSL_TEST_COPTS, copts = ABSL_TEST_COPTS,
tags = [
"no_test_wasm",
],
deps = [ deps = [
":config", ":config",
"//absl/synchronization:thread_pool", "//absl/synchronization:thread_pool",
...@@ -348,6 +384,9 @@ cc_test( ...@@ -348,6 +384,9 @@ cc_test(
name = "call_once_test", name = "call_once_test",
srcs = ["call_once_test.cc"], srcs = ["call_once_test.cc"],
copts = ABSL_TEST_COPTS, copts = ABSL_TEST_COPTS,
tags = [
"no_test_wasm",
],
deps = [ deps = [
":base", ":base",
":core_headers", ":core_headers",
...@@ -362,6 +401,7 @@ cc_test( ...@@ -362,6 +401,7 @@ cc_test(
copts = ABSL_TEST_COPTS, copts = ABSL_TEST_COPTS,
deps = [ deps = [
":base", ":base",
"//absl/strings",
"@com_google_googletest//:gtest_main", "@com_google_googletest//:gtest_main",
], ],
) )
...@@ -387,6 +427,7 @@ cc_test( ...@@ -387,6 +427,7 @@ cc_test(
"//absl:windows": [], "//absl:windows": [],
"//conditions:default": ["-pthread"], "//conditions:default": ["-pthread"],
}), }),
tags = ["no_test_ios_x86_64"],
deps = [":malloc_internal"], deps = [":malloc_internal"],
) )
...@@ -399,6 +440,9 @@ cc_test( ...@@ -399,6 +440,9 @@ cc_test(
"//absl:windows": [], "//absl:windows": [],
"//conditions:default": ["-pthread"], "//conditions:default": ["-pthread"],
}), }),
tags = [
"no_test_wasm",
],
deps = [ deps = [
":base", ":base",
":core_headers", ":core_headers",
...@@ -419,3 +463,23 @@ cc_test( ...@@ -419,3 +463,23 @@ cc_test(
"@com_github_google_benchmark//:benchmark_main", "@com_github_google_benchmark//:benchmark_main",
], ],
) )
cc_library(
name = "bits",
hdrs = ["internal/bits.h"],
visibility = [
"//absl:__subpackages__",
],
deps = [":core_headers"],
)
cc_test(
name = "bits_test",
size = "small",
srcs = ["internal/bits_test.cc"],
copts = ABSL_TEST_COPTS,
deps = [
":bits",
"@com_google_googletest//:gtest_main",
],
)
...@@ -100,7 +100,7 @@ ...@@ -100,7 +100,7 @@
// ABSL_PRINTF_ATTRIBUTE // ABSL_PRINTF_ATTRIBUTE
// ABSL_SCANF_ATTRIBUTE // ABSL_SCANF_ATTRIBUTE
// //
// Tells the compiler to perform `printf` format std::string checking if the // Tells the compiler to perform `printf` format string checking if the
// compiler supports it; see the 'format' attribute in // compiler supports it; see the 'format' attribute in
// <http://gcc.gnu.org/onlinedocs/gcc-4.7.0/gcc/Function-Attributes.html>. // <http://gcc.gnu.org/onlinedocs/gcc-4.7.0/gcc/Function-Attributes.html>.
// //
...@@ -155,7 +155,12 @@ ...@@ -155,7 +155,12 @@
// ABSL_ATTRIBUTE_WEAK // ABSL_ATTRIBUTE_WEAK
// //
// Tags a function as weak for the purposes of compilation and linking. // Tags a function as weak for the purposes of compilation and linking.
#if ABSL_HAVE_ATTRIBUTE(weak) || (defined(__GNUC__) && !defined(__clang__)) // Weak attributes currently do not work properly in LLVM's Windows backend,
// so disable them there. See https://bugs.llvm.org/show_bug.cgi?id=37598
// for futher information.
#if (ABSL_HAVE_ATTRIBUTE(weak) || \
(defined(__GNUC__) && !defined(__clang__))) && \
!(defined(__llvm__) && defined(_WIN32))
#undef ABSL_ATTRIBUTE_WEAK #undef ABSL_ATTRIBUTE_WEAK
#define ABSL_ATTRIBUTE_WEAK __attribute__((weak)) #define ABSL_ATTRIBUTE_WEAK __attribute__((weak))
#define ABSL_HAVE_ATTRIBUTE_WEAK 1 #define ABSL_HAVE_ATTRIBUTE_WEAK 1
...@@ -296,13 +301,13 @@ ...@@ -296,13 +301,13 @@
// ABSL_HAVE_ATTRIBUTE_SECTION // ABSL_HAVE_ATTRIBUTE_SECTION
// //
// Indicates whether labeled sections are supported. Labeled sections are not // Indicates whether labeled sections are supported. Weak symbol support is
// supported on Darwin/iOS. // a prerequisite. Labeled sections are not supported on Darwin/iOS.
#ifdef ABSL_HAVE_ATTRIBUTE_SECTION #ifdef ABSL_HAVE_ATTRIBUTE_SECTION
#error ABSL_HAVE_ATTRIBUTE_SECTION cannot be directly set #error ABSL_HAVE_ATTRIBUTE_SECTION cannot be directly set
#elif (ABSL_HAVE_ATTRIBUTE(section) || \ #elif (ABSL_HAVE_ATTRIBUTE(section) || \
(defined(__GNUC__) && !defined(__clang__))) && \ (defined(__GNUC__) && !defined(__clang__))) && \
!defined(__APPLE__) !defined(__APPLE__) && ABSL_HAVE_ATTRIBUTE_WEAK
#define ABSL_HAVE_ATTRIBUTE_SECTION 1 #define ABSL_HAVE_ATTRIBUTE_SECTION 1
// ABSL_ATTRIBUTE_SECTION // ABSL_ATTRIBUTE_SECTION
...@@ -397,17 +402,28 @@ ...@@ -397,17 +402,28 @@
// ABSL_MUST_USE_RESULT // ABSL_MUST_USE_RESULT
// //
// Tells the compiler to warn about unused return values for functions declared // Tells the compiler to warn about unused results.
// with this macro. The macro must appear as the very first part of a function
// declaration or definition:
// //
// Example: // When annotating a function, it must appear as the first part of the
// declaration or definition. The compiler will warn if the return value from
// such a function is unused:
// //
// ABSL_MUST_USE_RESULT Sprocket* AllocateSprocket(); // ABSL_MUST_USE_RESULT Sprocket* AllocateSprocket();
// AllocateSprocket(); // Triggers a warning.
//
// When annotating a class, it is equivalent to annotating every function which
// returns an instance.
//
// class ABSL_MUST_USE_RESULT Sprocket {};
// Sprocket(); // Triggers a warning.
//
// Sprocket MakeSprocket();
// MakeSprocket(); // Triggers a warning.
//
// Note that references and pointers are not instances:
// //
// This placement has the broadest compatibility with GCC, Clang, and MSVC, with // Sprocket* SprocketPointer();
// both defs and decls, and with GCC-style attributes, MSVC declspec, C++11 // SprocketPointer(); // Does *not* trigger a warning.
// and C++17 attributes.
// //
// ABSL_MUST_USE_RESULT allows using cast-to-void to suppress the unused result // ABSL_MUST_USE_RESULT allows using cast-to-void to suppress the unused result
// warning. For that, warn_unused_result is used only for clang but not for gcc. // warning. For that, warn_unused_result is used only for clang but not for gcc.
...@@ -494,14 +510,27 @@ ...@@ -494,14 +510,27 @@
#define ABSL_XRAY_LOG_ARGS(N) #define ABSL_XRAY_LOG_ARGS(N)
#endif #endif
// ABSL_ATTRIBUTE_REINITIALIZES
//
// Indicates that a member function reinitializes the entire object to a known
// state, independent of the previous state of the object.
//
// The clang-tidy check bugprone-use-after-move allows member functions marked
// with this attribute to be called on objects that have been moved from;
// without the attribute, this would result in a use-after-move warning.
#if ABSL_HAVE_CPP_ATTRIBUTE(clang::reinitializes)
#define ABSL_ATTRIBUTE_REINITIALIZES [[clang::reinitializes]]
#else
#define ABSL_ATTRIBUTE_REINITIALIZES
#endif
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// Variable Attributes // Variable Attributes
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// ABSL_ATTRIBUTE_UNUSED // ABSL_ATTRIBUTE_UNUSED
// //
// Prevents the compiler from complaining about or optimizing away variables // Prevents the compiler from complaining about variables that appear unused.
// that appear unused.
#if ABSL_HAVE_ATTRIBUTE(unused) || (defined(__GNUC__) && !defined(__clang__)) #if ABSL_HAVE_ATTRIBUTE(unused) || (defined(__GNUC__) && !defined(__clang__))
#undef ABSL_ATTRIBUTE_UNUSED #undef ABSL_ATTRIBUTE_UNUSED
#define ABSL_ATTRIBUTE_UNUSED __attribute__((__unused__)) #define ABSL_ATTRIBUTE_UNUSED __attribute__((__unused__))
......
...@@ -22,7 +22,7 @@ ...@@ -22,7 +22,7 @@
#include "absl/base/macros.h" #include "absl/base/macros.h"
namespace absl { namespace absl {
inline namespace lts_2018_06_20 { inline namespace lts_2018_12_18 {
namespace { namespace {
template <int N> template <int N>
...@@ -105,5 +105,5 @@ TEST(BitCast, Double) { ...@@ -105,5 +105,5 @@ TEST(BitCast, Double) {
} }
} // namespace } // namespace
} // inline namespace lts_2018_06_20 } // inline namespace lts_2018_12_18
} // namespace absl } // namespace absl
...@@ -39,7 +39,7 @@ ...@@ -39,7 +39,7 @@
#include "absl/base/port.h" #include "absl/base/port.h"
namespace absl { namespace absl {
inline namespace lts_2018_06_20 { inline namespace lts_2018_12_18 {
class once_flag; class once_flag;
...@@ -151,12 +151,8 @@ void CallOnceImpl(std::atomic<uint32_t>* control, ...@@ -151,12 +151,8 @@ void CallOnceImpl(std::atomic<uint32_t>* control,
old_control != kOnceRunning && old_control != kOnceRunning &&
old_control != kOnceWaiter && old_control != kOnceWaiter &&
old_control != kOnceDone) { old_control != kOnceDone) {
ABSL_RAW_LOG( ABSL_RAW_LOG(FATAL, "Unexpected value for control word: 0x%lx",
FATAL, static_cast<unsigned long>(old_control)); // NOLINT
"Unexpected value for control word: %lx. Either the control word "
"has non-static storage duration (where GoogleOnceDynamic might "
"be appropriate), or there's been a memory corruption.",
static_cast<unsigned long>(old_control)); // NOLINT
} }
} }
#endif // NDEBUG #endif // NDEBUG
...@@ -212,7 +208,7 @@ void call_once(absl::once_flag& flag, Callable&& fn, Args&&... args) { ...@@ -212,7 +208,7 @@ void call_once(absl::once_flag& flag, Callable&& fn, Args&&... args) {
} }
} }
} // inline namespace lts_2018_06_20 } // inline namespace lts_2018_12_18
} // namespace absl } // namespace absl
#endif // ABSL_BASE_CALL_ONCE_H_ #endif // ABSL_BASE_CALL_ONCE_H_
...@@ -22,7 +22,7 @@ ...@@ -22,7 +22,7 @@
#include "absl/synchronization/mutex.h" #include "absl/synchronization/mutex.h"
namespace absl { namespace absl {
inline namespace lts_2018_06_20 { inline namespace lts_2018_12_18 {
namespace { namespace {
absl::once_flag once; absl::once_flag once;
...@@ -100,5 +100,5 @@ TEST(CallOnceTest, ExecutionCount) { ...@@ -100,5 +100,5 @@ TEST(CallOnceTest, ExecutionCount) {
} }
} // namespace } // namespace
} // inline namespace lts_2018_06_20 } // inline namespace lts_2018_12_18
} // namespace absl } // namespace absl
...@@ -25,12 +25,36 @@ ...@@ -25,12 +25,36 @@
#define ABSL_BASE_CASTS_H_ #define ABSL_BASE_CASTS_H_
#include <cstring> #include <cstring>
#include <memory>
#include <type_traits> #include <type_traits>
#include "absl/base/internal/identity.h" #include "absl/base/internal/identity.h"
#include "absl/base/macros.h"
namespace absl { namespace absl {
inline namespace lts_2018_06_20 { inline namespace lts_2018_12_18 {
namespace internal_casts {
// NOTE: Not a fully compliant implementation of `std::is_trivially_copyable`.
// TODO(calabrese) Branch on implementations that directly provide
// `std::is_trivially_copyable`, create a more rigorous workaround, and publicly
// expose in meta/type_traits.
template <class T>
struct is_trivially_copyable
: std::integral_constant<
bool, std::is_destructible<T>::value&& __has_trivial_destructor(T) &&
__has_trivial_copy(T) && __has_trivial_assign(T)> {};
template <class Dest, class Source>
struct is_bitcastable
: std::integral_constant<bool,
sizeof(Dest) == sizeof(Source) &&
is_trivially_copyable<Source>::value &&
is_trivially_copyable<Dest>::value &&
std::is_default_constructible<Dest>::value> {};
} // namespace internal_casts
// implicit_cast() // implicit_cast()
// //
...@@ -82,7 +106,7 @@ inline namespace lts_2018_06_20 { ...@@ -82,7 +106,7 @@ inline namespace lts_2018_06_20 {
// //
// Such implicit cast chaining may be useful within template logic. // Such implicit cast chaining may be useful within template logic.
template <typename To> template <typename To>
inline To implicit_cast(typename absl::internal::identity_t<To> to) { constexpr To implicit_cast(typename absl::internal::identity_t<To> to) {
return to; return to;
} }
...@@ -126,7 +150,32 @@ inline To implicit_cast(typename absl::internal::identity_t<To> to) { ...@@ -126,7 +150,32 @@ inline To implicit_cast(typename absl::internal::identity_t<To> to) {
// and reading its bits back using a different type. A `bit_cast()` avoids this // and reading its bits back using a different type. A `bit_cast()` avoids this
// issue by implementing its casts using `memcpy()`, which avoids introducing // issue by implementing its casts using `memcpy()`, which avoids introducing
// this undefined behavior. // this undefined behavior.
template <typename Dest, typename Source> //
// NOTE: The requirements here are more strict than the bit_cast of standard
// proposal p0476 due to the need for workarounds and lack of intrinsics.
// Specifically, this implementation also requires `Dest` to be
// default-constructible.
template <
typename Dest, typename Source,
typename std::enable_if<internal_casts::is_bitcastable<Dest, Source>::value,
int>::type = 0>
inline Dest bit_cast(const Source& source) {
Dest dest;
memcpy(static_cast<void*>(std::addressof(dest)),
static_cast<const void*>(std::addressof(source)), sizeof(dest));
return dest;
}
// NOTE: This overload is only picked if the requirements of bit_cast are not
// met. It is therefore UB, but is provided temporarily as previous versions of
// this function template were unchecked. Do not use this in new code.
template <
typename Dest, typename Source,
typename std::enable_if<
!internal_casts::is_bitcastable<Dest, Source>::value, int>::type = 0>
ABSL_DEPRECATED(
"absl::bit_cast type requirements were violated. Update the types being "
"used such that they are the same size and are both TriviallyCopyable.")
inline Dest bit_cast(const Source& source) { 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.");
...@@ -136,7 +185,7 @@ inline Dest bit_cast(const Source& source) { ...@@ -136,7 +185,7 @@ inline Dest bit_cast(const Source& source) {
return dest; return dest;
} }
} // inline namespace lts_2018_06_20 } // inline namespace lts_2018_12_18
} // namespace absl } // namespace absl
#endif // ABSL_BASE_CASTS_H_ #endif // ABSL_BASE_CASTS_H_
...@@ -139,12 +139,18 @@ ...@@ -139,12 +139,18 @@
#ifdef ABSL_HAVE_THREAD_LOCAL #ifdef ABSL_HAVE_THREAD_LOCAL
#error ABSL_HAVE_THREAD_LOCAL cannot be directly set #error ABSL_HAVE_THREAD_LOCAL cannot be directly set
#elif defined(__APPLE__) #elif defined(__APPLE__)
// Notes: Xcode's clang did not support `thread_local` until version // Notes:
// 8, and even then not for all iOS < 9.0. Also, Xcode 9.3 started disallowing // * Xcode's clang did not support `thread_local` until version 8, and
// `thread_local` for 32-bit iOS simulator targeting iOS 9.x. // even then not for all iOS < 9.0.
// `__has_feature` is only supported by Clang so it has be inside // * Xcode 9.3 started disallowing `thread_local` for 32-bit iOS simulator
// targeting iOS 9.x.
// * Xcode 10 moves the deployment target check for iOS < 9.0 to link time
// making __has_feature unreliable there.
//
// Otherwise, `__has_feature` is only supported by Clang so it has be inside
// `defined(__APPLE__)` check. // `defined(__APPLE__)` check.
#if __has_feature(cxx_thread_local) #if __has_feature(cxx_thread_local) && \
!(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
#else // !defined(__APPLE__) #else // !defined(__APPLE__)
...@@ -199,7 +205,7 @@ ...@@ -199,7 +205,7 @@
#define ABSL_HAVE_INTRINSIC_INT128 1 #define ABSL_HAVE_INTRINSIC_INT128 1
#elif defined(__CUDACC__) #elif defined(__CUDACC__)
// __CUDACC_VER__ is a full version number before CUDA 9, and is defined to a // __CUDACC_VER__ is a full version number before CUDA 9, and is defined to a
// std::string explaining that it has been removed starting with CUDA 9. We use // string explaining that it has been removed starting with CUDA 9. We use
// nested #ifs because there is no short-circuiting in the preprocessor. // nested #ifs because there is no short-circuiting in the preprocessor.
// NOTE: `__CUDACC__` could be undefined while `__CUDACC_VER__` is defined. // NOTE: `__CUDACC__` could be undefined while `__CUDACC_VER__` is defined.
#if __CUDACC_VER__ >= 70000 #if __CUDACC_VER__ >= 70000
...@@ -268,7 +274,8 @@ ...@@ -268,7 +274,8 @@
#error ABSL_HAVE_MMAP cannot be directly set #error ABSL_HAVE_MMAP cannot be directly set
#elif defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__) || \ #elif defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__) || \
defined(__ros__) || defined(__native_client__) || defined(__asmjs__) || \ defined(__ros__) || defined(__native_client__) || defined(__asmjs__) || \
defined(__wasm__) || defined(__Fuchsia__) defined(__wasm__) || defined(__Fuchsia__) || defined(__sun) || \
defined(__ASYLO__)
#define ABSL_HAVE_MMAP 1 #define ABSL_HAVE_MMAP 1
#endif #endif
...@@ -322,6 +329,8 @@ ...@@ -322,6 +329,8 @@
#define ABSL_HAVE_ALARM 1 #define ABSL_HAVE_ALARM 1
#elif defined(_MSC_VER) #elif defined(_MSC_VER)
// feature tests for Microsoft's library // feature tests for Microsoft's library
#elif defined(__EMSCRIPTEN__)
// emscripten doesn't support signals
#elif defined(__native_client__) #elif defined(__native_client__)
#else #else
// other standard libraries // other standard libraries
...@@ -356,6 +365,18 @@ ...@@ -356,6 +365,18 @@
#error "absl endian detection needs to be set up for your compiler" #error "absl endian detection needs to be set up for your compiler"
#endif #endif
// MacOS 10.13 doesn't let you use <any>, <optional>, or <variant> even though
// the headers exist and are publicly noted to work. See
// https://github.com/abseil/abseil-cpp/issues/207 and
// https://developer.apple.com/documentation/xcode_release_notes/xcode_10_release_notes
#if defined(__APPLE__) && defined(_LIBCPP_VERSION) && \
defined(__MAC_OS_X_VERSION_MIN_REQUIRED__) && \
__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 101400
#define ABSL_INTERNAL_MACOS_HAS_CXX_17_TYPES 1
#else
#define ABSL_INTERNAL_MACOS_HAS_CXX_17_TYPES 0
#endif
// ABSL_HAVE_STD_ANY // ABSL_HAVE_STD_ANY
// //
// Checks whether C++17 std::any is available by checking whether <any> exists. // Checks whether C++17 std::any is available by checking whether <any> exists.
...@@ -364,7 +385,8 @@ ...@@ -364,7 +385,8 @@
#endif #endif
#ifdef __has_include #ifdef __has_include
#if __has_include(<any>) && __cplusplus >= 201703L #if __has_include(<any>) && __cplusplus >= 201703L && \
ABSL_INTERNAL_MACOS_HAS_CXX_17_TYPES
#define ABSL_HAVE_STD_ANY 1 #define ABSL_HAVE_STD_ANY 1
#endif #endif
#endif #endif
...@@ -377,7 +399,8 @@ ...@@ -377,7 +399,8 @@
#endif #endif
#ifdef __has_include #ifdef __has_include
#if __has_include(<optional>) && __cplusplus >= 201703L #if __has_include(<optional>) && __cplusplus >= 201703L && \
ABSL_INTERNAL_MACOS_HAS_CXX_17_TYPES
#define ABSL_HAVE_STD_OPTIONAL 1 #define ABSL_HAVE_STD_OPTIONAL 1
#endif #endif
#endif #endif
...@@ -390,7 +413,8 @@ ...@@ -390,7 +413,8 @@
#endif #endif
#ifdef __has_include #ifdef __has_include
#if __has_include(<variant>) && __cplusplus >= 201703L #if __has_include(<variant>) && __cplusplus >= 201703L && \
ABSL_INTERNAL_MACOS_HAS_CXX_17_TYPES
#define ABSL_HAVE_STD_VARIANT 1 #define ABSL_HAVE_STD_VARIANT 1
#endif #endif
#endif #endif
...@@ -414,14 +438,21 @@ ...@@ -414,14 +438,21 @@
// <string_view>, <variant> is implemented) or higher. Also, `__cplusplus` is // <string_view>, <variant> is implemented) or higher. Also, `__cplusplus` is
// not correctly set by MSVC, so we use `_MSVC_LANG` to check the language // not correctly set by MSVC, so we use `_MSVC_LANG` to check the language
// version. // version.
// TODO(zhangxy): fix tests before enabling aliasing for `std::any`, // TODO(zhangxy): fix tests before enabling aliasing for `std::any`.
// `std::string_view`.
#if defined(_MSC_VER) && _MSC_VER >= 1910 && \ #if defined(_MSC_VER) && _MSC_VER >= 1910 && \
((defined(_MSVC_LANG) && _MSVC_LANG > 201402) || __cplusplus > 201402) ((defined(_MSVC_LANG) && _MSVC_LANG > 201402) || __cplusplus > 201402)
// #define ABSL_HAVE_STD_ANY 1 // #define ABSL_HAVE_STD_ANY 1
#define ABSL_HAVE_STD_OPTIONAL 1 #define ABSL_HAVE_STD_OPTIONAL 1
#define ABSL_HAVE_STD_VARIANT 1 #define ABSL_HAVE_STD_VARIANT 1
// #define ABSL_HAVE_STD_STRING_VIEW 1 #define ABSL_HAVE_STD_STRING_VIEW 1
#endif
// In debug mode, MSVC 2017's std::variant throws a EXCEPTION_ACCESS_VIOLATION
// SEH exception from emplace for variant<SomeStruct> when constructing the
// struct can throw. This defeats some of variant_test and
// variant_exception_safety_test.
#if defined(_MSC_VER) && _MSC_VER >= 1700 && defined(_DEBUG)
#define ABSL_INTERNAL_MSVC_2017_DBG_MODE
#endif #endif
#endif // ABSL_BASE_CONFIG_H_ #endif // ABSL_BASE_CONFIG_H_
...@@ -20,7 +20,7 @@ ...@@ -20,7 +20,7 @@
#include "gtest/gtest.h" #include "gtest/gtest.h"
namespace absl { namespace absl {
inline namespace lts_2018_06_20 { inline namespace lts_2018_12_18 {
namespace inline_variable_testing_internal { namespace inline_variable_testing_internal {
namespace { namespace {
...@@ -60,5 +60,5 @@ TEST(InlineVariableTest, FunPtrType) { ...@@ -60,5 +60,5 @@ TEST(InlineVariableTest, FunPtrType) {
} // namespace } // namespace
} // namespace inline_variable_testing_internal } // namespace inline_variable_testing_internal
} // inline namespace lts_2018_06_20 } // inline namespace lts_2018_12_18
} // namespace absl } // namespace absl
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
#include "absl/base/internal/inline_variable_testing.h" #include "absl/base/internal/inline_variable_testing.h"
namespace absl { namespace absl {
inline namespace lts_2018_06_20 { inline namespace lts_2018_12_18 {
namespace inline_variable_testing_internal { namespace inline_variable_testing_internal {
const Foo& get_foo_a() { return inline_variable_foo; } const Foo& get_foo_a() { return inline_variable_foo; }
...@@ -23,5 +23,5 @@ const Foo& get_foo_a() { return inline_variable_foo; } ...@@ -23,5 +23,5 @@ const Foo& get_foo_a() { return inline_variable_foo; }
const int& get_int_a() { return inline_variable_int; } const int& get_int_a() { return inline_variable_int; }
} // namespace inline_variable_testing_internal } // namespace inline_variable_testing_internal
} // inline namespace lts_2018_06_20 } // inline namespace lts_2018_12_18
} // namespace absl } // namespace absl
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
#include "absl/base/internal/inline_variable_testing.h" #include "absl/base/internal/inline_variable_testing.h"
namespace absl { namespace absl {
inline namespace lts_2018_06_20 { inline namespace lts_2018_12_18 {
namespace inline_variable_testing_internal { namespace inline_variable_testing_internal {
const Foo& get_foo_b() { return inline_variable_foo; } const Foo& get_foo_b() { return inline_variable_foo; }
...@@ -23,5 +23,5 @@ const Foo& get_foo_b() { return inline_variable_foo; } ...@@ -23,5 +23,5 @@ const Foo& get_foo_b() { return inline_variable_foo; }
const int& get_int_b() { return inline_variable_int; } const int& get_int_b() { return inline_variable_int; }
} // namespace inline_variable_testing_internal } // namespace inline_variable_testing_internal
} // inline namespace lts_2018_06_20 } // inline namespace lts_2018_12_18
} // namespace absl } // namespace absl
...@@ -28,7 +28,7 @@ ...@@ -28,7 +28,7 @@
#endif #endif
namespace absl { namespace absl {
inline namespace lts_2018_06_20 { inline namespace lts_2018_12_18 {
namespace base_internal { namespace base_internal {
template <typename T> template <typename T>
...@@ -161,7 +161,7 @@ class AtomicHook<ReturnType (*)(Args...)> { ...@@ -161,7 +161,7 @@ class AtomicHook<ReturnType (*)(Args...)> {
#undef ABSL_HAVE_WORKING_ATOMIC_POINTER #undef ABSL_HAVE_WORKING_ATOMIC_POINTER
} // namespace base_internal } // namespace base_internal
} // inline namespace lts_2018_06_20 } // inline namespace lts_2018_12_18
} // namespace absl } // namespace absl
#endif // ABSL_BASE_INTERNAL_ATOMIC_HOOK_H_ #endif // ABSL_BASE_INTERNAL_ATOMIC_HOOK_H_
// Copyright 2018 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef ABSL_BASE_INTERNAL_BITS_H_
#define ABSL_BASE_INTERNAL_BITS_H_
// This file contains bitwise ops which are implementation details of various
// absl libraries.
#include <cstdint>
// Clang on Windows has __builtin_clzll; otherwise we need to use the
// windows intrinsic functions.
#if defined(_MSC_VER)
#include <intrin.h>
#if defined(_M_X64)
#pragma intrinsic(_BitScanReverse64)
#pragma intrinsic(_BitScanForward64)
#endif
#pragma intrinsic(_BitScanReverse)
#pragma intrinsic(_BitScanForward)
#endif
#include "absl/base/attributes.h"
#if defined(_MSC_VER)
// We can achieve something similar to attribute((always_inline)) with MSVC by
// using the __forceinline keyword, however this is not perfect. MSVC is
// much less aggressive about inlining, and even with the __forceinline keyword.
#define ABSL_BASE_INTERNAL_FORCEINLINE __forceinline
#else
// Use default attribute inline.
#define ABSL_BASE_INTERNAL_FORCEINLINE inline ABSL_ATTRIBUTE_ALWAYS_INLINE
#endif
namespace absl {
inline namespace lts_2018_12_18 {
namespace base_internal {
ABSL_BASE_INTERNAL_FORCEINLINE int CountLeadingZeros64Slow(uint64_t n) {
int zeroes = 60;
if (n >> 32) zeroes -= 32, n >>= 32;
if (n >> 16) zeroes -= 16, n >>= 16;
if (n >> 8) zeroes -= 8, n >>= 8;
if (n >> 4) zeroes -= 4, n >>= 4;
return "\4\3\2\2\1\1\1\1\0\0\0\0\0\0\0"[n] + zeroes;
}
ABSL_BASE_INTERNAL_FORCEINLINE int CountLeadingZeros64(uint64_t n) {
#if defined(_MSC_VER) && defined(_M_X64)
// MSVC does not have __buitin_clzll. Use _BitScanReverse64.
unsigned long result = 0; // NOLINT(runtime/int)
if (_BitScanReverse64(&result, n)) {
return 63 - result;
}
return 64;
#elif defined(_MSC_VER)
// MSVC does not have __buitin_clzll. Compose two calls to _BitScanReverse
unsigned long result = 0; // NOLINT(runtime/int)
if ((n >> 32) && _BitScanReverse(&result, n >> 32)) {
return 31 - result;
}
if (_BitScanReverse(&result, n)) {
return 63 - result;
}
return 64;
#elif defined(__GNUC__)
// Use __builtin_clzll, which uses the following instructions:
// x86: bsr
// ARM64: clz
// PPC: cntlzd
static_assert(sizeof(unsigned long long) == sizeof(n), // NOLINT(runtime/int)
"__builtin_clzll does not take 64-bit arg");
// Handle 0 as a special case because __builtin_clzll(0) is undefined.
if (n == 0) {
return 64;
}
return __builtin_clzll(n);
#else
return CountLeadingZeros64Slow(n);
#endif
}
ABSL_BASE_INTERNAL_FORCEINLINE int CountLeadingZeros32Slow(uint64_t n) {
int zeroes = 28;
if (n >> 16) zeroes -= 16, n >>= 16;
if (n >> 8) zeroes -= 8, n >>= 8;
if (n >> 4) zeroes -= 4, n >>= 4;
return "\4\3\2\2\1\1\1\1\0\0\0\0\0\0\0"[n] + zeroes;
}
ABSL_BASE_INTERNAL_FORCEINLINE int CountLeadingZeros32(uint32_t n) {
#if defined(_MSC_VER)
unsigned long result = 0; // NOLINT(runtime/int)
if (_BitScanReverse(&result, n)) {
return 31 - result;
}
return 32;
#elif defined(__GNUC__)
// Use __builtin_clz, which uses the following instructions:
// x86: bsr
// ARM64: clz
// PPC: cntlzd
static_assert(sizeof(int) == sizeof(n),
"__builtin_clz does not take 32-bit arg");
// Handle 0 as a special case because __builtin_clz(0) is undefined.
if (n == 0) {
return 32;
}
return __builtin_clz(n);
#else
return CountLeadingZeros32Slow(n);
#endif
}
ABSL_BASE_INTERNAL_FORCEINLINE int CountTrailingZerosNonZero64Slow(uint64_t n) {
int c = 63;
n &= ~n + 1;
if (n & 0x00000000FFFFFFFF) c -= 32;
if (n & 0x0000FFFF0000FFFF) c -= 16;
if (n & 0x00FF00FF00FF00FF) c -= 8;
if (n & 0x0F0F0F0F0F0F0F0F) c -= 4;
if (n & 0x3333333333333333) c -= 2;
if (n & 0x5555555555555555) c -= 1;
return c;
}
ABSL_BASE_INTERNAL_FORCEINLINE int CountTrailingZerosNonZero64(uint64_t n) {
#if defined(_MSC_VER) && defined(_M_X64)
unsigned long result = 0; // NOLINT(runtime/int)
_BitScanForward64(&result, n);
return result;
#elif defined(_MSC_VER)
unsigned long result = 0; // NOLINT(runtime/int)
if (static_cast<uint32_t>(n) == 0) {
_BitScanForward(&result, n >> 32);
return result + 32;
}
_BitScanForward(&result, n);
return result;
#elif defined(__GNUC__)
static_assert(sizeof(unsigned long long) == sizeof(n), // NOLINT(runtime/int)
"__builtin_ctzll does not take 64-bit arg");
return __builtin_ctzll(n);
#else
return CountTrailingZerosNonZero64Slow(n);
#endif
}
ABSL_BASE_INTERNAL_FORCEINLINE int CountTrailingZerosNonZero32Slow(uint32_t n) {
int c = 31;
n &= ~n + 1;
if (n & 0x0000FFFF) c -= 16;
if (n & 0x00FF00FF) c -= 8;
if (n & 0x0F0F0F0F) c -= 4;
if (n & 0x33333333) c -= 2;
if (n & 0x55555555) c -= 1;
return c;
}
ABSL_BASE_INTERNAL_FORCEINLINE int CountTrailingZerosNonZero32(uint32_t n) {
#if defined(_MSC_VER)
unsigned long result = 0; // NOLINT(runtime/int)
_BitScanForward(&result, n);
return result;
#elif defined(__GNUC__)
static_assert(sizeof(int) == sizeof(n),
"__builtin_ctz does not take 32-bit arg");
return __builtin_ctz(n);
#else
return CountTrailingZerosNonZero32Slow(n);
#endif
}
#undef ABSL_BASE_INTERNAL_FORCEINLINE
} // namespace base_internal
} // inline namespace lts_2018_12_18
} // namespace absl
#endif // ABSL_BASE_INTERNAL_BITS_H_
// Copyright 2018 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "absl/base/internal/bits.h"
#include "gtest/gtest.h"
namespace {
int CLZ64(uint64_t n) {
int fast = absl::base_internal::CountLeadingZeros64(n);
int slow = absl::base_internal::CountLeadingZeros64Slow(n);
EXPECT_EQ(fast, slow) << n;
return fast;
}
TEST(BitsTest, CountLeadingZeros64) {
EXPECT_EQ(64, CLZ64(uint64_t{}));
EXPECT_EQ(0, CLZ64(~uint64_t{}));
for (int index = 0; index < 64; index++) {
uint64_t x = static_cast<uint64_t>(1) << index;
const auto cnt = 63 - index;
ASSERT_EQ(cnt, CLZ64(x)) << index;
ASSERT_EQ(cnt, CLZ64(x + x - 1)) << index;
}
}
int CLZ32(uint32_t n) {
int fast = absl::base_internal::CountLeadingZeros32(n);
int slow = absl::base_internal::CountLeadingZeros32Slow(n);
EXPECT_EQ(fast, slow) << n;
return fast;
}
TEST(BitsTest, CountLeadingZeros32) {
EXPECT_EQ(32, CLZ32(uint32_t{}));
EXPECT_EQ(0, CLZ32(~uint32_t{}));
for (int index = 0; index < 32; index++) {
uint32_t x = static_cast<uint32_t>(1) << index;
const auto cnt = 31 - index;
ASSERT_EQ(cnt, CLZ32(x)) << index;
ASSERT_EQ(cnt, CLZ32(x + x - 1)) << index;
ASSERT_EQ(CLZ64(x), CLZ32(x) + 32);
}
}
int CTZ64(uint64_t n) {
int fast = absl::base_internal::CountTrailingZerosNonZero64(n);
int slow = absl::base_internal::CountTrailingZerosNonZero64Slow(n);
EXPECT_EQ(fast, slow) << n;
return fast;
}
TEST(BitsTest, CountTrailingZerosNonZero64) {
EXPECT_EQ(0, CTZ64(~uint64_t{}));
for (int index = 0; index < 64; index++) {
uint64_t x = static_cast<uint64_t>(1) << index;
const auto cnt = index;
ASSERT_EQ(cnt, CTZ64(x)) << index;
ASSERT_EQ(cnt, CTZ64(~(x - 1))) << index;
}
}
int CTZ32(uint32_t n) {
int fast = absl::base_internal::CountTrailingZerosNonZero32(n);
int slow = absl::base_internal::CountTrailingZerosNonZero32Slow(n);
EXPECT_EQ(fast, slow) << n;
return fast;
}
TEST(BitsTest, CountTrailingZerosNonZero32) {
EXPECT_EQ(0, CTZ32(~uint32_t{}));
for (int index = 0; index < 32; index++) {
uint32_t x = static_cast<uint32_t>(1) << index;
const auto cnt = index;
ASSERT_EQ(cnt, CTZ32(x)) << index;
ASSERT_EQ(cnt, CTZ32(~(x - 1))) << index;
}
}
} // namespace
...@@ -27,7 +27,7 @@ ...@@ -27,7 +27,7 @@
#include "absl/base/internal/unscaledcycleclock.h" #include "absl/base/internal/unscaledcycleclock.h"
namespace absl { namespace absl {
inline namespace lts_2018_06_20 { inline namespace lts_2018_12_18 {
namespace base_internal { namespace base_internal {
#if ABSL_USE_UNSCALED_CYCLECLOCK #if ABSL_USE_UNSCALED_CYCLECLOCK
...@@ -79,5 +79,5 @@ double CycleClock::Frequency() { ...@@ -79,5 +79,5 @@ double CycleClock::Frequency() {
#endif #endif
} // namespace base_internal } // namespace base_internal
} // inline namespace lts_2018_06_20 } // inline namespace lts_2018_12_18
} // namespace absl } // namespace absl
...@@ -46,7 +46,7 @@ ...@@ -46,7 +46,7 @@
#include <cstdint> #include <cstdint>
namespace absl { namespace absl {
inline namespace lts_2018_06_20 { inline namespace lts_2018_12_18 {
namespace base_internal { namespace base_internal {
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
...@@ -73,7 +73,7 @@ class CycleClock { ...@@ -73,7 +73,7 @@ class CycleClock {
}; };
} // namespace base_internal } // namespace base_internal
} // inline namespace lts_2018_06_20 } // inline namespace lts_2018_12_18
} // namespace absl } // namespace absl
#endif // ABSL_BASE_INTERNAL_CYCLECLOCK_H_ #endif // ABSL_BASE_INTERNAL_CYCLECLOCK_H_
...@@ -62,7 +62,7 @@ extern "C" void* __mmap2(void*, size_t, int, int, int, size_t); ...@@ -62,7 +62,7 @@ extern "C" void* __mmap2(void*, size_t, int, int, int, size_t);
#endif // __BIONIC__ #endif // __BIONIC__
namespace absl { namespace absl {
inline namespace lts_2018_06_20 { inline namespace lts_2018_12_18 {
namespace base_internal { namespace base_internal {
// Platform specific logic extracted from // Platform specific logic extracted from
...@@ -76,7 +76,11 @@ inline void* DirectMmap(void* start, size_t length, int prot, int flags, int fd, ...@@ -76,7 +76,11 @@ inline void* DirectMmap(void* start, size_t length, int prot, int flags, int fd,
// On these architectures, implement mmap with mmap2. // On these architectures, implement mmap with mmap2.
static int pagesize = 0; static int pagesize = 0;
if (pagesize == 0) { if (pagesize == 0) {
#if defined(__wasm__) || defined(__asmjs__)
pagesize = getpagesize(); pagesize = getpagesize();
#else
pagesize = sysconf(_SC_PAGESIZE);
#endif
} }
if (offset < 0 || offset % pagesize != 0) { if (offset < 0 || offset % pagesize != 0) {
errno = EINVAL; errno = EINVAL;
...@@ -93,11 +97,13 @@ inline void* DirectMmap(void* start, size_t length, int prot, int flags, int fd, ...@@ -93,11 +97,13 @@ inline void* DirectMmap(void* start, size_t length, int prot, int flags, int fd,
#endif #endif
#elif defined(__s390x__) #elif defined(__s390x__)
// On s390x, mmap() arguments are passed in memory. // On s390x, mmap() arguments are passed in memory.
uint32_t buf[6] = { unsigned long buf[6] = {reinterpret_cast<unsigned long>(start), // NOLINT
reinterpret_cast<uint32_t>(start), static_cast<uint32_t>(length), static_cast<unsigned long>(length), // NOLINT
static_cast<uint32_t>(prot), static_cast<uint32_t>(flags), static_cast<unsigned long>(prot), // NOLINT
static_cast<uint32_t>(fd), static_cast<uint32_t>(offset)}; static_cast<unsigned long>(flags), // NOLINT
return reintrepret_cast<void*>(syscall(SYS_mmap, buf)); static_cast<unsigned long>(fd), // NOLINT
static_cast<unsigned long>(offset)}; // NOLINT
return reinterpret_cast<void*>(syscall(SYS_mmap, buf));
#elif defined(__x86_64__) #elif defined(__x86_64__)
// The x32 ABI has 32 bit longs, but the syscall interface is 64 bit. // The x32 ABI has 32 bit longs, but the syscall interface is 64 bit.
// We need to explicitly cast to an unsigned 64 bit type to avoid implicit // We need to explicitly cast to an unsigned 64 bit type to avoid implicit
...@@ -123,7 +129,7 @@ inline int DirectMunmap(void* start, size_t length) { ...@@ -123,7 +129,7 @@ inline int DirectMunmap(void* start, size_t length) {
} }
} // namespace base_internal } // namespace base_internal
} // inline namespace lts_2018_06_20 } // inline namespace lts_2018_12_18
} // namespace absl } // namespace absl
#else // !__linux__ #else // !__linux__
...@@ -132,7 +138,7 @@ inline int DirectMunmap(void* start, size_t length) { ...@@ -132,7 +138,7 @@ inline int DirectMunmap(void* start, size_t length) {
// actual mmap()/munmap() methods. // actual mmap()/munmap() methods.
namespace absl { namespace absl {
inline namespace lts_2018_06_20 { inline namespace lts_2018_12_18 {
namespace base_internal { namespace base_internal {
inline void* DirectMmap(void* start, size_t length, int prot, int flags, int fd, inline void* DirectMmap(void* start, size_t length, int prot, int flags, int fd,
...@@ -145,7 +151,7 @@ inline int DirectMunmap(void* start, size_t length) { ...@@ -145,7 +151,7 @@ inline int DirectMunmap(void* start, size_t length) {
} }
} // namespace base_internal } // namespace base_internal
} // inline namespace lts_2018_06_20 } // inline namespace lts_2018_12_18
} // namespace absl } // namespace absl
#endif // __linux__ #endif // __linux__
......
...@@ -34,7 +34,7 @@ ...@@ -34,7 +34,7 @@
#include "absl/base/port.h" #include "absl/base/port.h"
namespace absl { namespace absl {
inline namespace lts_2018_06_20 { inline namespace lts_2018_12_18 {
// Use compiler byte-swapping intrinsics if they are available. 32-bit // Use compiler byte-swapping intrinsics if they are available. 32-bit
// and 64-bit versions are available in Clang and GCC as of GCC 4.3.0. // and 64-bit versions are available in Clang and GCC as of GCC 4.3.0.
...@@ -83,14 +83,14 @@ inline uint64_t gbswap_64(uint64_t host_int) { ...@@ -83,14 +83,14 @@ inline uint64_t gbswap_64(uint64_t host_int) {
#elif defined(__GLIBC__) #elif defined(__GLIBC__)
return bswap_64(host_int); return bswap_64(host_int);
#else #else
return (((x & uint64_t{(0xFF}) << 56) | return (((host_int & uint64_t{0xFF}) << 56) |
((x & uint64_t{(0xFF00}) << 40) | ((host_int & uint64_t{0xFF00}) << 40) |
((x & uint64_t{(0xFF0000}) << 24) | ((host_int & uint64_t{0xFF0000}) << 24) |
((x & uint64_t{(0xFF000000}) << 8) | ((host_int & uint64_t{0xFF000000}) << 8) |
((x & uint64_t{(0xFF00000000}) >> 8) | ((host_int & uint64_t{0xFF00000000}) >> 8) |
((x & uint64_t{(0xFF0000000000}) >> 24) | ((host_int & uint64_t{0xFF0000000000}) >> 24) |
((x & uint64_t{(0xFF000000000000}) >> 40) | ((host_int & uint64_t{0xFF000000000000}) >> 40) |
((x & uint64_t{(0xFF00000000000000}) >> 56)); ((host_int & uint64_t{0xFF00000000000000}) >> 56));
#endif // bswap_64 #endif // bswap_64
} }
...@@ -98,8 +98,10 @@ inline uint32_t gbswap_32(uint32_t host_int) { ...@@ -98,8 +98,10 @@ inline uint32_t gbswap_32(uint32_t host_int) {
#if defined(__GLIBC__) #if defined(__GLIBC__)
return bswap_32(host_int); return bswap_32(host_int);
#else #else
return (((x & 0xFF) << 24) | ((x & 0xFF00) << 8) | ((x & 0xFF0000) >> 8) | return (((host_int & uint32_t{0xFF}) << 24) |
((x & 0xFF000000) >> 24)); ((host_int & uint32_t{0xFF00}) << 8) |
((host_int & uint32_t{0xFF0000}) >> 8) |
((host_int & uint32_t{0xFF000000}) >> 24));
#endif #endif
} }
...@@ -107,7 +109,8 @@ inline uint16_t gbswap_16(uint16_t host_int) { ...@@ -107,7 +109,8 @@ inline uint16_t gbswap_16(uint16_t host_int) {
#if defined(__GLIBC__) #if defined(__GLIBC__)
return bswap_16(host_int); return bswap_16(host_int);
#else #else
return uint16_t{((x & 0xFF) << 8) | ((x & 0xFF00) >> 8)}; return (((host_int & uint16_t{0xFF}) << 8) |
((host_int & uint16_t{0xFF00}) >> 8));
#endif #endif
} }
...@@ -265,7 +268,7 @@ inline void Store64(void *p, uint64_t v) { ...@@ -265,7 +268,7 @@ inline void Store64(void *p, uint64_t v) {
} // namespace big_endian } // namespace big_endian
} // inline namespace lts_2018_06_20 } // inline namespace lts_2018_12_18
} // namespace absl } // namespace absl
#endif // ABSL_BASE_INTERNAL_ENDIAN_H_ #endif // ABSL_BASE_INTERNAL_ENDIAN_H_
...@@ -24,7 +24,7 @@ ...@@ -24,7 +24,7 @@
#include "absl/base/config.h" #include "absl/base/config.h"
namespace absl { namespace absl {
inline namespace lts_2018_06_20 { inline namespace lts_2018_12_18 {
namespace { namespace {
const uint64_t kInitialNumber{0x0123456789abcdef}; const uint64_t kInitialNumber{0x0123456789abcdef};
...@@ -34,32 +34,16 @@ const uint16_t k16Value{0x0123}; ...@@ -34,32 +34,16 @@ const uint16_t k16Value{0x0123};
const int kNumValuesToTest = 1000000; const int kNumValuesToTest = 1000000;
const int kRandomSeed = 12345; const int kRandomSeed = 12345;
#ifdef ABSL_IS_BIG_ENDIAN #if defined(ABSL_IS_BIG_ENDIAN)
const uint64_t kInitialInNetworkOrder{kInitialNumber}; const uint64_t kInitialInNetworkOrder{kInitialNumber};
const uint64_t k64ValueLE{0xefcdab8967452301}; const uint64_t k64ValueLE{0xefcdab8967452301};
const uint32_t k32ValueLE{0x67452301}; const uint32_t k32ValueLE{0x67452301};
const uint16_t k16ValueLE{0x2301}; const uint16_t k16ValueLE{0x2301};
const uint8_t k8ValueLE{k8Value};
const uint64_t k64IValueLE{0xefcdab89674523a1};
const uint32_t k32IValueLE{0x67452391};
const uint16_t k16IValueLE{0x85ff};
const uint8_t k8IValueLE{0xff};
const uint64_t kDoubleValueLE{0x6e861bf0f9210940};
const uint32_t kFloatValueLE{0xd00f4940};
const uint8_t kBoolValueLE{0x1};
const uint64_t k64ValueBE{kInitialNumber}; const uint64_t k64ValueBE{kInitialNumber};
const uint32_t k32ValueBE{k32Value}; const uint32_t k32ValueBE{k32Value};
const uint16_t k16ValueBE{k16Value}; const uint16_t k16ValueBE{k16Value};
const uint8_t k8ValueBE{k8Value}; #elif defined(ABSL_IS_LITTLE_ENDIAN)
const uint64_t k64IValueBE{0xa123456789abcdef};
const uint32_t k32IValueBE{0x91234567};
const uint16_t k16IValueBE{0xff85};
const uint8_t k8IValueBE{0xff};
const uint64_t kDoubleValueBE{0x400921f9f01b866e};
const uint32_t kFloatValueBE{0x40490fd0};
const uint8_t kBoolValueBE{0x1};
#elif defined ABSL_IS_LITTLE_ENDIAN
const uint64_t kInitialInNetworkOrder{0xefcdab8967452301}; const uint64_t kInitialInNetworkOrder{0xefcdab8967452301};
const uint64_t k64ValueLE{kInitialNumber}; const uint64_t k64ValueLE{kInitialNumber};
const uint32_t k32ValueLE{k32Value}; const uint32_t k32ValueLE{k32Value};
...@@ -277,5 +261,5 @@ TEST(EndianessTest, big_endian) { ...@@ -277,5 +261,5 @@ TEST(EndianessTest, big_endian) {
} }
} // namespace } // namespace
} // inline namespace lts_2018_06_20 } // inline namespace lts_2018_12_18
} // namespace absl } // namespace absl
...@@ -23,6 +23,10 @@ exceptions_internal::NoThrowTag nothrow_ctor; ...@@ -23,6 +23,10 @@ exceptions_internal::NoThrowTag nothrow_ctor;
exceptions_internal::StrongGuaranteeTagType strong_guarantee; exceptions_internal::StrongGuaranteeTagType strong_guarantee;
exceptions_internal::ExceptionSafetyTestBuilder<> MakeExceptionSafetyTester() {
return {};
}
namespace exceptions_internal { namespace exceptions_internal {
int countdown = -1; int countdown = -1;
......
...@@ -35,7 +35,7 @@ ...@@ -35,7 +35,7 @@
EXPECT_DEATH(expr, ".*") EXPECT_DEATH(expr, ".*")
#else #else
#define ABSL_BASE_INTERNAL_EXPECT_FAIL(expr, exception_t, text) \ #define ABSL_BASE_INTERNAL_EXPECT_FAIL(expr, exception_t, text) \
EXPECT_DEATH(expr, text) EXPECT_DEATH_IF_SUPPORTED(expr, text)
#endif #endif
......
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
#include <cstdint> #include <cstdint>
namespace absl { namespace absl {
inline namespace lts_2018_06_20 { inline namespace lts_2018_12_18 {
namespace base_internal { namespace base_internal {
// Arbitrary value with high bits set. Xor'ing with it is unlikely // Arbitrary value with high bits set. Xor'ing with it is unlikely
...@@ -43,7 +43,7 @@ inline T* UnhidePtr(uintptr_t hidden) { ...@@ -43,7 +43,7 @@ inline T* UnhidePtr(uintptr_t hidden) {
} }
} // namespace base_internal } // namespace base_internal
} // inline namespace lts_2018_06_20 } // inline namespace lts_2018_12_18
} // namespace absl } // namespace absl
#endif // ABSL_BASE_INTERNAL_HIDE_PTR_H_ #endif // ABSL_BASE_INTERNAL_HIDE_PTR_H_
...@@ -17,7 +17,7 @@ ...@@ -17,7 +17,7 @@
#define ABSL_BASE_INTERNAL_IDENTITY_H_ #define ABSL_BASE_INTERNAL_IDENTITY_H_
namespace absl { namespace absl {
inline namespace lts_2018_06_20 { inline namespace lts_2018_12_18 {
namespace internal { namespace internal {
template <typename T> template <typename T>
...@@ -29,7 +29,7 @@ template <typename T> ...@@ -29,7 +29,7 @@ template <typename T>
using identity_t = typename identity<T>::type; using identity_t = typename identity<T>::type;
} // namespace internal } // namespace internal
} // inline namespace lts_2018_06_20 } // inline namespace lts_2018_12_18
} // namespace absl } // namespace absl
#endif // ABSL_BASE_INTERNAL_IDENTITY_H_ #endif // ABSL_BASE_INTERNAL_IDENTITY_H_
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
#include "absl/base/internal/inline_variable.h" #include "absl/base/internal/inline_variable.h"
namespace absl { namespace absl {
inline namespace lts_2018_06_20 { inline namespace lts_2018_12_18 {
namespace inline_variable_testing_internal { namespace inline_variable_testing_internal {
struct Foo { struct Foo {
...@@ -40,7 +40,7 @@ const int& get_int_a(); ...@@ -40,7 +40,7 @@ const int& get_int_a();
const int& get_int_b(); const int& get_int_b();
} // namespace inline_variable_testing_internal } // namespace inline_variable_testing_internal
} // inline namespace lts_2018_06_20 } // inline namespace lts_2018_12_18
} // namespace absl } // namespace absl
#endif // ABSL_BASE_INLINE_VARIABLE_TESTING_H_ #endif // ABSL_BASE_INLINE_VARIABLE_TESTING_H_
...@@ -43,7 +43,7 @@ ...@@ -43,7 +43,7 @@
// top of this file for the API documentation. // top of this file for the API documentation.
namespace absl { namespace absl {
inline namespace lts_2018_06_20 { inline namespace lts_2018_12_18 {
namespace base_internal { namespace base_internal {
// The five classes below each implement one of the clauses from the definition // The five classes below each implement one of the clauses from the definition
...@@ -184,7 +184,7 @@ InvokeT<F, Args...> Invoke(F&& f, Args&&... args) { ...@@ -184,7 +184,7 @@ InvokeT<F, Args...> Invoke(F&& f, Args&&... args) {
std::forward<Args>(args)...); std::forward<Args>(args)...);
} }
} // namespace base_internal } // namespace base_internal
} // inline namespace lts_2018_06_20 } // inline namespace lts_2018_12_18
} // namespace absl } // namespace absl
#endif // ABSL_BASE_INTERNAL_INVOKE_H_ #endif // ABSL_BASE_INTERNAL_INVOKE_H_
...@@ -63,7 +63,7 @@ ...@@ -63,7 +63,7 @@
#endif // __APPLE__ #endif // __APPLE__
namespace absl { namespace absl {
inline namespace lts_2018_06_20 { inline namespace lts_2018_12_18 {
namespace base_internal { namespace base_internal {
// A first-fit allocator with amortized logarithmic free() time. // A first-fit allocator with amortized logarithmic free() time.
...@@ -209,7 +209,7 @@ struct LowLevelAlloc::Arena { ...@@ -209,7 +209,7 @@ struct LowLevelAlloc::Arena {
int32_t allocation_count GUARDED_BY(mu); int32_t allocation_count GUARDED_BY(mu);
// flags passed to NewArena // flags passed to NewArena
const uint32_t flags; const uint32_t flags;
// Result of getpagesize() // Result of sysconf(_SC_PAGESIZE)
const size_t pagesize; const size_t pagesize;
// Lowest power of two >= max(16, sizeof(AllocList)) // Lowest power of two >= max(16, sizeof(AllocList))
const size_t roundup; const size_t roundup;
...@@ -325,8 +325,10 @@ size_t GetPageSize() { ...@@ -325,8 +325,10 @@ size_t GetPageSize() {
SYSTEM_INFO system_info; SYSTEM_INFO system_info;
GetSystemInfo(&system_info); GetSystemInfo(&system_info);
return std::max(system_info.dwPageSize, system_info.dwAllocationGranularity); return std::max(system_info.dwPageSize, system_info.dwAllocationGranularity);
#else #elif defined(__wasm__) || defined(__asmjs__)
return getpagesize(); return getpagesize();
#else
return sysconf(_SC_PAGESIZE);
#endif #endif
} }
...@@ -402,16 +404,20 @@ bool LowLevelAlloc::DeleteArena(Arena *arena) { ...@@ -402,16 +404,20 @@ bool LowLevelAlloc::DeleteArena(Arena *arena) {
ABSL_RAW_CHECK(munmap_result != 0, ABSL_RAW_CHECK(munmap_result != 0,
"LowLevelAlloc::DeleteArena: VitualFree failed"); "LowLevelAlloc::DeleteArena: VitualFree failed");
#else #else
#ifndef ABSL_LOW_LEVEL_ALLOC_ASYNC_SIGNAL_SAFE_MISSING
if ((arena->flags & LowLevelAlloc::kAsyncSignalSafe) == 0) { if ((arena->flags & LowLevelAlloc::kAsyncSignalSafe) == 0) {
munmap_result = munmap(region, size); munmap_result = munmap(region, size);
} else { } else {
munmap_result = base_internal::DirectMunmap(region, size); munmap_result = base_internal::DirectMunmap(region, size);
} }
#else
munmap_result = munmap(region, size);
#endif // ABSL_LOW_LEVEL_ALLOC_ASYNC_SIGNAL_SAFE_MISSING
if (munmap_result != 0) { if (munmap_result != 0) {
ABSL_RAW_LOG(FATAL, "LowLevelAlloc::DeleteArena: munmap failed: %d", ABSL_RAW_LOG(FATAL, "LowLevelAlloc::DeleteArena: munmap failed: %d",
errno); errno);
} }
#endif #endif // _WIN32
} }
section.Leave(); section.Leave();
arena->~Arena(); arena->~Arena();
...@@ -546,6 +552,7 @@ static void *DoAllocWithArena(size_t request, LowLevelAlloc::Arena *arena) { ...@@ -546,6 +552,7 @@ static void *DoAllocWithArena(size_t request, LowLevelAlloc::Arena *arena) {
MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
ABSL_RAW_CHECK(new_pages != nullptr, "VirtualAlloc failed"); ABSL_RAW_CHECK(new_pages != nullptr, "VirtualAlloc failed");
#else #else
#ifndef ABSL_LOW_LEVEL_ALLOC_ASYNC_SIGNAL_SAFE_MISSING
if ((arena->flags & LowLevelAlloc::kAsyncSignalSafe) != 0) { if ((arena->flags & LowLevelAlloc::kAsyncSignalSafe) != 0) {
new_pages = base_internal::DirectMmap(nullptr, new_pages_size, new_pages = base_internal::DirectMmap(nullptr, new_pages_size,
PROT_WRITE|PROT_READ, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0); PROT_WRITE|PROT_READ, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
...@@ -553,10 +560,15 @@ static void *DoAllocWithArena(size_t request, LowLevelAlloc::Arena *arena) { ...@@ -553,10 +560,15 @@ static void *DoAllocWithArena(size_t request, LowLevelAlloc::Arena *arena) {
new_pages = mmap(nullptr, new_pages_size, PROT_WRITE | PROT_READ, new_pages = mmap(nullptr, new_pages_size, PROT_WRITE | PROT_READ,
MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
} }
#else
new_pages = mmap(nullptr, new_pages_size, PROT_WRITE | PROT_READ,
MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
#endif // ABSL_LOW_LEVEL_ALLOC_ASYNC_SIGNAL_SAFE_MISSING
if (new_pages == MAP_FAILED) { if (new_pages == MAP_FAILED) {
ABSL_RAW_LOG(FATAL, "mmap error: %d", errno); ABSL_RAW_LOG(FATAL, "mmap error: %d", errno);
} }
#endif
#endif // _WIN32
arena->mu.Lock(); arena->mu.Lock();
s = reinterpret_cast<AllocList *>(new_pages); s = reinterpret_cast<AllocList *>(new_pages);
s->header.size = new_pages_size; s->header.size = new_pages_size;
...@@ -600,7 +612,7 @@ void *LowLevelAlloc::AllocWithArena(size_t request, Arena *arena) { ...@@ -600,7 +612,7 @@ void *LowLevelAlloc::AllocWithArena(size_t request, Arena *arena) {
} }
} // namespace base_internal } // namespace base_internal
} // inline namespace lts_2018_06_20 } // inline namespace lts_2018_12_18
} // namespace absl } // namespace absl
#endif // ABSL_LOW_LEVEL_ALLOC_MISSING #endif // ABSL_LOW_LEVEL_ALLOC_MISSING
...@@ -39,10 +39,13 @@ ...@@ -39,10 +39,13 @@
#define ABSL_LOW_LEVEL_ALLOC_MISSING 1 #define ABSL_LOW_LEVEL_ALLOC_MISSING 1
#endif #endif
// Using LowLevelAlloc with kAsyncSignalSafe isn't supported on Windows. // Using LowLevelAlloc with kAsyncSignalSafe isn't supported on Windows or
// asm.js / WebAssembly.
// See https://kripken.github.io/emscripten-site/docs/porting/pthreads.html
// for more information.
#ifdef ABSL_LOW_LEVEL_ALLOC_ASYNC_SIGNAL_SAFE_MISSING #ifdef ABSL_LOW_LEVEL_ALLOC_ASYNC_SIGNAL_SAFE_MISSING
#error ABSL_LOW_LEVEL_ALLOC_ASYNC_SIGNAL_SAFE_MISSING cannot be directly set #error ABSL_LOW_LEVEL_ALLOC_ASYNC_SIGNAL_SAFE_MISSING cannot be directly set
#elif defined(_WIN32) #elif defined(_WIN32) || defined(__asmjs__) || defined(__wasm__)
#define ABSL_LOW_LEVEL_ALLOC_ASYNC_SIGNAL_SAFE_MISSING 1 #define ABSL_LOW_LEVEL_ALLOC_ASYNC_SIGNAL_SAFE_MISSING 1
#endif #endif
...@@ -51,7 +54,7 @@ ...@@ -51,7 +54,7 @@
#include "absl/base/port.h" #include "absl/base/port.h"
namespace absl { namespace absl {
inline namespace lts_2018_06_20 { inline namespace lts_2018_12_18 {
namespace base_internal { namespace base_internal {
class LowLevelAlloc { class LowLevelAlloc {
...@@ -116,6 +119,6 @@ class LowLevelAlloc { ...@@ -116,6 +119,6 @@ class LowLevelAlloc {
}; };
} // namespace base_internal } // namespace base_internal
} // inline namespace lts_2018_06_20 } // inline namespace lts_2018_12_18
} // namespace absl } // namespace absl
#endif // ABSL_BASE_INTERNAL_LOW_LEVEL_ALLOC_H_ #endif // ABSL_BASE_INTERNAL_LOW_LEVEL_ALLOC_H_
...@@ -22,7 +22,7 @@ ...@@ -22,7 +22,7 @@
#include <utility> #include <utility>
namespace absl { namespace absl {
inline namespace lts_2018_06_20 { inline namespace lts_2018_12_18 {
namespace base_internal { namespace base_internal {
namespace { namespace {
...@@ -149,7 +149,7 @@ static struct BeforeMain { ...@@ -149,7 +149,7 @@ static struct BeforeMain {
} // namespace } // namespace
} // namespace base_internal } // namespace base_internal
} // inline namespace lts_2018_06_20 } // inline namespace lts_2018_12_18
} // namespace absl } // namespace absl
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
......
...@@ -28,7 +28,7 @@ extern "C" bool __google_disable_rescheduling(void); ...@@ -28,7 +28,7 @@ extern "C" bool __google_disable_rescheduling(void);
extern "C" void __google_enable_rescheduling(bool disable_result); extern "C" void __google_enable_rescheduling(bool disable_result);
namespace absl { namespace absl {
inline namespace lts_2018_06_20 { inline namespace lts_2018_12_18 {
namespace base_internal { namespace base_internal {
class SchedulingHelper; // To allow use of SchedulingGuard. class SchedulingHelper; // To allow use of SchedulingGuard.
...@@ -101,6 +101,6 @@ inline void SchedulingGuard::EnableRescheduling(bool /* disable_result */) { ...@@ -101,6 +101,6 @@ inline void SchedulingGuard::EnableRescheduling(bool /* disable_result */) {
} // namespace base_internal } // namespace base_internal
} // inline namespace lts_2018_06_20 } // inline namespace lts_2018_12_18
} // namespace absl } // namespace absl
#endif // ABSL_BASE_INTERNAL_LOW_LEVEL_SCHEDULING_H_ #endif // ABSL_BASE_INTERNAL_LOW_LEVEL_SCHEDULING_H_
...@@ -139,7 +139,7 @@ void RawLogVA(absl::LogSeverity severity, const char* file, int line, ...@@ -139,7 +139,7 @@ void RawLogVA(absl::LogSeverity severity, const char* file, int line,
#endif #endif
#ifdef ABSL_MIN_LOG_LEVEL #ifdef ABSL_MIN_LOG_LEVEL
if (static_cast<int>(severity) < ABSL_MIN_LOG_LEVEL && if (severity < static_cast<absl::LogSeverity>(ABSL_MIN_LOG_LEVEL) &&
severity < absl::LogSeverity::kFatal) { severity < absl::LogSeverity::kFatal) {
enabled = false; enabled = false;
} }
...@@ -181,7 +181,7 @@ void RawLogVA(absl::LogSeverity severity, const char* file, int line, ...@@ -181,7 +181,7 @@ void RawLogVA(absl::LogSeverity severity, const char* file, int line,
} // namespace } // namespace
namespace absl { namespace absl {
inline namespace lts_2018_06_20 { inline namespace lts_2018_12_18 {
namespace raw_logging_internal { namespace raw_logging_internal {
void SafeWriteToStderr(const char *s, size_t len) { void SafeWriteToStderr(const char *s, size_t len) {
#if defined(ABSL_HAVE_SYSCALL_WRITE) #if defined(ABSL_HAVE_SYSCALL_WRITE)
...@@ -207,6 +207,15 @@ void RawLog(absl::LogSeverity severity, const char* file, int line, ...@@ -207,6 +207,15 @@ void RawLog(absl::LogSeverity severity, const char* file, int line,
va_end(ap); va_end(ap);
} }
// Non-formatting version of RawLog().
//
// TODO(gfalcon): When string_view no longer depends on base, change this
// interface to take its message as a string_view instead.
static void DefaultInternalLog(absl::LogSeverity severity, const char* file,
int line, const std::string& message) {
RawLog(severity, file, line, "%s", message.c_str());
}
bool RawLoggingFullySupported() { bool RawLoggingFullySupported() {
#ifdef ABSL_LOW_LEVEL_WRITE_SUPPORTED #ifdef ABSL_LOW_LEVEL_WRITE_SUPPORTED
return true; return true;
...@@ -215,6 +224,13 @@ bool RawLoggingFullySupported() { ...@@ -215,6 +224,13 @@ bool RawLoggingFullySupported() {
#endif // !ABSL_LOW_LEVEL_WRITE_SUPPORTED #endif // !ABSL_LOW_LEVEL_WRITE_SUPPORTED
} }
ABSL_CONST_INIT absl::base_internal::AtomicHook<InternalLogFunction>
internal_log_function(DefaultInternalLog);
void RegisterInternalLogFunction(InternalLogFunction func) {
internal_log_function.Store(func);
}
} // namespace raw_logging_internal } // namespace raw_logging_internal
} // inline namespace lts_2018_06_20 } // inline namespace lts_2018_12_18
} // namespace absl } // namespace absl
...@@ -19,7 +19,10 @@ ...@@ -19,7 +19,10 @@
#ifndef ABSL_BASE_INTERNAL_RAW_LOGGING_H_ #ifndef ABSL_BASE_INTERNAL_RAW_LOGGING_H_
#define ABSL_BASE_INTERNAL_RAW_LOGGING_H_ #define ABSL_BASE_INTERNAL_RAW_LOGGING_H_
#include <string>
#include "absl/base/attributes.h" #include "absl/base/attributes.h"
#include "absl/base/internal/atomic_hook.h"
#include "absl/base/log_severity.h" #include "absl/base/log_severity.h"
#include "absl/base/macros.h" #include "absl/base/macros.h"
#include "absl/base/port.h" #include "absl/base/port.h"
...@@ -57,6 +60,34 @@ ...@@ -57,6 +60,34 @@
} \ } \
} while (0) } while (0)
// ABSL_INTERNAL_LOG and ABSL_INTERNAL_CHECK work like the RAW variants above,
// except that if the richer log library is linked into the binary, we dispatch
// to that instead. This is potentially useful for internal logging and
// assertions, where we are using RAW_LOG neither for its async-signal-safety
// nor for its non-allocating nature, but rather because raw logging has very
// few other dependencies.
//
// The API is a subset of the above: each macro only takes two arguments. Use
// StrCat if you need to build a richer message.
#define ABSL_INTERNAL_LOG(severity, message) \
do { \
constexpr const char* absl_raw_logging_internal_basename = \
::absl::raw_logging_internal::Basename(__FILE__, \
sizeof(__FILE__) - 1); \
::absl::raw_logging_internal::internal_log_function( \
ABSL_RAW_LOGGING_INTERNAL_##severity, \
absl_raw_logging_internal_basename, __LINE__, message); \
} while (0)
#define ABSL_INTERNAL_CHECK(condition, message) \
do { \
if (ABSL_PREDICT_FALSE(!(condition))) { \
std::string death_message = "Check " #condition " failed: "; \
death_message += std::string(message); \
ABSL_INTERNAL_LOG(FATAL, death_message); \
} \
} while (0)
#define ABSL_RAW_LOGGING_INTERNAL_INFO ::absl::LogSeverity::kInfo #define ABSL_RAW_LOGGING_INTERNAL_INFO ::absl::LogSeverity::kInfo
#define ABSL_RAW_LOGGING_INTERNAL_WARNING ::absl::LogSeverity::kWarning #define ABSL_RAW_LOGGING_INTERNAL_WARNING ::absl::LogSeverity::kWarning
#define ABSL_RAW_LOGGING_INTERNAL_ERROR ::absl::LogSeverity::kError #define ABSL_RAW_LOGGING_INTERNAL_ERROR ::absl::LogSeverity::kError
...@@ -65,7 +96,7 @@ ...@@ -65,7 +96,7 @@
::absl::NormalizeLogSeverity(severity) ::absl::NormalizeLogSeverity(severity)
namespace absl { namespace absl {
inline namespace lts_2018_06_20 { inline namespace lts_2018_12_18 {
namespace raw_logging_internal { namespace raw_logging_internal {
// Helper function to implement ABSL_RAW_LOG // Helper function to implement ABSL_RAW_LOG
...@@ -84,7 +115,7 @@ void SafeWriteToStderr(const char *s, size_t len); ...@@ -84,7 +115,7 @@ void SafeWriteToStderr(const char *s, size_t len);
// compile-time function to get the "base" filename, that is, the part of // compile-time function to get the "base" filename, that is, the part of
// a filename after the last "/" or "\" path separator. The search starts at // a filename after the last "/" or "\" path separator. The search starts at
// the end of the std::string; the second parameter is the length of the std::string. // the end of the string; the second parameter is the length of the string.
constexpr const char* Basename(const char* fname, int offset) { constexpr const char* Basename(const char* fname, int offset) {
return offset == 0 || fname[offset - 1] == '/' || fname[offset - 1] == '\\' return offset == 0 || fname[offset - 1] == '/' || fname[offset - 1] == '\\'
? fname + offset ? fname + offset
...@@ -132,8 +163,20 @@ using LogPrefixHook = bool (*)(absl::LogSeverity severity, const char* file, ...@@ -132,8 +163,20 @@ using LogPrefixHook = bool (*)(absl::LogSeverity severity, const char* file,
using AbortHook = void (*)(const char* file, int line, const char* buf_start, using AbortHook = void (*)(const char* file, int line, const char* buf_start,
const char* prefix_end, const char* buf_end); const char* prefix_end, const char* buf_end);
// Internal logging function for ABSL_INTERNAL_LOG to dispatch to.
//
// TODO(gfalcon): When string_view no longer depends on base, change this
// interface to take its message as a string_view instead.
using InternalLogFunction = void (*)(absl::LogSeverity severity,
const char* file, int line,
const std::string& message);
extern base_internal::AtomicHook<InternalLogFunction> internal_log_function;
void RegisterInternalLogFunction(InternalLogFunction func);
} // namespace raw_logging_internal } // namespace raw_logging_internal
} // inline namespace lts_2018_06_20 } // inline namespace lts_2018_12_18
} // namespace absl } // namespace absl
#endif // ABSL_BASE_INTERNAL_RAW_LOGGING_H_ #endif // ABSL_BASE_INTERNAL_RAW_LOGGING_H_
...@@ -19,7 +19,7 @@ ...@@ -19,7 +19,7 @@
#define ABSL_BASE_INTERNAL_SCHEDULING_MODE_H_ #define ABSL_BASE_INTERNAL_SCHEDULING_MODE_H_
namespace absl { namespace absl {
inline namespace lts_2018_06_20 { inline namespace lts_2018_12_18 {
namespace base_internal { namespace base_internal {
// Used to describe how a thread may be scheduled. Typically associated with // Used to describe how a thread may be scheduled. Typically associated with
...@@ -50,7 +50,7 @@ enum SchedulingMode { ...@@ -50,7 +50,7 @@ enum SchedulingMode {
}; };
} // namespace base_internal } // namespace base_internal
} // inline namespace lts_2018_06_20 } // inline namespace lts_2018_12_18
} // namespace absl } // namespace absl
#endif // ABSL_BASE_INTERNAL_SCHEDULING_MODE_H_ #endif // ABSL_BASE_INTERNAL_SCHEDULING_MODE_H_
...@@ -54,7 +54,7 @@ ...@@ -54,7 +54,7 @@
// holder to acquire the lock. There may be outstanding waiter(s). // holder to acquire the lock. There may be outstanding waiter(s).
namespace absl { namespace absl {
inline namespace lts_2018_06_20 { inline namespace lts_2018_12_18 {
namespace base_internal { namespace base_internal {
ABSL_CONST_INIT static base_internal::AtomicHook<void (*)(const void *lock, ABSL_CONST_INIT static base_internal::AtomicHook<void (*)(const void *lock,
...@@ -96,13 +96,9 @@ void SpinLock::InitLinkerInitializedAndCooperative() { ...@@ -96,13 +96,9 @@ void SpinLock::InitLinkerInitializedAndCooperative() {
} }
// 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). A timestamp indicating // (adaptive_spin_count loop iterations). The last value read from the lock
// when the thread initially started waiting for the lock is passed in via // is returned from the method.
// the initial_wait_timestamp value. The total wait time in cycles for the uint32_t SpinLock::SpinLoop() {
// lock is returned in the wait_cycles parameter. The last value read
// from the lock is returned from the method.
uint32_t SpinLock::SpinLoop(int64_t initial_wait_timestamp,
uint32_t *wait_cycles) {
// We are already in the slow path of SpinLock, initialize the // We are already in the slow path of SpinLock, initialize the
// adaptive_spin_count here. // adaptive_spin_count here.
ABSL_CONST_INIT static absl::once_flag init_adaptive_spin_count; ABSL_CONST_INIT static absl::once_flag init_adaptive_spin_count;
...@@ -116,22 +112,21 @@ uint32_t SpinLock::SpinLoop(int64_t initial_wait_timestamp, ...@@ -116,22 +112,21 @@ uint32_t SpinLock::SpinLoop(int64_t initial_wait_timestamp,
do { do {
lock_value = lockword_.load(std::memory_order_relaxed); lock_value = lockword_.load(std::memory_order_relaxed);
} while ((lock_value & kSpinLockHeld) != 0 && --c > 0); } while ((lock_value & kSpinLockHeld) != 0 && --c > 0);
uint32_t spin_loop_wait_cycles = return lock_value;
EncodeWaitCycles(initial_wait_timestamp, CycleClock::Now());
*wait_cycles = spin_loop_wait_cycles;
return TryLockInternal(lock_value, spin_loop_wait_cycles);
} }
void SpinLock::SlowLock() { void SpinLock::SlowLock() {
uint32_t lock_value = SpinLoop();
lock_value = TryLockInternal(lock_value, 0);
if ((lock_value & kSpinLockHeld) == 0) {
return;
}
// 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
// obtains the lock. // obtains the lock.
int64_t wait_start_time = CycleClock::Now(); int64_t wait_start_time = CycleClock::Now();
uint32_t wait_cycles; uint32_t wait_cycles = 0;
uint32_t lock_value = SpinLoop(wait_start_time, &wait_cycles);
int lock_wait_call_count = 0; int lock_wait_call_count = 0;
while ((lock_value & kSpinLockHeld) != 0) { while ((lock_value & kSpinLockHeld) != 0) {
// If the lock is currently held, but not marked as having a sleeper, mark // If the lock is currently held, but not marked as having a sleeper, mark
...@@ -142,7 +137,7 @@ void SpinLock::SlowLock() { ...@@ -142,7 +137,7 @@ void SpinLock::SlowLock() {
// owner to think it experienced contention. // owner to think it experienced contention.
if (lockword_.compare_exchange_strong( if (lockword_.compare_exchange_strong(
lock_value, lock_value | kSpinLockSleeper, lock_value, lock_value | kSpinLockSleeper,
std::memory_order_acquire, std::memory_order_relaxed)) { std::memory_order_relaxed, std::memory_order_relaxed)) {
// Successfully transitioned to kSpinLockSleeper. Pass // Successfully transitioned to kSpinLockSleeper. Pass
// kSpinLockSleeper to the SpinLockWait routine to properly indicate // kSpinLockSleeper to the SpinLockWait routine to properly indicate
// the last lock_value observed. // the last lock_value observed.
...@@ -171,7 +166,9 @@ void SpinLock::SlowLock() { ...@@ -171,7 +166,9 @@ void SpinLock::SlowLock() {
ABSL_TSAN_MUTEX_POST_DIVERT(this, 0); ABSL_TSAN_MUTEX_POST_DIVERT(this, 0);
// Spin again after returning from the wait routine to give this thread // Spin again after returning from the wait routine to give this thread
// some chance of obtaining the lock. // some chance of obtaining the lock.
lock_value = SpinLoop(wait_start_time, &wait_cycles); lock_value = SpinLoop();
wait_cycles = EncodeWaitCycles(wait_start_time, CycleClock::Now());
lock_value = TryLockInternal(lock_value, wait_cycles);
} }
} }
...@@ -207,14 +204,20 @@ uint32_t SpinLock::EncodeWaitCycles(int64_t wait_start_time, ...@@ -207,14 +204,20 @@ uint32_t SpinLock::EncodeWaitCycles(int64_t wait_start_time,
(wait_end_time - wait_start_time) >> PROFILE_TIMESTAMP_SHIFT; (wait_end_time - wait_start_time) >> PROFILE_TIMESTAMP_SHIFT;
// 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. bit_cast is required as Atomic32 is signed. // the lock word's upper bits.
const 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) << LOCKWORD_RESERVED_SHIFT);
// bump up value if necessary to avoid returning kSpinLockSleeper. if (clamped == 0) {
const uint32_t after_spinlock_sleeper = return kSpinLockSleeper; // Just wake waiters, but don't record contention.
kSpinLockSleeper + (1 << LOCKWORD_RESERVED_SHIFT); }
return clamped == kSpinLockSleeper ? after_spinlock_sleeper : clamped; // Bump up value if necessary to avoid returning kSpinLockSleeper.
const uint32_t kMinWaitTime =
kSpinLockSleeper + (1 << LOCKWORD_RESERVED_SHIFT);
if (clamped == kSpinLockSleeper) {
return kMinWaitTime;
}
return clamped;
} }
uint64_t SpinLock::DecodeWaitCycles(uint32_t lock_value) { uint64_t SpinLock::DecodeWaitCycles(uint32_t lock_value) {
...@@ -226,5 +229,5 @@ uint64_t SpinLock::DecodeWaitCycles(uint32_t lock_value) { ...@@ -226,5 +229,5 @@ uint64_t SpinLock::DecodeWaitCycles(uint32_t lock_value) {
} }
} // namespace base_internal } // namespace base_internal
} // inline namespace lts_2018_06_20 } // inline namespace lts_2018_12_18
} // namespace absl } // namespace absl
...@@ -45,7 +45,7 @@ ...@@ -45,7 +45,7 @@
#include "absl/base/thread_annotations.h" #include "absl/base/thread_annotations.h"
namespace absl { namespace absl {
inline namespace lts_2018_06_20 { inline namespace lts_2018_12_18 {
namespace base_internal { namespace base_internal {
class LOCKABLE SpinLock { class LOCKABLE SpinLock {
...@@ -102,8 +102,8 @@ class LOCKABLE SpinLock { ...@@ -102,8 +102,8 @@ class LOCKABLE SpinLock {
inline void Unlock() UNLOCK_FUNCTION() { inline void Unlock() UNLOCK_FUNCTION() {
ABSL_TSAN_MUTEX_PRE_UNLOCK(this, 0); ABSL_TSAN_MUTEX_PRE_UNLOCK(this, 0);
uint32_t lock_value = lockword_.load(std::memory_order_relaxed); uint32_t lock_value = lockword_.load(std::memory_order_relaxed);
lockword_.store(lock_value & kSpinLockCooperative, lock_value = lockword_.exchange(lock_value & kSpinLockCooperative,
std::memory_order_release); std::memory_order_release);
if ((lock_value & kSpinLockDisabledScheduling) != 0) { if ((lock_value & kSpinLockDisabledScheduling) != 0) {
base_internal::SchedulingGuard::EnableRescheduling(true); base_internal::SchedulingGuard::EnableRescheduling(true);
...@@ -162,7 +162,7 @@ class LOCKABLE SpinLock { ...@@ -162,7 +162,7 @@ class LOCKABLE SpinLock {
void InitLinkerInitializedAndCooperative(); 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(int64_t initial_wait_timestamp, uint32_t* wait_cycles); uint32_t SpinLoop();
inline bool TryLockImpl() { inline bool TryLockImpl() {
uint32_t lock_value = lockword_.load(std::memory_order_relaxed); uint32_t lock_value = lockword_.load(std::memory_order_relaxed);
...@@ -235,7 +235,7 @@ inline uint32_t SpinLock::TryLockInternal(uint32_t lock_value, ...@@ -235,7 +235,7 @@ inline uint32_t SpinLock::TryLockInternal(uint32_t lock_value,
} }
} // namespace base_internal } // namespace base_internal
} // inline namespace lts_2018_06_20 } // inline namespace lts_2018_12_18
} // namespace absl } // namespace absl
#endif // ABSL_BASE_INTERNAL_SPINLOCK_H_ #endif // ABSL_BASE_INTERNAL_SPINLOCK_H_
// Copyright 2018 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// See also //absl/synchronization:mutex_benchmark for a comparison of SpinLock
// and Mutex performance under varying levels of contention.
#include "absl/base/internal/raw_logging.h"
#include "absl/base/internal/scheduling_mode.h"
#include "absl/base/internal/spinlock.h"
#include "absl/synchronization/internal/create_thread_identity.h"
#include "benchmark/benchmark.h"
namespace {
template <absl::base_internal::SchedulingMode scheduling_mode>
static void BM_SpinLock(benchmark::State& state) {
// Ensure a ThreadIdentity is installed.
ABSL_INTERNAL_CHECK(
absl::synchronization_internal::GetOrCreateCurrentThreadIdentity() !=
nullptr,
"GetOrCreateCurrentThreadIdentity() failed");
static auto* spinlock = new absl::base_internal::SpinLock(scheduling_mode);
for (auto _ : state) {
absl::base_internal::SpinLockHolder holder(spinlock);
}
}
BENCHMARK_TEMPLATE(BM_SpinLock,
absl::base_internal::SCHEDULE_KERNEL_ONLY)
->UseRealTime()
->Threads(1)
->ThreadPerCpu();
BENCHMARK_TEMPLATE(BM_SpinLock,
absl::base_internal::SCHEDULE_COOPERATIVE_AND_KERNEL)
->UseRealTime()
->Threads(1)
->ThreadPerCpu();
} // namespace
// Copyright 2018 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// This file is a Linux-specific part of spinlock_wait.cc
#include <linux/futex.h>
#include <sys/syscall.h>
#include <unistd.h>
#include <atomic>
#include <cerrno>
#include <climits>
#include <cstdint>
#include <ctime>
#include "absl/base/attributes.h"
// The SpinLock lockword is `std::atomic<uint32_t>`. Here we assert that
// `std::atomic<uint32_t>` is bitwise equivalent of the `int` expected
// by SYS_futex. We also assume that reads/writes done to the lockword
// by SYS_futex have rational semantics with regard to the
// std::atomic<> API. C++ provides no guarantees of these assumptions,
// but they are believed to hold in practice.
static_assert(sizeof(std::atomic<uint32_t>) == sizeof(int),
"SpinLock lockword has the wrong size for a futex");
// Some Android headers are missing these definitions even though they
// support these futex operations.
#ifdef __BIONIC__
#ifndef SYS_futex
#define SYS_futex __NR_futex
#endif
#ifndef FUTEX_PRIVATE_FLAG
#define FUTEX_PRIVATE_FLAG 128
#endif
#endif
extern "C" {
ABSL_ATTRIBUTE_WEAK void AbslInternalSpinLockDelay(
std::atomic<uint32_t> *w, uint32_t value, int loop,
absl::base_internal::SchedulingMode) {
if (loop != 0) {
int save_errno = errno;
struct timespec tm;
tm.tv_sec = 0;
// Increase the delay; we expect (but do not rely on) explicit wakeups.
// We don't rely on explicit wakeups because we intentionally allow for
// a race on the kSpinLockSleeper bit.
tm.tv_nsec = 16 * absl::base_internal::SpinLockSuggestedDelayNS(loop);
syscall(SYS_futex, w, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, value, &tm);
errno = save_errno;
}
}
ABSL_ATTRIBUTE_WEAK void AbslInternalSpinLockWake(std::atomic<uint32_t> *w,
bool all) {
syscall(SYS_futex, w, FUTEX_WAKE | FUTEX_PRIVATE_FLAG, all ? INT_MAX : 1, 0);
}
} // extern "C"
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
// limitations under the License. // limitations under the License.
// The OS-specific header included below must provide two calls: // The OS-specific header included below must provide two calls:
// base::subtle::SpinLockDelay() and base::subtle::SpinLockWake(). // AbslInternalSpinLockDelay() and AbslInternalSpinLockWake().
// See spinlock_wait.h for the specs. // See spinlock_wait.h for the specs.
#include <atomic> #include <atomic>
...@@ -23,6 +23,8 @@ ...@@ -23,6 +23,8 @@
#if defined(_WIN32) #if defined(_WIN32)
#include "absl/base/internal/spinlock_win32.inc" #include "absl/base/internal/spinlock_win32.inc"
#elif defined(__linux__)
#include "absl/base/internal/spinlock_linux.inc"
#elif defined(__akaros__) #elif defined(__akaros__)
#include "absl/base/internal/spinlock_akaros.inc" #include "absl/base/internal/spinlock_akaros.inc"
#else #else
...@@ -30,21 +32,22 @@ ...@@ -30,21 +32,22 @@
#endif #endif
namespace absl { namespace absl {
inline namespace lts_2018_06_20 { inline namespace lts_2018_12_18 {
namespace base_internal { namespace base_internal {
// See spinlock_wait.h for spec. // See spinlock_wait.h for spec.
uint32_t SpinLockWait(std::atomic<uint32_t> *w, int n, uint32_t SpinLockWait(std::atomic<uint32_t> *w, int n,
const SpinLockWaitTransition trans[], const SpinLockWaitTransition trans[],
base_internal::SchedulingMode scheduling_mode) { base_internal::SchedulingMode scheduling_mode) {
for (int loop = 0; ; loop++) { int loop = 0;
for (;;) {
uint32_t v = w->load(std::memory_order_acquire); uint32_t v = w->load(std::memory_order_acquire);
int i; int i;
for (i = 0; i != n && v != trans[i].from; i++) { for (i = 0; i != n && v != trans[i].from; i++) {
} }
if (i == n) { if (i == n) {
SpinLockDelay(w, v, loop, scheduling_mode); // no matching transition SpinLockDelay(w, v, ++loop, scheduling_mode); // no matching transition
} else if (trans[i].to == v || // null transition } else if (trans[i].to == v || // null transition
w->compare_exchange_strong(v, trans[i].to, w->compare_exchange_strong(v, trans[i].to,
std::memory_order_acquire, std::memory_order_acquire,
std::memory_order_relaxed)) { std::memory_order_relaxed)) {
...@@ -77,5 +80,5 @@ int SpinLockSuggestedDelayNS(int loop) { ...@@ -77,5 +80,5 @@ int SpinLockSuggestedDelayNS(int loop) {
} }
} // namespace base_internal } // namespace base_internal
} // inline namespace lts_2018_06_20 } // inline namespace lts_2018_12_18
} // namespace absl } // namespace absl
...@@ -24,7 +24,7 @@ ...@@ -24,7 +24,7 @@
#include "absl/base/internal/scheduling_mode.h" #include "absl/base/internal/scheduling_mode.h"
namespace absl { namespace absl {
inline namespace lts_2018_06_20 { inline namespace lts_2018_12_18 {
namespace base_internal { namespace base_internal {
// SpinLockWait() waits until it can perform one of several transitions from // SpinLockWait() waits until it can perform one of several transitions from
...@@ -63,7 +63,7 @@ void SpinLockDelay(std::atomic<uint32_t> *w, uint32_t value, int loop, ...@@ -63,7 +63,7 @@ void SpinLockDelay(std::atomic<uint32_t> *w, uint32_t value, int loop,
int SpinLockSuggestedDelayNS(int loop); int SpinLockSuggestedDelayNS(int loop);
} // namespace base_internal } // namespace base_internal
} // inline namespace lts_2018_06_20 } // inline namespace lts_2018_12_18
} // namespace absl } // namespace absl
// In some build configurations we pass --detect-odr-violations to the // In some build configurations we pass --detect-odr-violations to the
......
...@@ -56,7 +56,7 @@ ...@@ -56,7 +56,7 @@
#include "absl/base/internal/unscaledcycleclock.h" #include "absl/base/internal/unscaledcycleclock.h"
namespace absl { namespace absl {
inline namespace lts_2018_06_20 { inline namespace lts_2018_12_18 {
namespace base_internal { namespace base_internal {
static once_flag init_system_info_once; static once_flag init_system_info_once;
...@@ -402,5 +402,5 @@ pid_t GetTID() { ...@@ -402,5 +402,5 @@ pid_t GetTID() {
#endif #endif
} // namespace base_internal } // namespace base_internal
} // inline namespace lts_2018_06_20 } // inline namespace lts_2018_12_18
} // namespace absl } // namespace absl
...@@ -33,7 +33,7 @@ ...@@ -33,7 +33,7 @@
#include "absl/base/port.h" #include "absl/base/port.h"
namespace absl { namespace absl {
inline namespace lts_2018_06_20 { inline namespace lts_2018_12_18 {
namespace base_internal { namespace base_internal {
// Nominal core processor cycles per second of each processor. This is _not_ // Nominal core processor cycles per second of each processor. This is _not_
...@@ -59,7 +59,7 @@ using pid_t = DWORD; ...@@ -59,7 +59,7 @@ using pid_t = DWORD;
pid_t GetTID(); pid_t GetTID();
} // namespace base_internal } // namespace base_internal
} // inline namespace lts_2018_06_20 } // inline namespace lts_2018_12_18
} // namespace absl } // namespace absl
#endif // ABSL_BASE_INTERNAL_SYSINFO_H_ #endif // ABSL_BASE_INTERNAL_SYSINFO_H_
...@@ -28,7 +28,7 @@ ...@@ -28,7 +28,7 @@
#include "absl/synchronization/mutex.h" #include "absl/synchronization/mutex.h"
namespace absl { namespace absl {
inline namespace lts_2018_06_20 { inline namespace lts_2018_12_18 {
namespace base_internal { namespace base_internal {
namespace { namespace {
...@@ -96,5 +96,5 @@ TEST(SysinfoTest, LinuxGetTID) { ...@@ -96,5 +96,5 @@ TEST(SysinfoTest, LinuxGetTID) {
} // namespace } // namespace
} // namespace base_internal } // namespace base_internal
} // inline namespace lts_2018_06_20 } // inline namespace lts_2018_12_18
} // namespace absl } // namespace absl
...@@ -28,7 +28,7 @@ ...@@ -28,7 +28,7 @@
#include "absl/base/internal/spinlock.h" #include "absl/base/internal/spinlock.h"
namespace absl { namespace absl {
inline namespace lts_2018_06_20 { inline namespace lts_2018_12_18 {
namespace base_internal { namespace base_internal {
#if ABSL_THREAD_IDENTITY_MODE != ABSL_THREAD_IDENTITY_MODE_USE_CPP11 #if ABSL_THREAD_IDENTITY_MODE != ABSL_THREAD_IDENTITY_MODE_USE_CPP11
...@@ -69,6 +69,14 @@ void SetCurrentThreadIdentity( ...@@ -69,6 +69,14 @@ void SetCurrentThreadIdentity(
// NOTE: Not async-safe. But can be open-coded. // NOTE: Not async-safe. But can be open-coded.
absl::call_once(init_thread_identity_key_once, AllocateThreadIdentityKey, absl::call_once(init_thread_identity_key_once, AllocateThreadIdentityKey,
reclaimer); reclaimer);
#ifdef __EMSCRIPTEN__
// Emscripten PThread implementation does not support signals.
// See https://kripken.github.io/emscripten-site/docs/porting/pthreads.html
// for more information.
pthread_setspecific(thread_identity_pthread_key,
reinterpret_cast<void*>(identity));
#else
// We must mask signals around the call to setspecific as with current glibc, // We must mask signals around the call to setspecific as with current glibc,
// a concurrent getspecific (needed for GetCurrentThreadIdentityIfPresent()) // a concurrent getspecific (needed for GetCurrentThreadIdentityIfPresent())
// may zero our value. // may zero our value.
...@@ -82,6 +90,8 @@ void SetCurrentThreadIdentity( ...@@ -82,6 +90,8 @@ void SetCurrentThreadIdentity(
pthread_setspecific(thread_identity_pthread_key, pthread_setspecific(thread_identity_pthread_key,
reinterpret_cast<void*>(identity)); reinterpret_cast<void*>(identity));
pthread_sigmask(SIG_SETMASK, &curr_signals, nullptr); pthread_sigmask(SIG_SETMASK, &curr_signals, nullptr);
#endif // !__EMSCRIPTEN__
#elif ABSL_THREAD_IDENTITY_MODE == ABSL_THREAD_IDENTITY_MODE_USE_TLS #elif ABSL_THREAD_IDENTITY_MODE == ABSL_THREAD_IDENTITY_MODE_USE_TLS
// NOTE: Not async-safe. But can be open-coded. // NOTE: Not async-safe. But can be open-coded.
absl::call_once(init_thread_identity_key_once, AllocateThreadIdentityKey, absl::call_once(init_thread_identity_key_once, AllocateThreadIdentityKey,
...@@ -121,5 +131,5 @@ ThreadIdentity* CurrentThreadIdentityIfPresent() { ...@@ -121,5 +131,5 @@ ThreadIdentity* CurrentThreadIdentityIfPresent() {
#endif #endif
} // namespace base_internal } // namespace base_internal
} // inline namespace lts_2018_06_20 } // inline namespace lts_2018_12_18
} // namespace absl } // namespace absl
...@@ -33,7 +33,7 @@ ...@@ -33,7 +33,7 @@
#include "absl/base/internal/per_thread_tls.h" #include "absl/base/internal/per_thread_tls.h"
namespace absl { namespace absl {
inline namespace lts_2018_06_20 { inline namespace lts_2018_12_18 {
struct SynchLocksHeld; struct SynchLocksHeld;
struct SynchWaitParams; struct SynchWaitParams;
...@@ -237,6 +237,6 @@ inline ThreadIdentity* CurrentThreadIdentityIfPresent() { ...@@ -237,6 +237,6 @@ inline ThreadIdentity* CurrentThreadIdentityIfPresent() {
#endif #endif
} // namespace base_internal } // namespace base_internal
} // inline namespace lts_2018_06_20 } // inline namespace lts_2018_12_18
} // namespace absl } // namespace absl
#endif // ABSL_BASE_INTERNAL_THREAD_IDENTITY_H_ #endif // ABSL_BASE_INTERNAL_THREAD_IDENTITY_H_
...@@ -25,7 +25,7 @@ ...@@ -25,7 +25,7 @@
#include "absl/synchronization/mutex.h" #include "absl/synchronization/mutex.h"
namespace absl { namespace absl {
inline namespace lts_2018_06_20 { inline namespace lts_2018_12_18 {
namespace base_internal { namespace base_internal {
namespace { namespace {
...@@ -124,5 +124,5 @@ TEST(ThreadIdentityTest, ReusedThreadIdentityMutexTest) { ...@@ -124,5 +124,5 @@ TEST(ThreadIdentityTest, ReusedThreadIdentityMutexTest) {
} // namespace } // namespace
} // namespace base_internal } // namespace base_internal
} // inline namespace lts_2018_06_20 } // inline namespace lts_2018_12_18
} // namespace absl } // namespace absl
...@@ -22,7 +22,7 @@ ...@@ -22,7 +22,7 @@
#include "absl/base/internal/raw_logging.h" #include "absl/base/internal/raw_logging.h"
namespace absl { namespace absl {
inline namespace lts_2018_06_20 { inline namespace lts_2018_12_18 {
namespace base_internal { namespace base_internal {
namespace { namespace {
...@@ -31,8 +31,8 @@ template <typename T> ...@@ -31,8 +31,8 @@ template <typename T>
#ifdef ABSL_HAVE_EXCEPTIONS #ifdef ABSL_HAVE_EXCEPTIONS
throw error; throw error;
#else #else
ABSL_RAW_LOG(ERROR, "%s", error.what()); ABSL_RAW_LOG(FATAL, "%s", error.what());
abort(); std::abort();
#endif #endif
} }
} // namespace } // namespace
...@@ -104,5 +104,5 @@ void ThrowStdBadFunctionCall() { Throw(std::bad_function_call()); } ...@@ -104,5 +104,5 @@ void ThrowStdBadFunctionCall() { Throw(std::bad_function_call()); }
void ThrowStdBadAlloc() { Throw(std::bad_alloc()); } void ThrowStdBadAlloc() { Throw(std::bad_alloc()); }
} // namespace base_internal } // namespace base_internal
} // inline namespace lts_2018_06_20 } // inline namespace lts_2018_12_18
} // namespace absl } // namespace absl
...@@ -20,7 +20,7 @@ ...@@ -20,7 +20,7 @@
#include <string> #include <string>
namespace absl { namespace absl {
inline namespace lts_2018_06_20 { inline namespace lts_2018_12_18 {
namespace base_internal { namespace base_internal {
// Helper functions that allow throwing exceptions consistently from anywhere. // Helper functions that allow throwing exceptions consistently from anywhere.
...@@ -67,7 +67,7 @@ namespace base_internal { ...@@ -67,7 +67,7 @@ namespace base_internal {
// [[noreturn]] void ThrowStdBadArrayNewLength(); // [[noreturn]] void ThrowStdBadArrayNewLength();
} // namespace base_internal } // namespace base_internal
} // inline namespace lts_2018_06_20 } // inline namespace lts_2018_12_18
} // namespace absl } // namespace absl
#endif // ABSL_BASE_INTERNAL_THROW_DELEGATE_H_ #endif // ABSL_BASE_INTERNAL_THROW_DELEGATE_H_
...@@ -65,7 +65,8 @@ void __sanitizer_unaligned_store64(void *p, uint64_t v); ...@@ -65,7 +65,8 @@ void __sanitizer_unaligned_store64(void *p, uint64_t v);
} // extern "C" } // extern "C"
namespace absl { namespace absl {
inline namespace lts_2018_06_20 { inline namespace lts_2018_12_18 {
namespace base_internal {
inline uint16_t UnalignedLoad16(const void *p) { inline uint16_t UnalignedLoad16(const void *p) {
return __sanitizer_unaligned_load16(p); return __sanitizer_unaligned_load16(p);
...@@ -91,19 +92,71 @@ inline void UnalignedStore64(void *p, uint64_t v) { ...@@ -91,19 +92,71 @@ inline void UnalignedStore64(void *p, uint64_t v) {
__sanitizer_unaligned_store64(p, v); __sanitizer_unaligned_store64(p, v);
} }
} // inline namespace lts_2018_06_20 } // namespace base_internal
} // inline namespace lts_2018_12_18
} // namespace absl } // namespace absl
#define ABSL_INTERNAL_UNALIGNED_LOAD16(_p) (absl::UnalignedLoad16(_p)) #define ABSL_INTERNAL_UNALIGNED_LOAD16(_p) \
#define ABSL_INTERNAL_UNALIGNED_LOAD32(_p) (absl::UnalignedLoad32(_p)) (absl::base_internal::UnalignedLoad16(_p))
#define ABSL_INTERNAL_UNALIGNED_LOAD64(_p) (absl::UnalignedLoad64(_p)) #define ABSL_INTERNAL_UNALIGNED_LOAD32(_p) \
(absl::base_internal::UnalignedLoad32(_p))
#define ABSL_INTERNAL_UNALIGNED_LOAD64(_p) \
(absl::base_internal::UnalignedLoad64(_p))
#define ABSL_INTERNAL_UNALIGNED_STORE16(_p, _val) \
(absl::base_internal::UnalignedStore16(_p, _val))
#define ABSL_INTERNAL_UNALIGNED_STORE32(_p, _val) \
(absl::base_internal::UnalignedStore32(_p, _val))
#define ABSL_INTERNAL_UNALIGNED_STORE64(_p, _val) \
(absl::base_internal::UnalignedStore64(_p, _val))
#elif defined(UNDEFINED_BEHAVIOR_SANITIZER)
namespace absl {
inline namespace lts_2018_12_18 {
namespace base_internal {
inline uint16_t UnalignedLoad16(const void *p) {
uint16_t t;
memcpy(&t, p, sizeof t);
return t;
}
inline uint32_t UnalignedLoad32(const void *p) {
uint32_t t;
memcpy(&t, p, sizeof t);
return t;
}
inline uint64_t UnalignedLoad64(const void *p) {
uint64_t t;
memcpy(&t, p, sizeof t);
return t;
}
inline void UnalignedStore16(void *p, uint16_t v) { memcpy(p, &v, sizeof v); }
inline void UnalignedStore32(void *p, uint32_t v) { memcpy(p, &v, sizeof v); }
inline void UnalignedStore64(void *p, uint64_t v) { memcpy(p, &v, sizeof v); }
} // namespace base_internal
} // inline namespace lts_2018_12_18
} // namespace absl
#define ABSL_INTERNAL_UNALIGNED_LOAD16(_p) \
(absl::base_internal::UnalignedLoad16(_p))
#define ABSL_INTERNAL_UNALIGNED_LOAD32(_p) \
(absl::base_internal::UnalignedLoad32(_p))
#define ABSL_INTERNAL_UNALIGNED_LOAD64(_p) \
(absl::base_internal::UnalignedLoad64(_p))
#define ABSL_INTERNAL_UNALIGNED_STORE16(_p, _val) \ #define ABSL_INTERNAL_UNALIGNED_STORE16(_p, _val) \
(absl::UnalignedStore16(_p, _val)) (absl::base_internal::UnalignedStore16(_p, _val))
#define ABSL_INTERNAL_UNALIGNED_STORE32(_p, _val) \ #define ABSL_INTERNAL_UNALIGNED_STORE32(_p, _val) \
(absl::UnalignedStore32(_p, _val)) (absl::base_internal::UnalignedStore32(_p, _val))
#define ABSL_INTERNAL_UNALIGNED_STORE64(_p, _val) \ #define ABSL_INTERNAL_UNALIGNED_STORE64(_p, _val) \
(absl::UnalignedStore64(_p, _val)) (absl::base_internal::UnalignedStore64(_p, _val))
#elif defined(__x86_64__) || defined(_M_X64) || defined(__i386) || \ #elif defined(__x86_64__) || defined(_M_X64) || defined(__i386) || \
defined(_M_IX86) || defined(__ppc__) || defined(__PPC__) || \ defined(_M_IX86) || defined(__ppc__) || defined(__PPC__) || \
...@@ -160,8 +213,8 @@ inline void UnalignedStore64(void *p, uint64_t v) { ...@@ -160,8 +213,8 @@ inline void UnalignedStore64(void *p, uint64_t v) {
// so we do that. // so we do that.
namespace absl { namespace absl {
inline namespace lts_2018_06_20 { inline namespace lts_2018_12_18 {
namespace internal { namespace base_internal {
struct Unaligned16Struct { struct Unaligned16Struct {
uint16_t value; uint16_t value;
...@@ -173,24 +226,27 @@ struct Unaligned32Struct { ...@@ -173,24 +226,27 @@ struct Unaligned32Struct {
uint8_t dummy; // To make the size non-power-of-two. uint8_t dummy; // To make the size non-power-of-two.
} ABSL_ATTRIBUTE_PACKED; } ABSL_ATTRIBUTE_PACKED;
} // namespace internal } // namespace base_internal
} // inline namespace lts_2018_06_20 } // inline namespace lts_2018_12_18
} // namespace absl } // namespace absl
#define ABSL_INTERNAL_UNALIGNED_LOAD16(_p) \ #define ABSL_INTERNAL_UNALIGNED_LOAD16(_p) \
((reinterpret_cast<const ::absl::internal::Unaligned16Struct *>(_p))->value) ((reinterpret_cast<const ::absl::base_internal::Unaligned16Struct *>(_p)) \
#define ABSL_INTERNAL_UNALIGNED_LOAD32(_p) \ ->value)
((reinterpret_cast<const ::absl::internal::Unaligned32Struct *>(_p))->value) #define ABSL_INTERNAL_UNALIGNED_LOAD32(_p) \
((reinterpret_cast<const ::absl::base_internal::Unaligned32Struct *>(_p)) \
->value)
#define ABSL_INTERNAL_UNALIGNED_STORE16(_p, _val) \ #define ABSL_INTERNAL_UNALIGNED_STORE16(_p, _val) \
((reinterpret_cast< ::absl::internal::Unaligned16Struct *>(_p))->value = \ ((reinterpret_cast< ::absl::base_internal::Unaligned16Struct *>(_p)) \
(_val)) ->value = (_val))
#define ABSL_INTERNAL_UNALIGNED_STORE32(_p, _val) \ #define ABSL_INTERNAL_UNALIGNED_STORE32(_p, _val) \
((reinterpret_cast< ::absl::internal::Unaligned32Struct *>(_p))->value = \ ((reinterpret_cast< ::absl::base_internal::Unaligned32Struct *>(_p)) \
(_val)) ->value = (_val))
namespace absl { namespace absl {
inline namespace lts_2018_06_20 { inline namespace lts_2018_12_18 {
namespace base_internal {
inline uint64_t UnalignedLoad64(const void *p) { inline uint64_t UnalignedLoad64(const void *p) {
uint64_t t; uint64_t t;
...@@ -200,12 +256,14 @@ inline uint64_t UnalignedLoad64(const void *p) { ...@@ -200,12 +256,14 @@ inline uint64_t UnalignedLoad64(const void *p) {
inline void UnalignedStore64(void *p, uint64_t v) { memcpy(p, &v, sizeof v); } inline void UnalignedStore64(void *p, uint64_t v) { memcpy(p, &v, sizeof v); }
} // inline namespace lts_2018_06_20 } // namespace base_internal
} // inline namespace lts_2018_12_18
} // namespace absl } // namespace absl
#define ABSL_INTERNAL_UNALIGNED_LOAD64(_p) (absl::UnalignedLoad64(_p)) #define ABSL_INTERNAL_UNALIGNED_LOAD64(_p) \
(absl::base_internal::UnalignedLoad64(_p))
#define ABSL_INTERNAL_UNALIGNED_STORE64(_p, _val) \ #define ABSL_INTERNAL_UNALIGNED_STORE64(_p, _val) \
(absl::UnalignedStore64(_p, _val)) (absl::base_internal::UnalignedStore64(_p, _val))
#else #else
...@@ -217,7 +275,8 @@ inline void UnalignedStore64(void *p, uint64_t v) { memcpy(p, &v, sizeof v); } ...@@ -217,7 +275,8 @@ inline void UnalignedStore64(void *p, uint64_t v) { memcpy(p, &v, sizeof v); }
// unaligned loads and stores. // unaligned loads and stores.
namespace absl { namespace absl {
inline namespace lts_2018_06_20 { inline namespace lts_2018_12_18 {
namespace base_internal {
inline uint16_t UnalignedLoad16(const void *p) { inline uint16_t UnalignedLoad16(const void *p) {
uint16_t t; uint16_t t;
...@@ -243,19 +302,23 @@ inline void UnalignedStore32(void *p, uint32_t v) { memcpy(p, &v, sizeof v); } ...@@ -243,19 +302,23 @@ inline void UnalignedStore32(void *p, uint32_t v) { memcpy(p, &v, sizeof v); }
inline void UnalignedStore64(void *p, uint64_t v) { memcpy(p, &v, sizeof v); } inline void UnalignedStore64(void *p, uint64_t v) { memcpy(p, &v, sizeof v); }
} // inline namespace lts_2018_06_20 } // namespace base_internal
} // inline namespace lts_2018_12_18
} // namespace absl } // namespace absl
#define ABSL_INTERNAL_UNALIGNED_LOAD16(_p) (absl::UnalignedLoad16(_p)) #define ABSL_INTERNAL_UNALIGNED_LOAD16(_p) \
#define ABSL_INTERNAL_UNALIGNED_LOAD32(_p) (absl::UnalignedLoad32(_p)) (absl::base_internal::UnalignedLoad16(_p))
#define ABSL_INTERNAL_UNALIGNED_LOAD64(_p) (absl::UnalignedLoad64(_p)) #define ABSL_INTERNAL_UNALIGNED_LOAD32(_p) \
(absl::base_internal::UnalignedLoad32(_p))
#define ABSL_INTERNAL_UNALIGNED_LOAD64(_p) \
(absl::base_internal::UnalignedLoad64(_p))
#define ABSL_INTERNAL_UNALIGNED_STORE16(_p, _val) \ #define ABSL_INTERNAL_UNALIGNED_STORE16(_p, _val) \
(absl::UnalignedStore16(_p, _val)) (absl::base_internal::UnalignedStore16(_p, _val))
#define ABSL_INTERNAL_UNALIGNED_STORE32(_p, _val) \ #define ABSL_INTERNAL_UNALIGNED_STORE32(_p, _val) \
(absl::UnalignedStore32(_p, _val)) (absl::base_internal::UnalignedStore32(_p, _val))
#define ABSL_INTERNAL_UNALIGNED_STORE64(_p, _val) \ #define ABSL_INTERNAL_UNALIGNED_STORE64(_p, _val) \
(absl::UnalignedStore64(_p, _val)) (absl::base_internal::UnalignedStore64(_p, _val))
#endif #endif
......
...@@ -27,7 +27,7 @@ ...@@ -27,7 +27,7 @@
#include "absl/base/internal/sysinfo.h" #include "absl/base/internal/sysinfo.h"
namespace absl { namespace absl {
inline namespace lts_2018_06_20 { inline namespace lts_2018_12_18 {
namespace base_internal { namespace base_internal {
#if defined(__i386__) #if defined(__i386__)
...@@ -97,7 +97,7 @@ double UnscaledCycleClock::Frequency() { ...@@ -97,7 +97,7 @@ double UnscaledCycleClock::Frequency() {
#endif #endif
} // namespace base_internal } // namespace base_internal
} // inline namespace lts_2018_06_20 } // inline namespace lts_2018_12_18
} // namespace absl } // namespace absl
#endif // ABSL_USE_UNSCALED_CYCLECLOCK #endif // ABSL_USE_UNSCALED_CYCLECLOCK
...@@ -84,7 +84,7 @@ ...@@ -84,7 +84,7 @@
#define ABSL_INTERNAL_UNSCALED_CYCLECLOCK_FREQUENCY_IS_CPU_FREQUENCY #define ABSL_INTERNAL_UNSCALED_CYCLECLOCK_FREQUENCY_IS_CPU_FREQUENCY
#endif #endif
namespace absl { namespace absl {
inline namespace lts_2018_06_20 { inline namespace lts_2018_12_18 {
namespace time_internal { namespace time_internal {
class UnscaledCycleClockWrapperForGetCurrentTime; class UnscaledCycleClockWrapperForGetCurrentTime;
} // namespace time_internal } // namespace time_internal
...@@ -114,7 +114,7 @@ class UnscaledCycleClock { ...@@ -114,7 +114,7 @@ class UnscaledCycleClock {
}; };
} // namespace base_internal } // namespace base_internal
} // inline namespace lts_2018_06_20 } // inline namespace lts_2018_12_18
} // namespace absl } // namespace absl
#endif // ABSL_USE_UNSCALED_CYCLECLOCK #endif // ABSL_USE_UNSCALED_CYCLECLOCK
......
...@@ -25,7 +25,7 @@ ...@@ -25,7 +25,7 @@
#include "absl/strings/str_cat.h" #include "absl/strings/str_cat.h"
namespace absl { namespace absl {
inline namespace lts_2018_06_20 { inline namespace lts_2018_12_18 {
namespace base_internal { namespace base_internal {
namespace { namespace {
...@@ -198,5 +198,5 @@ TEST(InvokeTest, SfinaeFriendly) { ...@@ -198,5 +198,5 @@ TEST(InvokeTest, SfinaeFriendly) {
} // namespace } // namespace
} // namespace base_internal } // namespace base_internal
} // inline namespace lts_2018_06_20 } // inline namespace lts_2018_12_18
} // namespace absl } // namespace absl
...@@ -21,7 +21,7 @@ ...@@ -21,7 +21,7 @@
#include "absl/base/attributes.h" #include "absl/base/attributes.h"
namespace absl { namespace absl {
inline namespace lts_2018_06_20 { inline namespace lts_2018_12_18 {
// Four severity levels are defined. Logging APIs should terminate the program // Four severity levels are defined. Logging APIs should terminate the program
// when a message is logged at severity `kFatal`; the other levels have no // when a message is logged at severity `kFatal`; the other levels have no
...@@ -40,7 +40,7 @@ constexpr std::array<absl::LogSeverity, 4> LogSeverities() { ...@@ -40,7 +40,7 @@ constexpr std::array<absl::LogSeverity, 4> LogSeverities() {
absl::LogSeverity::kError, absl::LogSeverity::kFatal}}; absl::LogSeverity::kError, absl::LogSeverity::kFatal}};
} }
// Returns the all-caps std::string representation (e.g. "INFO") of the specified // Returns the all-caps string representation (e.g. "INFO") of the specified
// severity level if it is one of the normal levels and "UNKNOWN" otherwise. // severity level if it is one of the normal levels and "UNKNOWN" otherwise.
constexpr const char* LogSeverityName(absl::LogSeverity s) { constexpr const char* LogSeverityName(absl::LogSeverity s) {
return s == absl::LogSeverity::kInfo return s == absl::LogSeverity::kInfo
...@@ -63,7 +63,7 @@ constexpr absl::LogSeverity NormalizeLogSeverity(int s) { ...@@ -63,7 +63,7 @@ constexpr absl::LogSeverity NormalizeLogSeverity(int s) {
return NormalizeLogSeverity(static_cast<absl::LogSeverity>(s)); return NormalizeLogSeverity(static_cast<absl::LogSeverity>(s));
} }
} // inline namespace lts_2018_06_20 } // inline namespace lts_2018_12_18
} // namespace absl } // namespace absl
#endif // ABSL_BASE_INTERNAL_LOG_SEVERITY_H_ #endif // ABSL_BASE_INTERNAL_LOG_SEVERITY_H_
...@@ -43,14 +43,14 @@ ...@@ -43,14 +43,14 @@
(sizeof(::absl::macros_internal::ArraySizeHelper(array))) (sizeof(::absl::macros_internal::ArraySizeHelper(array)))
namespace absl { namespace absl {
inline namespace lts_2018_06_20 { inline namespace lts_2018_12_18 {
namespace macros_internal { namespace macros_internal {
// Note: this internal template function declaration is used by ABSL_ARRAYSIZE. // Note: this internal template function declaration is used by ABSL_ARRAYSIZE.
// The function doesn't need a definition, as we only use its type. // The function doesn't need a definition, as we only use its type.
template <typename T, size_t N> template <typename T, size_t N>
auto ArraySizeHelper(const T (&array)[N]) -> char (&)[N]; auto ArraySizeHelper(const T (&array)[N]) -> char (&)[N];
} // namespace macros_internal } // namespace macros_internal
} // inline namespace lts_2018_06_20 } // inline namespace lts_2018_12_18
} // namespace absl } // namespace absl
// kLinkerInitialized // kLinkerInitialized
...@@ -74,13 +74,13 @@ auto ArraySizeHelper(const T (&array)[N]) -> char (&)[N]; ...@@ -74,13 +74,13 @@ auto ArraySizeHelper(const T (&array)[N]) -> char (&)[N];
// // Invocation // // Invocation
// static MyClass my_global(absl::base_internal::kLinkerInitialized); // static MyClass my_global(absl::base_internal::kLinkerInitialized);
namespace absl { namespace absl {
inline namespace lts_2018_06_20 { inline namespace lts_2018_12_18 {
namespace base_internal { namespace base_internal {
enum LinkerInitialized { enum LinkerInitialized {
kLinkerInitialized = 0, kLinkerInitialized = 0,
}; };
} // namespace base_internal } // namespace base_internal
} // inline namespace lts_2018_06_20 } // inline namespace lts_2018_12_18
} // namespace absl } // namespace absl
// ABSL_FALLTHROUGH_INTENDED // ABSL_FALLTHROUGH_INTENDED
...@@ -203,4 +203,14 @@ enum LinkerInitialized { ...@@ -203,4 +203,14 @@ enum LinkerInitialized {
: [] { assert(false && #expr); }()) // NOLINT : [] { assert(false && #expr); }()) // NOLINT
#endif #endif
#ifdef ABSL_HAVE_EXCEPTIONS
#define ABSL_INTERNAL_TRY try
#define ABSL_INTERNAL_CATCH_ANY catch (...)
#define ABSL_INTERNAL_RETHROW do { throw; } while (false)
#else // ABSL_HAVE_EXCEPTIONS
#define ABSL_INTERNAL_TRY if (true)
#define ABSL_INTERNAL_CATCH_ANY else if (false)
#define ABSL_INTERNAL_RETHROW do {} while (false)
#endif // ABSL_HAVE_EXCEPTIONS
#endif // ABSL_BASE_MACROS_H_ #endif // ABSL_BASE_MACROS_H_
...@@ -18,12 +18,20 @@ ...@@ -18,12 +18,20 @@
#include "absl/base/internal/raw_logging.h" #include "absl/base/internal/raw_logging.h"
#include <tuple>
#include "gtest/gtest.h" #include "gtest/gtest.h"
#include "absl/strings/str_cat.h"
namespace { namespace {
TEST(RawLoggingCompilationTest, Log) { TEST(RawLoggingCompilationTest, Log) {
ABSL_RAW_LOG(INFO, "RAW INFO: %d", 1); ABSL_RAW_LOG(INFO, "RAW INFO: %d", 1);
ABSL_RAW_LOG(INFO, "RAW INFO: %d %d", 1, 2);
ABSL_RAW_LOG(INFO, "RAW INFO: %d %d %d", 1, 2, 3);
ABSL_RAW_LOG(INFO, "RAW INFO: %d %d %d %d", 1, 2, 3, 4);
ABSL_RAW_LOG(INFO, "RAW INFO: %d %d %d %d %d", 1, 2, 3, 4, 5);
ABSL_RAW_LOG(WARNING, "RAW WARNING: %d", 1);
ABSL_RAW_LOG(ERROR, "RAW ERROR: %d", 1); ABSL_RAW_LOG(ERROR, "RAW ERROR: %d", 1);
} }
...@@ -32,7 +40,7 @@ TEST(RawLoggingCompilationTest, PassingCheck) { ...@@ -32,7 +40,7 @@ TEST(RawLoggingCompilationTest, PassingCheck) {
} }
// Not all platforms support output from raw log, so we don't verify any // Not all platforms support output from raw log, so we don't verify any
// particular output for RAW check failures (expecting the empty std::string // particular output for RAW check failures (expecting the empty string
// accomplishes this). This test is primarily a compilation test, but we // accomplishes this). This test is primarily a compilation test, but we
// are verifying process death when EXPECT_DEATH works for a platform. // are verifying process death when EXPECT_DEATH works for a platform.
const char kExpectedDeathOutput[] = ""; const char kExpectedDeathOutput[] = "";
...@@ -47,4 +55,25 @@ TEST(RawLoggingDeathTest, LogFatal) { ...@@ -47,4 +55,25 @@ TEST(RawLoggingDeathTest, LogFatal) {
kExpectedDeathOutput); kExpectedDeathOutput);
} }
TEST(InternalLog, CompilationTest) {
ABSL_INTERNAL_LOG(INFO, "Internal Log");
std::string log_msg = "Internal Log";
ABSL_INTERNAL_LOG(INFO, log_msg);
ABSL_INTERNAL_LOG(INFO, log_msg + " 2");
float d = 1.1f;
ABSL_INTERNAL_LOG(INFO, absl::StrCat("Internal log ", 3, " + ", d));
}
TEST(InternalLogDeathTest, FailingCheck) {
EXPECT_DEATH_IF_SUPPORTED(ABSL_INTERNAL_CHECK(1 == 0, "explanation"),
kExpectedDeathOutput);
}
TEST(InternalLogDeathTest, LogFatal) {
EXPECT_DEATH_IF_SUPPORTED(ABSL_INTERNAL_LOG(FATAL, "my dog has fleas"),
kExpectedDeathOutput);
}
} // namespace } // namespace
...@@ -36,7 +36,7 @@ constexpr int32_t kNumThreads = 10; ...@@ -36,7 +36,7 @@ constexpr int32_t kNumThreads = 10;
constexpr int32_t kIters = 1000; constexpr int32_t kIters = 1000;
namespace absl { namespace absl {
inline namespace lts_2018_06_20 { inline namespace lts_2018_12_18 {
namespace base_internal { namespace base_internal {
// This is defined outside of anonymous namespace so that it can be // This is defined outside of anonymous namespace so that it can be
...@@ -156,7 +156,8 @@ TEST(SpinLock, WaitCyclesEncoding) { ...@@ -156,7 +156,8 @@ TEST(SpinLock, WaitCyclesEncoding) {
// Test corner cases // Test corner cases
int64_t start_time = time_distribution(generator); int64_t start_time = time_distribution(generator);
EXPECT_EQ(0, SpinLockTest::EncodeWaitCycles(start_time, start_time)); EXPECT_EQ(kSpinLockSleeper,
SpinLockTest::EncodeWaitCycles(start_time, start_time));
EXPECT_EQ(0, SpinLockTest::DecodeWaitCycles(0)); EXPECT_EQ(0, SpinLockTest::DecodeWaitCycles(0));
EXPECT_EQ(0, SpinLockTest::DecodeWaitCycles(kLockwordReservedMask)); EXPECT_EQ(0, SpinLockTest::DecodeWaitCycles(kLockwordReservedMask));
EXPECT_EQ(kMaxCycles & ~kProfileTimestampMask, EXPECT_EQ(kMaxCycles & ~kProfileTimestampMask,
...@@ -264,5 +265,5 @@ TEST(SpinLockWithThreads, DoesNotDeadlock) { ...@@ -264,5 +265,5 @@ TEST(SpinLockWithThreads, DoesNotDeadlock) {
} // namespace } // namespace
} // namespace base_internal } // namespace base_internal
} // inline namespace lts_2018_06_20 } // inline namespace lts_2018_12_18
} // namespace absl } // namespace absl
...@@ -31,7 +31,6 @@ ...@@ -31,7 +31,6 @@
// that evaluate to a concrete mutex object whenever possible. If the mutex // that evaluate to a concrete mutex object whenever possible. If the mutex
// you want to refer to is not in scope, you may use a member pointer // you want to refer to is not in scope, you may use a member pointer
// (e.g. &MyClass::mutex_) to refer to a mutex in some (unknown) object. // (e.g. &MyClass::mutex_) to refer to a mutex in some (unknown) object.
//
#ifndef ABSL_BASE_THREAD_ANNOTATIONS_H_ #ifndef ABSL_BASE_THREAD_ANNOTATIONS_H_
#define ABSL_BASE_THREAD_ANNOTATIONS_H_ #define ABSL_BASE_THREAD_ANNOTATIONS_H_
...@@ -109,13 +108,23 @@ ...@@ -109,13 +108,23 @@
// The mutex is expected to be held both on entry to, and exit from, the // The mutex is expected to be held both on entry to, and exit from, the
// function. // function.
// //
// An exclusive lock allows read-write access to the guarded data member(s), and
// only one thread can acquire a lock exclusively at any one time. A shared lock
// allows read-only access, and any number of threads can acquire a shared lock
// concurrently.
//
// Generally, non-const methods should be annotated with
// EXCLUSIVE_LOCKS_REQUIRED, while const methods should be annotated with
// SHARED_LOCKS_REQUIRED.
//
// Example: // Example:
// //
// Mutex mu1, mu2; // Mutex mu1, mu2;
// int a GUARDED_BY(mu1); // int a GUARDED_BY(mu1);
// int b GUARDED_BY(mu2); // int b GUARDED_BY(mu2);
// //
// void foo() EXCLUSIVE_LOCKS_REQUIRED(mu1, mu2) { ... }; // void foo() EXCLUSIVE_LOCKS_REQUIRED(mu1, mu2) { ... }
// void bar() const SHARED_LOCKS_REQUIRED(mu1, mu2) { ... }
#define EXCLUSIVE_LOCKS_REQUIRED(...) \ #define EXCLUSIVE_LOCKS_REQUIRED(...) \
THREAD_ANNOTATION_ATTRIBUTE__(exclusive_locks_required(__VA_ARGS__)) THREAD_ANNOTATION_ATTRIBUTE__(exclusive_locks_required(__VA_ARGS__))
......
#
# Copyright 2018 The Abseil Authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
"""Creates config_setting that allows selecting based on 'compiler' value."""
def create_llvm_config(name, visibility):
# The "do_not_use_tools_cpp_compiler_present" attribute exists to
# distinguish between older versions of Bazel that do not support
# "@bazel_tools//tools/cpp:compiler" flag_value, and newer ones that do.
# In the future, the only way to select on the compiler will be through
# flag_values{"@bazel_tools//tools/cpp:compiler"} and the else branch can
# be removed.
if hasattr(cc_common, "do_not_use_tools_cpp_compiler_present"):
native.config_setting(
name = name,
flag_values = {
"@bazel_tools//tools/cpp:compiler": "llvm",
},
visibility = visibility,
)
else:
native.config_setting(
name = name,
values = {"compiler": "llvm"},
visibility = visibility,
)
// Copyright 2017 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <initializer_list>
#include "absl/container/fixed_array.h"
#include "gtest/gtest.h"
#include "absl/base/internal/exception_safety_testing.h"
namespace absl {
inline namespace lts_2018_12_18 {
namespace {
constexpr size_t kInlined = 25;
constexpr size_t kSmallSize = kInlined / 2;
constexpr size_t kLargeSize = kInlined * 2;
constexpr int kInitialValue = 5;
constexpr int kUpdatedValue = 10;
using ::testing::TestThrowingCtor;
using Thrower = testing::ThrowingValue<testing::TypeSpec::kEverythingThrows>;
using FixedArr = absl::FixedArray<Thrower, kInlined>;
using MoveThrower = testing::ThrowingValue<testing::TypeSpec::kNoThrowMove>;
using MoveFixedArr = absl::FixedArray<MoveThrower, kInlined>;
TEST(FixedArrayExceptionSafety, CopyConstructor) {
auto small = FixedArr(kSmallSize);
TestThrowingCtor<FixedArr>(small);
auto large = FixedArr(kLargeSize);
TestThrowingCtor<FixedArr>(large);
}
TEST(FixedArrayExceptionSafety, MoveConstructor) {
TestThrowingCtor<FixedArr>(FixedArr(kSmallSize));
TestThrowingCtor<FixedArr>(FixedArr(kLargeSize));
// TypeSpec::kNoThrowMove
TestThrowingCtor<MoveFixedArr>(MoveFixedArr(kSmallSize));
TestThrowingCtor<MoveFixedArr>(MoveFixedArr(kLargeSize));
}
TEST(FixedArrayExceptionSafety, SizeConstructor) {
TestThrowingCtor<FixedArr>(kSmallSize);
TestThrowingCtor<FixedArr>(kLargeSize);
}
TEST(FixedArrayExceptionSafety, SizeValueConstructor) {
TestThrowingCtor<FixedArr>(kSmallSize, Thrower());
TestThrowingCtor<FixedArr>(kLargeSize, Thrower());
}
TEST(FixedArrayExceptionSafety, IteratorConstructor) {
auto small = FixedArr(kSmallSize);
TestThrowingCtor<FixedArr>(small.begin(), small.end());
auto large = FixedArr(kLargeSize);
TestThrowingCtor<FixedArr>(large.begin(), large.end());
}
TEST(FixedArrayExceptionSafety, InitListConstructor) {
constexpr int small_inlined = 3;
using SmallFixedArr = absl::FixedArray<Thrower, small_inlined>;
TestThrowingCtor<SmallFixedArr>(std::initializer_list<Thrower>{});
// Test inlined allocation
TestThrowingCtor<SmallFixedArr>(
std::initializer_list<Thrower>{Thrower{}, Thrower{}});
// Test out of line allocation
TestThrowingCtor<SmallFixedArr>(std::initializer_list<Thrower>{
Thrower{}, Thrower{}, Thrower{}, Thrower{}, Thrower{}});
}
testing::AssertionResult ReadMemory(FixedArr* fixed_arr) {
// Marked volatile to prevent optimization. Used for running asan tests.
volatile int sum = 0;
for (const auto& thrower : *fixed_arr) {
sum += thrower.Get();
}
return testing::AssertionSuccess() << "Values sum to [" << sum << "]";
}
TEST(FixedArrayExceptionSafety, Fill) {
auto test_fill = testing::MakeExceptionSafetyTester()
.WithContracts(ReadMemory)
.WithOperation([&](FixedArr* fixed_arr_ptr) {
auto thrower =
Thrower(kUpdatedValue, testing::nothrow_ctor);
fixed_arr_ptr->fill(thrower);
});
EXPECT_TRUE(
test_fill.WithInitialValue(FixedArr(kSmallSize, Thrower(kInitialValue)))
.Test());
EXPECT_TRUE(
test_fill.WithInitialValue(FixedArr(kLargeSize, Thrower(kInitialValue)))
.Test());
}
} // namespace
} // inline namespace lts_2018_12_18
} // namespace absl
...@@ -15,9 +15,11 @@ ...@@ -15,9 +15,11 @@
#include "absl/container/fixed_array.h" #include "absl/container/fixed_array.h"
#include <stdio.h> #include <stdio.h>
#include <cstring>
#include <list> #include <list>
#include <memory> #include <memory>
#include <numeric> #include <numeric>
#include <scoped_allocator>
#include <stdexcept> #include <stdexcept>
#include <string> #include <string>
#include <vector> #include <vector>
...@@ -25,6 +27,7 @@ ...@@ -25,6 +27,7 @@
#include "gmock/gmock.h" #include "gmock/gmock.h"
#include "gtest/gtest.h" #include "gtest/gtest.h"
#include "absl/base/internal/exception_testing.h" #include "absl/base/internal/exception_testing.h"
#include "absl/hash/hash_testing.h"
#include "absl/memory/memory.h" #include "absl/memory/memory.h"
using ::testing::ElementsAreArray; using ::testing::ElementsAreArray;
...@@ -607,6 +610,216 @@ TEST(FixedArrayTest, Fill) { ...@@ -607,6 +610,216 @@ TEST(FixedArrayTest, Fill) {
empty.fill(fill_val); empty.fill(fill_val);
} }
// TODO(johnsoncj): Investigate InlinedStorage default initialization in GCC 4.x
#ifndef __GNUC__
TEST(FixedArrayTest, DefaultCtorDoesNotValueInit) {
using T = char;
constexpr auto capacity = 10;
using FixedArrType = absl::FixedArray<T, capacity>;
using FixedArrBuffType =
absl::aligned_storage_t<sizeof(FixedArrType), alignof(FixedArrType)>;
constexpr auto scrubbed_bits = 0x95;
constexpr auto length = capacity / 2;
FixedArrBuffType buff;
std::memset(std::addressof(buff), scrubbed_bits, sizeof(FixedArrBuffType));
FixedArrType* arr =
::new (static_cast<void*>(std::addressof(buff))) FixedArrType(length);
EXPECT_THAT(*arr, testing::Each(scrubbed_bits));
arr->~FixedArrType();
}
#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) {
constexpr size_t inlined_size = 4;
using Alloc = CountingAllocator<int>;
using AllocFxdArr = absl::FixedArray<int, inlined_size, Alloc>;
int64_t allocated = 0;
int64_t active_instances = 0;
{
const int ia[] = {0, 1, 2, 3, 4, 5, 6, 7};
Alloc alloc(&allocated, &active_instances);
AllocFxdArr arr(ia, ia + inlined_size, alloc);
static_cast<void>(arr);
}
EXPECT_EQ(allocated, 0);
EXPECT_EQ(active_instances, 0);
}
TEST(AllocatorSupportTest, CountOutoflineAllocations) {
constexpr size_t inlined_size = 4;
using Alloc = CountingAllocator<int>;
using AllocFxdArr = absl::FixedArray<int, inlined_size, Alloc>;
int64_t allocated = 0;
int64_t active_instances = 0;
{
const int ia[] = {0, 1, 2, 3, 4, 5, 6, 7};
Alloc alloc(&allocated, &active_instances);
AllocFxdArr arr(ia, ia + ABSL_ARRAYSIZE(ia), alloc);
EXPECT_EQ(allocated, arr.size() * sizeof(int));
static_cast<void>(arr);
}
EXPECT_EQ(active_instances, 0);
}
TEST(AllocatorSupportTest, CountCopyInlineAllocations) {
constexpr size_t inlined_size = 4;
using Alloc = CountingAllocator<int>;
using AllocFxdArr = absl::FixedArray<int, inlined_size, Alloc>;
int64_t allocated1 = 0;
int64_t allocated2 = 0;
int64_t active_instances = 0;
Alloc alloc(&allocated1, &active_instances);
Alloc alloc2(&allocated2, &active_instances);
{
int initial_value = 1;
AllocFxdArr arr1(inlined_size / 2, initial_value, alloc);
EXPECT_EQ(allocated1, 0);
AllocFxdArr arr2(arr1, alloc2);
EXPECT_EQ(allocated2, 0);
static_cast<void>(arr1);
static_cast<void>(arr2);
}
EXPECT_EQ(active_instances, 0);
}
TEST(AllocatorSupportTest, CountCopyOutoflineAllocations) {
constexpr size_t inlined_size = 4;
using Alloc = CountingAllocator<int>;
using AllocFxdArr = absl::FixedArray<int, inlined_size, Alloc>;
int64_t allocated1 = 0;
int64_t allocated2 = 0;
int64_t active_instances = 0;
Alloc alloc(&allocated1, &active_instances);
Alloc alloc2(&allocated2, &active_instances);
{
int initial_value = 1;
AllocFxdArr arr1(inlined_size * 2, initial_value, alloc);
EXPECT_EQ(allocated1, arr1.size() * sizeof(int));
AllocFxdArr arr2(arr1, alloc2);
EXPECT_EQ(allocated2, inlined_size * 2 * sizeof(int));
static_cast<void>(arr1);
static_cast<void>(arr2);
}
EXPECT_EQ(active_instances, 0);
}
TEST(AllocatorSupportTest, SizeValAllocConstructor) {
using testing::AllOf;
using testing::Each;
using testing::SizeIs;
constexpr size_t inlined_size = 4;
using Alloc = CountingAllocator<int>;
using AllocFxdArr = absl::FixedArray<int, inlined_size, Alloc>;
{
auto len = inlined_size / 2;
auto val = 0;
int64_t allocated = 0;
AllocFxdArr arr(len, val, Alloc(&allocated));
EXPECT_EQ(allocated, 0);
EXPECT_THAT(arr, AllOf(SizeIs(len), Each(0)));
}
{
auto len = inlined_size * 2;
auto val = 0;
int64_t allocated = 0;
AllocFxdArr arr(len, val, Alloc(&allocated));
EXPECT_EQ(allocated, len * sizeof(int));
EXPECT_THAT(arr, AllOf(SizeIs(len), Each(0)));
}
}
#ifdef ADDRESS_SANITIZER #ifdef ADDRESS_SANITIZER
TEST(FixedArrayTest, AddressSanitizerAnnotations1) { TEST(FixedArrayTest, AddressSanitizerAnnotations1) {
absl::FixedArray<int, 32> a(10); absl::FixedArray<int, 32> a(10);
......
// Copyright 2018 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "absl/container/flat_hash_map.h"
#include "absl/container/internal/hash_generator_testing.h"
#include "absl/container/internal/unordered_map_constructor_test.h"
#include "absl/container/internal/unordered_map_lookup_test.h"
#include "absl/container/internal/unordered_map_modifiers_test.h"
#include "absl/types/any.h"
namespace absl {
inline namespace lts_2018_12_18 {
namespace container_internal {
namespace {
using ::absl::container_internal::hash_internal::Enum;
using ::absl::container_internal::hash_internal::EnumClass;
using ::testing::_;
using ::testing::Pair;
using ::testing::UnorderedElementsAre;
template <class K, class V>
using Map =
flat_hash_map<K, V, StatefulTestingHash, StatefulTestingEqual, Alloc<>>;
static_assert(!std::is_standard_layout<NonStandardLayout>(), "");
using MapTypes =
::testing::Types<Map<int, int>, Map<std::string, int>, Map<Enum, std::string>,
Map<EnumClass, int>, Map<int, NonStandardLayout>,
Map<NonStandardLayout, int>>;
INSTANTIATE_TYPED_TEST_CASE_P(FlatHashMap, ConstructorTest, MapTypes);
INSTANTIATE_TYPED_TEST_CASE_P(FlatHashMap, LookupTest, MapTypes);
INSTANTIATE_TYPED_TEST_CASE_P(FlatHashMap, ModifiersTest, MapTypes);
TEST(FlatHashMap, StandardLayout) {
struct Int {
explicit Int(size_t value) : value(value) {}
Int() : value(0) { ADD_FAILURE(); }
Int(const Int& other) : value(other.value) { ADD_FAILURE(); }
Int(Int&&) = default;
bool operator==(const Int& other) const { return value == other.value; }
size_t value;
};
static_assert(std::is_standard_layout<Int>(), "");
struct Hash {
size_t operator()(const Int& obj) const { return obj.value; }
};
// Verify that neither the key nor the value get default-constructed or
// copy-constructed.
{
flat_hash_map<Int, Int, Hash> m;
m.try_emplace(Int(1), Int(2));
m.try_emplace(Int(3), Int(4));
m.erase(Int(1));
m.rehash(2 * m.bucket_count());
}
{
flat_hash_map<Int, Int, Hash> m;
m.try_emplace(Int(1), Int(2));
m.try_emplace(Int(3), Int(4));
m.erase(Int(1));
m.clear();
}
}
// gcc becomes unhappy if this is inside the method, so pull it out here.
struct balast {};
TEST(FlatHashMap, IteratesMsan) {
// Because SwissTable randomizes on pointer addresses, we keep old tables
// around to ensure we don't reuse old memory.
std::vector<absl::flat_hash_map<int, balast>> garbage;
for (int i = 0; i < 100; ++i) {
absl::flat_hash_map<int, balast> t;
for (int j = 0; j < 100; ++j) {
t[j];
for (const auto& p : t) EXPECT_THAT(p, Pair(_, _));
}
garbage.push_back(std::move(t));
}
}
// Demonstration of the "Lazy Key" pattern. This uses heterogeneous insert to
// avoid creating expensive key elements when the item is already present in the
// map.
struct LazyInt {
explicit LazyInt(size_t value, int* tracker)
: value(value), tracker(tracker) {}
explicit operator size_t() const {
++*tracker;
return value;
}
size_t value;
int* tracker;
};
struct Hash {
using is_transparent = void;
int* tracker;
size_t operator()(size_t obj) const {
++*tracker;
return obj;
}
size_t operator()(const LazyInt& obj) const {
++*tracker;
return obj.value;
}
};
struct Eq {
using is_transparent = void;
bool operator()(size_t lhs, size_t rhs) const {
return lhs == rhs;
}
bool operator()(size_t lhs, const LazyInt& rhs) const {
return lhs == rhs.value;
}
};
TEST(FlatHashMap, LazyKeyPattern) {
// hashes are only guaranteed in opt mode, we use assertions to track internal
// state that can cause extra calls to hash.
int conversions = 0;
int hashes = 0;
flat_hash_map<size_t, size_t, Hash, Eq> m(0, Hash{&hashes});
m[LazyInt(1, &conversions)] = 1;
EXPECT_THAT(m, UnorderedElementsAre(Pair(1, 1)));
EXPECT_EQ(conversions, 1);
#ifdef NDEBUG
EXPECT_EQ(hashes, 1);
#endif
m[LazyInt(1, &conversions)] = 2;
EXPECT_THAT(m, UnorderedElementsAre(Pair(1, 2)));
EXPECT_EQ(conversions, 1);
#ifdef NDEBUG
EXPECT_EQ(hashes, 2);
#endif
m.try_emplace(LazyInt(2, &conversions), 3);
EXPECT_THAT(m, UnorderedElementsAre(Pair(1, 2), Pair(2, 3)));
EXPECT_EQ(conversions, 2);
#ifdef NDEBUG
EXPECT_EQ(hashes, 3);
#endif
m.try_emplace(LazyInt(2, &conversions), 4);
EXPECT_THAT(m, UnorderedElementsAre(Pair(1, 2), Pair(2, 3)));
EXPECT_EQ(conversions, 2);
#ifdef NDEBUG
EXPECT_EQ(hashes, 4);
#endif
}
TEST(FlatHashMap, BitfieldArgument) {
union {
int n : 1;
};
n = 0;
flat_hash_map<int, int> m;
m.erase(n);
m.count(n);
m.prefetch(n);
m.find(n);
m.contains(n);
m.equal_range(n);
m.insert_or_assign(n, n);
m.insert_or_assign(m.end(), n, n);
m.try_emplace(n);
m.try_emplace(m.end(), n);
m.at(n);
m[n];
}
TEST(FlatHashMap, MergeExtractInsert) {
// We can't test mutable keys, or non-copyable keys with flat_hash_map.
// Test that the nodes have the proper API.
absl::flat_hash_map<int, int> m = {{1, 7}, {2, 9}};
auto node = m.extract(1);
EXPECT_TRUE(node);
EXPECT_EQ(node.key(), 1);
EXPECT_EQ(node.mapped(), 7);
EXPECT_THAT(m, UnorderedElementsAre(Pair(2, 9)));
node.mapped() = 17;
m.insert(std::move(node));
EXPECT_THAT(m, UnorderedElementsAre(Pair(1, 17), Pair(2, 9)));
}
#if !defined(__ANDROID__) && !defined(__APPLE__) && !defined(__EMSCRIPTEN__)
TEST(FlatHashMap, Any) {
absl::flat_hash_map<int, absl::any> m;
m.emplace(1, 7);
auto it = m.find(1);
ASSERT_NE(it, m.end());
EXPECT_EQ(7, absl::any_cast<int>(it->second));
m.emplace(std::piecewise_construct, std::make_tuple(2), std::make_tuple(8));
it = m.find(2);
ASSERT_NE(it, m.end());
EXPECT_EQ(8, absl::any_cast<int>(it->second));
m.emplace(std::piecewise_construct, std::make_tuple(3),
std::make_tuple(absl::any(9)));
it = m.find(3);
ASSERT_NE(it, m.end());
EXPECT_EQ(9, absl::any_cast<int>(it->second));
struct H {
size_t operator()(const absl::any&) const { return 0; }
};
struct E {
bool operator()(const absl::any&, const absl::any&) const { return true; }
};
absl::flat_hash_map<absl::any, int, H, E> m2;
m2.emplace(1, 7);
auto it2 = m2.find(1);
ASSERT_NE(it2, m2.end());
EXPECT_EQ(7, it2->second);
}
#endif // __ANDROID__
} // namespace
} // namespace container_internal
} // inline namespace lts_2018_12_18
} // namespace absl
// Copyright 2018 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "absl/container/flat_hash_set.h"
#include <vector>
#include "absl/container/internal/hash_generator_testing.h"
#include "absl/container/internal/unordered_set_constructor_test.h"
#include "absl/container/internal/unordered_set_lookup_test.h"
#include "absl/container/internal/unordered_set_modifiers_test.h"
#include "absl/memory/memory.h"
#include "absl/strings/string_view.h"
namespace absl {
inline namespace lts_2018_12_18 {
namespace container_internal {
namespace {
using ::absl::container_internal::hash_internal::Enum;
using ::absl::container_internal::hash_internal::EnumClass;
using ::testing::Pointee;
using ::testing::UnorderedElementsAre;
using ::testing::UnorderedElementsAreArray;
template <class T>
using Set =
absl::flat_hash_set<T, StatefulTestingHash, StatefulTestingEqual, Alloc<T>>;
using SetTypes =
::testing::Types<Set<int>, Set<std::string>, Set<Enum>, Set<EnumClass>>;
INSTANTIATE_TYPED_TEST_CASE_P(FlatHashSet, ConstructorTest, SetTypes);
INSTANTIATE_TYPED_TEST_CASE_P(FlatHashSet, LookupTest, SetTypes);
INSTANTIATE_TYPED_TEST_CASE_P(FlatHashSet, ModifiersTest, SetTypes);
TEST(FlatHashSet, EmplaceString) {
std::vector<std::string> v = {"a", "b"};
absl::flat_hash_set<absl::string_view> hs(v.begin(), v.end());
EXPECT_THAT(hs, UnorderedElementsAreArray(v));
}
TEST(FlatHashSet, BitfieldArgument) {
union {
int n : 1;
};
n = 0;
absl::flat_hash_set<int> s = {n};
s.insert(n);
s.insert(s.end(), n);
s.insert({n});
s.erase(n);
s.count(n);
s.prefetch(n);
s.find(n);
s.contains(n);
s.equal_range(n);
}
TEST(FlatHashSet, MergeExtractInsert) {
struct Hash {
size_t operator()(const std::unique_ptr<int>& p) const { return *p; }
};
struct Eq {
bool operator()(const std::unique_ptr<int>& a,
const std::unique_ptr<int>& b) const {
return *a == *b;
}
};
absl::flat_hash_set<std::unique_ptr<int>, Hash, Eq> set1, set2;
set1.insert(absl::make_unique<int>(7));
set1.insert(absl::make_unique<int>(17));
set2.insert(absl::make_unique<int>(7));
set2.insert(absl::make_unique<int>(19));
EXPECT_THAT(set1, UnorderedElementsAre(Pointee(7), Pointee(17)));
EXPECT_THAT(set2, UnorderedElementsAre(Pointee(7), Pointee(19)));
set1.merge(set2);
EXPECT_THAT(set1, UnorderedElementsAre(Pointee(7), Pointee(17), Pointee(19)));
EXPECT_THAT(set2, UnorderedElementsAre(Pointee(7)));
auto node = set1.extract(absl::make_unique<int>(7));
EXPECT_TRUE(node);
EXPECT_THAT(node.value(), Pointee(7));
EXPECT_THAT(set1, UnorderedElementsAre(Pointee(17), Pointee(19)));
auto insert_result = set2.insert(std::move(node));
EXPECT_FALSE(node);
EXPECT_FALSE(insert_result.inserted);
EXPECT_TRUE(insert_result.node);
EXPECT_THAT(insert_result.node.value(), Pointee(7));
EXPECT_EQ(**insert_result.position, 7);
EXPECT_NE(insert_result.position->get(), insert_result.node.value().get());
EXPECT_THAT(set2, UnorderedElementsAre(Pointee(7)));
node = set1.extract(absl::make_unique<int>(17));
EXPECT_TRUE(node);
EXPECT_THAT(node.value(), Pointee(17));
EXPECT_THAT(set1, UnorderedElementsAre(Pointee(19)));
node.value() = absl::make_unique<int>(23);
insert_result = set2.insert(std::move(node));
EXPECT_FALSE(node);
EXPECT_TRUE(insert_result.inserted);
EXPECT_FALSE(insert_result.node);
EXPECT_EQ(**insert_result.position, 23);
EXPECT_THAT(set2, UnorderedElementsAre(Pointee(7), Pointee(23)));
}
} // namespace
} // namespace container_internal
} // inline namespace lts_2018_12_18
} // namespace absl
...@@ -66,7 +66,7 @@ BENCHMARK(BM_StdVectorFill)->Range(0, 1024); ...@@ -66,7 +66,7 @@ BENCHMARK(BM_StdVectorFill)->Range(0, 1024);
// The purpose of the next two benchmarks is to verify that // The purpose of the next two benchmarks is to verify that
// absl::InlinedVector is efficient when moving is more efficent than // absl::InlinedVector is efficient when moving is more efficent than
// copying. To do so, we use strings that are larger than the short // copying. To do so, we use strings that are larger than the short
// std::string optimization. // string optimization.
bool StringRepresentedInline(std::string s) { bool StringRepresentedInline(std::string s) {
const char* chars = s.data(); const char* chars = s.data();
std::string s1 = std::move(s); std::string s1 = std::move(s);
......
...@@ -31,6 +31,7 @@ ...@@ -31,6 +31,7 @@
#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/container/internal/test_instance_tracker.h" #include "absl/container/internal/test_instance_tracker.h"
#include "absl/hash/hash_testing.h"
#include "absl/memory/memory.h" #include "absl/memory/memory.h"
#include "absl/strings/str_cat.h" #include "absl/strings/str_cat.h"
...@@ -905,6 +906,8 @@ TYPED_TEST_P(InstanceTest, Swap) { ...@@ -905,6 +906,8 @@ TYPED_TEST_P(InstanceTest, Swap) {
InstanceTracker tracker; InstanceTracker tracker;
InstanceVec a, b; InstanceVec a, b;
const size_t inlined_capacity = a.capacity(); const size_t inlined_capacity = a.capacity();
auto min_len = std::min(l1, l2);
auto max_len = std::max(l1, l2);
for (int i = 0; i < l1; i++) a.push_back(Instance(i)); for (int i = 0; i < l1; i++) a.push_back(Instance(i));
for (int i = 0; i < l2; i++) b.push_back(Instance(100+i)); for (int i = 0; i < l2; i++) b.push_back(Instance(100+i));
EXPECT_EQ(tracker.instances(), l1 + l2); EXPECT_EQ(tracker.instances(), l1 + l2);
...@@ -918,15 +921,15 @@ TYPED_TEST_P(InstanceTest, Swap) { ...@@ -918,15 +921,15 @@ TYPED_TEST_P(InstanceTest, Swap) {
EXPECT_EQ(tracker.swaps(), 0); // Allocations are swapped. EXPECT_EQ(tracker.swaps(), 0); // Allocations are swapped.
EXPECT_EQ(tracker.moves(), 0); EXPECT_EQ(tracker.moves(), 0);
} else if (a.size() <= inlined_capacity && b.size() <= inlined_capacity) { } else if (a.size() <= inlined_capacity && b.size() <= inlined_capacity) {
EXPECT_EQ(tracker.swaps(), std::min(l1, l2)); EXPECT_EQ(tracker.swaps(), min_len);
// TODO(bsamwel): This should use moves when the type is movable. EXPECT_EQ((tracker.moves() ? tracker.moves() : tracker.copies()),
EXPECT_EQ(tracker.copies(), std::max(l1, l2) - std::min(l1, l2)); max_len - min_len);
} else { } else {
// One is allocated and the other isn't. The allocation is transferred // One is allocated and the other isn't. The allocation is transferred
// without copying elements, and the inlined instances are copied/moved. // without copying elements, and the inlined instances are copied/moved.
EXPECT_EQ(tracker.swaps(), 0); EXPECT_EQ(tracker.swaps(), 0);
// TODO(bsamwel): This should use moves when the type is movable. EXPECT_EQ((tracker.moves() ? tracker.moves() : tracker.copies()),
EXPECT_EQ(tracker.copies(), std::min(l1, l2)); min_len);
} }
EXPECT_EQ(l1, b.size()); EXPECT_EQ(l1, b.size());
...@@ -1725,42 +1728,87 @@ TEST(AllocatorSupportTest, ScopedAllocatorWorks) { ...@@ -1725,42 +1728,87 @@ TEST(AllocatorSupportTest, ScopedAllocatorWorks) {
std::scoped_allocator_adaptor<CountingAllocator<StdVector>>; std::scoped_allocator_adaptor<CountingAllocator<StdVector>>;
using AllocVec = absl::InlinedVector<StdVector, 4, MyAlloc>; using AllocVec = absl::InlinedVector<StdVector, 4, MyAlloc>;
// MSVC 2017's std::vector allocates different amounts of memory in debug
// versus opt mode.
int64_t test_allocated = 0;
StdVector v(CountingAllocator<int>{&test_allocated});
// The amount of memory allocated by a default constructed vector<int>
auto default_std_vec_allocated = test_allocated;
v.push_back(1);
// The amound of memory allocated by a copy-constructed vector<int> with one
// element.
int64_t one_element_std_vec_copy_allocated = test_allocated;
int64_t allocated = 0; int64_t allocated = 0;
AllocVec vec(MyAlloc{CountingAllocator<StdVector>{&allocated}}); AllocVec vec(MyAlloc{CountingAllocator<StdVector>{&allocated}});
EXPECT_EQ(allocated, 0); EXPECT_EQ(allocated, 0);
// This default constructs a vector<int>, but the allocator should pass itself // This default constructs a vector<int>, but the allocator should pass itself
// into the vector<int>. // into the vector<int>, so check allocation compared to that.
// The absl::InlinedVector does not allocate any memory. // The absl::InlinedVector does not allocate any memory.
// The vector<int> does not allocate any memory. // The vector<int> may allocate any memory.
auto expected = default_std_vec_allocated;
vec.resize(1); vec.resize(1);
EXPECT_EQ(allocated, 0); EXPECT_EQ(allocated, expected);
// We make vector<int> allocate memory. // We make vector<int> allocate memory.
// It must go through the allocator even though we didn't construct the // It must go through the allocator even though we didn't construct the
// vector directly. // vector directly. This assumes that vec[0] doesn't need to grow its
// allocation.
expected += sizeof(int);
vec[0].push_back(1); vec[0].push_back(1);
EXPECT_EQ(allocated, sizeof(int) * 1); EXPECT_EQ(allocated, expected);
// Another allocating vector. // Another allocating vector.
expected += one_element_std_vec_copy_allocated;
vec.push_back(vec[0]); vec.push_back(vec[0]);
EXPECT_EQ(allocated, sizeof(int) * 2); EXPECT_EQ(allocated, expected);
// Overflow the inlined memory. // Overflow the inlined memory.
// The absl::InlinedVector will now allocate. // The absl::InlinedVector will now allocate.
expected += sizeof(StdVector) * 8 + default_std_vec_allocated * 3;
vec.resize(5); vec.resize(5);
EXPECT_EQ(allocated, sizeof(int) * 2 + sizeof(StdVector) * 8); EXPECT_EQ(allocated, expected);
// Adding one more in external mode should also work. // Adding one more in external mode should also work.
expected += one_element_std_vec_copy_allocated;
vec.push_back(vec[0]); vec.push_back(vec[0]);
EXPECT_EQ(allocated, sizeof(int) * 3 + sizeof(StdVector) * 8); EXPECT_EQ(allocated, expected);
// And extending these should still work. // And extending these should still work. This assumes that vec[0] does not
// need to grow its allocation.
expected += sizeof(int);
vec[0].push_back(1); vec[0].push_back(1);
EXPECT_EQ(allocated, sizeof(int) * 4 + sizeof(StdVector) * 8); EXPECT_EQ(allocated, expected);
vec.clear(); vec.clear();
EXPECT_EQ(allocated, 0); EXPECT_EQ(allocated, 0);
} }
TEST(AllocatorSupportTest, SizeAllocConstructor) {
constexpr int inlined_size = 4;
using Alloc = CountingAllocator<int>;
using AllocVec = absl::InlinedVector<int, inlined_size, Alloc>;
{
auto len = inlined_size / 2;
int64_t allocated = 0;
auto v = AllocVec(len, Alloc(&allocated));
// Inline storage used; allocator should not be invoked
EXPECT_THAT(allocated, 0);
EXPECT_THAT(v, AllOf(SizeIs(len), Each(0)));
}
{
auto len = inlined_size * 2;
int64_t allocated = 0;
auto v = AllocVec(len, Alloc(&allocated));
// Out of line storage used; allocation of 8 elements expected
EXPECT_THAT(allocated, len * sizeof(int));
EXPECT_THAT(v, AllOf(SizeIs(len), Each(0)));
}
}
} // anonymous namespace } // anonymous namespace
// Copyright 2018 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Helper class to perform the Empty Base Optimization.
// Ts can contain classes and non-classes, empty or not. For the ones that
// are empty classes, we perform the optimization. If all types in Ts are empty
// classes, then CompressedTuple<Ts...> is itself an empty class.
//
// To access the members, use member get<N>() function.
//
// Eg:
// absl::container_internal::CompressedTuple<int, T1, T2, T3> value(7, t1, t2,
// t3);
// assert(value.get<0>() == 7);
// T1& t1 = value.get<1>();
// const T2& t2 = value.get<2>();
// ...
//
// http://en.cppreference.com/w/cpp/language/ebo
#ifndef ABSL_CONTAINER_INTERNAL_COMPRESSED_TUPLE_H_
#define ABSL_CONTAINER_INTERNAL_COMPRESSED_TUPLE_H_
#include <tuple>
#include <type_traits>
#include <utility>
#include "absl/utility/utility.h"
#ifdef _MSC_VER
// We need to mark these classes with this declspec to ensure that
// CompressedTuple happens.
#define ABSL_INTERNAL_COMPRESSED_TUPLE_DECLSPEC __declspec(empty_bases)
#else // _MSC_VER
#define ABSL_INTERNAL_COMPRESSED_TUPLE_DECLSPEC
#endif // _MSC_VER
namespace absl {
inline namespace lts_2018_12_18 {
namespace container_internal {
template <typename... Ts>
class CompressedTuple;
namespace internal_compressed_tuple {
template <typename D, size_t I>
struct Elem;
template <typename... B, size_t I>
struct Elem<CompressedTuple<B...>, I>
: std::tuple_element<I, std::tuple<B...>> {};
template <typename D, size_t I>
using ElemT = typename Elem<D, I>::type;
// Use the __is_final intrinsic if available. Where it's not available, classes
// declared with the 'final' specifier cannot be used as CompressedTuple
// elements.
// TODO(sbenza): Replace this with std::is_final in C++14.
template <typename T>
constexpr bool IsFinal() {
#if defined(__clang__) || defined(__GNUC__)
return __is_final(T);
#else
return false;
#endif
}
template <typename T>
constexpr bool ShouldUseBase() {
return std::is_class<T>::value && std::is_empty<T>::value && !IsFinal<T>();
}
// The storage class provides two specializations:
// - For empty classes, it stores T as a base class.
// - For everything else, it stores T as a member.
template <typename D, size_t I, bool = ShouldUseBase<ElemT<D, I>>()>
struct Storage {
using T = ElemT<D, I>;
T value;
constexpr Storage() = default;
explicit constexpr Storage(T&& v) : value(absl::forward<T>(v)) {}
constexpr const T& get() const { return value; }
T& get() { return value; }
};
template <typename D, size_t I>
struct ABSL_INTERNAL_COMPRESSED_TUPLE_DECLSPEC Storage<D, I, true>
: ElemT<D, I> {
using T = internal_compressed_tuple::ElemT<D, I>;
constexpr Storage() = default;
explicit constexpr Storage(T&& v) : T(absl::forward<T>(v)) {}
constexpr const T& get() const { return *this; }
T& get() { return *this; }
};
template <typename D, typename I>
struct ABSL_INTERNAL_COMPRESSED_TUPLE_DECLSPEC CompressedTupleImpl;
template <typename... Ts, size_t... I>
struct ABSL_INTERNAL_COMPRESSED_TUPLE_DECLSPEC
CompressedTupleImpl<CompressedTuple<Ts...>, absl::index_sequence<I...>>
// We use the dummy identity function through std::integral_constant to
// convince MSVC of accepting and expanding I in that context. Without it
// you would get:
// error C3548: 'I': parameter pack cannot be used in this context
: Storage<CompressedTuple<Ts...>,
std::integral_constant<size_t, I>::value>... {
constexpr CompressedTupleImpl() = default;
explicit constexpr CompressedTupleImpl(Ts&&... args)
: Storage<CompressedTuple<Ts...>, I>(absl::forward<Ts>(args))... {}
};
} // namespace internal_compressed_tuple
// Helper class to perform the Empty Base Class Optimization.
// Ts can contain classes and non-classes, empty or not. For the ones that
// are empty classes, we perform the CompressedTuple. If all types in Ts are
// empty classes, then CompressedTuple<Ts...> is itself an empty class.
//
// To access the members, use member .get<N>() function.
//
// Eg:
// absl::container_internal::CompressedTuple<int, T1, T2, T3> value(7, t1, t2,
// t3);
// assert(value.get<0>() == 7);
// T1& t1 = value.get<1>();
// const T2& t2 = value.get<2>();
// ...
//
// http://en.cppreference.com/w/cpp/language/ebo
template <typename... Ts>
class ABSL_INTERNAL_COMPRESSED_TUPLE_DECLSPEC CompressedTuple
: private internal_compressed_tuple::CompressedTupleImpl<
CompressedTuple<Ts...>, absl::index_sequence_for<Ts...>> {
private:
template <int I>
using ElemT = internal_compressed_tuple::ElemT<CompressedTuple, I>;
public:
constexpr CompressedTuple() = default;
explicit constexpr CompressedTuple(Ts... base)
: CompressedTuple::CompressedTupleImpl(absl::forward<Ts>(base)...) {}
template <int I>
ElemT<I>& get() {
return internal_compressed_tuple::Storage<CompressedTuple, I>::get();
}
template <int I>
constexpr const ElemT<I>& get() const {
return internal_compressed_tuple::Storage<CompressedTuple, I>::get();
}
};
// Explicit specialization for a zero-element tuple
// (needed to avoid ambiguous overloads for the default constructor).
template <>
class ABSL_INTERNAL_COMPRESSED_TUPLE_DECLSPEC CompressedTuple<> {};
} // namespace container_internal
} // inline namespace lts_2018_12_18
} // namespace absl
#undef ABSL_INTERNAL_COMPRESSED_TUPLE_DECLSPEC
#endif // ABSL_CONTAINER_INTERNAL_COMPRESSED_TUPLE_H_
// Copyright 2018 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "absl/container/internal/compressed_tuple.h"
#include <string>
#include "gmock/gmock.h"
#include "gtest/gtest.h"
namespace absl {
inline namespace lts_2018_12_18 {
namespace container_internal {
namespace {
template <int>
struct Empty {};
template <typename T>
struct NotEmpty {
T value;
};
template <typename T, typename U>
struct TwoValues {
T value1;
U value2;
};
TEST(CompressedTupleTest, Sizeof) {
EXPECT_EQ(sizeof(int), sizeof(CompressedTuple<int>));
EXPECT_EQ(sizeof(int), sizeof(CompressedTuple<int, Empty<0>>));
EXPECT_EQ(sizeof(int), sizeof(CompressedTuple<int, Empty<0>, Empty<1>>));
EXPECT_EQ(sizeof(int),
sizeof(CompressedTuple<int, Empty<0>, Empty<1>, Empty<2>>));
EXPECT_EQ(sizeof(TwoValues<int, double>),
sizeof(CompressedTuple<int, NotEmpty<double>>));
EXPECT_EQ(sizeof(TwoValues<int, double>),
sizeof(CompressedTuple<int, Empty<0>, NotEmpty<double>>));
EXPECT_EQ(sizeof(TwoValues<int, double>),
sizeof(CompressedTuple<int, Empty<0>, NotEmpty<double>, Empty<1>>));
}
TEST(CompressedTupleTest, Access) {
struct S {
std::string x;
};
CompressedTuple<int, Empty<0>, S> x(7, {}, S{"ABC"});
EXPECT_EQ(sizeof(x), sizeof(TwoValues<int, S>));
EXPECT_EQ(7, x.get<0>());
EXPECT_EQ("ABC", x.get<2>().x);
}
TEST(CompressedTupleTest, NonClasses) {
CompressedTuple<int, const char*> x(7, "ABC");
EXPECT_EQ(7, x.get<0>());
EXPECT_STREQ("ABC", x.get<1>());
}
TEST(CompressedTupleTest, MixClassAndNonClass) {
CompressedTuple<int, const char*, Empty<0>, NotEmpty<double>> x(7, "ABC", {},
{1.25});
struct Mock {
int v;
const char* p;
double d;
};
EXPECT_EQ(sizeof(x), sizeof(Mock));
EXPECT_EQ(7, x.get<0>());
EXPECT_STREQ("ABC", x.get<1>());
EXPECT_EQ(1.25, x.get<3>().value);
}
TEST(CompressedTupleTest, Nested) {
CompressedTuple<int, CompressedTuple<int>,
CompressedTuple<int, CompressedTuple<int>>>
x(1, CompressedTuple<int>(2),
CompressedTuple<int, CompressedTuple<int>>(3, CompressedTuple<int>(4)));
EXPECT_EQ(1, x.get<0>());
EXPECT_EQ(2, x.get<1>().get<0>());
EXPECT_EQ(3, x.get<2>().get<0>());
EXPECT_EQ(4, x.get<2>().get<1>().get<0>());
CompressedTuple<Empty<0>, Empty<0>,
CompressedTuple<Empty<0>, CompressedTuple<Empty<0>>>>
y;
std::set<Empty<0>*> empties{&y.get<0>(), &y.get<1>(), &y.get<2>().get<0>(),
&y.get<2>().get<1>().get<0>()};
#ifdef _MSC_VER
// MSVC has a bug where many instances of the same base class are layed out in
// the same address when using __declspec(empty_bases).
// This will be fixed in a future version of MSVC.
int expected = 1;
#else
int expected = 4;
#endif
EXPECT_EQ(expected, sizeof(y));
EXPECT_EQ(expected, empties.size());
EXPECT_EQ(sizeof(y), sizeof(Empty<0>) * empties.size());
EXPECT_EQ(4 * sizeof(char),
sizeof(CompressedTuple<CompressedTuple<char, char>,
CompressedTuple<char, char>>));
EXPECT_TRUE(
(std::is_empty<CompressedTuple<CompressedTuple<Empty<0>>,
CompressedTuple<Empty<1>>>>::value));
}
TEST(CompressedTupleTest, Reference) {
int i = 7;
std::string s = "Very long std::string that goes in the heap";
CompressedTuple<int, int&, std::string, std::string&> x(i, i, s, s);
// Sanity check. We should have not moved from `s`
EXPECT_EQ(s, "Very long std::string that goes in the heap");
EXPECT_EQ(x.get<0>(), x.get<1>());
EXPECT_NE(&x.get<0>(), &x.get<1>());
EXPECT_EQ(&x.get<1>(), &i);
EXPECT_EQ(x.get<2>(), x.get<3>());
EXPECT_NE(&x.get<2>(), &x.get<3>());
EXPECT_EQ(&x.get<3>(), &s);
}
TEST(CompressedTupleTest, NoElements) {
CompressedTuple<> x;
static_cast<void>(x); // Silence -Wunused-variable.
EXPECT_TRUE(std::is_empty<CompressedTuple<>>::value);
}
TEST(CompressedTupleTest, Constexpr) {
constexpr CompressedTuple<int, double, CompressedTuple<int>> x(
7, 1.25, CompressedTuple<int>(5));
constexpr int x0 = x.get<0>();
constexpr double x1 = x.get<1>();
constexpr int x2 = x.get<2>().get<0>();
EXPECT_EQ(x0, 7);
EXPECT_EQ(x1, 1.25);
EXPECT_EQ(x2, 5);
}
#if defined(__clang__) || defined(__GNUC__)
TEST(CompressedTupleTest, EmptyFinalClass) {
struct S final {
int f() const { return 5; }
};
CompressedTuple<S> x;
EXPECT_EQ(x.get<0>().f(), 5);
}
#endif
} // namespace
} // namespace container_internal
} // inline namespace lts_2018_12_18
} // namespace absl
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