diff --git a/CMake/AbseilHelpers.cmake b/CMake/AbseilHelpers.cmake index 6d26169..58f98c8 100644 --- a/CMake/AbseilHelpers.cmake +++ b/CMake/AbseilHelpers.cmake
@@ -16,7 +16,7 @@ include(CMakeParseArguments) include(AbseilConfigureCopts) -include(GNUInstallDirs) +include(AbseilInstallDirs) # The IDE folder for Abseil that will be used if Abseil is included in a CMake # project that sets @@ -59,7 +59,7 @@ # SRCS # "b.cc" # DEPS -# absl_internal_awesome # not "awesome"! +# absl::awesome # not "awesome" ! # PUBLIC # ) # @@ -68,7 +68,7 @@ # main_lib # ... # DEPS -# absl::fantastic_lib # since fantastic_lib is public +# absl::fantastic_lib # ) # # TODO: Implement "ALWAYSLINK" @@ -80,8 +80,12 @@ ${ARGN} ) - if (NOT ABSL_CC_LIB_TESTONLY OR ABSL_RUN_TESTS) - set(_NAME "${ABSL_CC_LIB_NAME}") + if(NOT ABSL_CC_LIB_TESTONLY OR ABSL_RUN_TESTS) + if(ABSL_ENABLE_INSTALL) + set(_NAME "${ABSL_CC_LIB_NAME}") + else() + set(_NAME "absl_${ABSL_CC_LIB_NAME}") + endif() # Check if this is a header-only library # Note that as of February 2019, many popular OS's (for example, Ubuntu @@ -93,7 +97,7 @@ list(REMOVE_ITEM ABSL_CC_SRCS "${src_file}") endif() endforeach() - if ("${ABSL_CC_SRCS}" STREQUAL "") + if("${ABSL_CC_SRCS}" STREQUAL "") set(ABSL_CC_LIB_IS_INTERFACE 1) else() set(ABSL_CC_LIB_IS_INTERFACE 0) @@ -105,13 +109,15 @@ target_include_directories(${_NAME} PUBLIC $<BUILD_INTERFACE:${ABSL_COMMON_INCLUDE_DIRS}> - $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}> + $<INSTALL_INTERFACE:${ABSL_INSTALL_INCLUDEDIR}> ) target_compile_options(${_NAME} PRIVATE ${ABSL_CC_LIB_COPTS}) target_link_libraries(${_NAME} PUBLIC ${ABSL_CC_LIB_DEPS} - PRIVATE ${ABSL_CC_LIB_LINKOPTS} + PRIVATE + ${ABSL_CC_LIB_LINKOPTS} + ${ABSL_DEFAULT_LINKOPTS} ) target_compile_definitions(${_NAME} PUBLIC ${ABSL_CC_LIB_DEFINES}) @@ -140,21 +146,24 @@ target_include_directories(${_NAME} INTERFACE $<BUILD_INTERFACE:${ABSL_COMMON_INCLUDE_DIRS}> - $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}> + $<INSTALL_INTERFACE:${ABSL_INSTALL_INCLUDEDIR}> ) target_link_libraries(${_NAME} - INTERFACE ${ABSL_CC_LIB_DEPS} ${ABSL_CC_LIB_LINKOPTS} + INTERFACE + ${ABSL_CC_LIB_DEPS} + ${ABSL_CC_LIB_LINKOPTS} + ${ABSL_DEFAULT_LINKOPTS} ) target_compile_definitions(${_NAME} INTERFACE ${ABSL_CC_LIB_DEFINES}) endif() # TODO currently we don't install googletest alongside abseil sources, so # installed abseil can't be tested. - if (NOT ABSL_CC_LIB_TESTONLY) + if(NOT ABSL_CC_LIB_TESTONLY AND ABSL_ENABLE_INSTALL) install(TARGETS ${_NAME} EXPORT ${PROJECT_NAME}Targets - RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} - LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} - ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + RUNTIME DESTINATION ${ABSL_INSTALL_BINDIR} + LIBRARY DESTINATION ${ABSL_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${ABSL_INSTALL_LIBDIR} ) endif()
diff --git a/CMake/AbseilInstallDirs.cmake b/CMake/AbseilInstallDirs.cmake new file mode 100644 index 0000000..b67272f --- /dev/null +++ b/CMake/AbseilInstallDirs.cmake
@@ -0,0 +1,20 @@ +include(GNUInstallDirs) + +# absl_VERSION is only set if we are an LTS release being installed, in which +# case it may be into a system directory and so we need to make subdirectories +# for each installed version of Abseil. This mechanism is implemented in +# Abseil's internal Copybara (https://github.com/google/copybara) workflows and +# isn't visible in the CMake buildsystem itself. + +if(absl_VERSION) + set(ABSL_SUBDIR "${PROJECT_NAME}_${PROJECT_VERSION}") + set(ABSL_INSTALL_BINDIR "${CMAKE_INSTALL_BINDIR}/${ABSL_SUBDIR}") + set(ABSL_INSTALL_CONFIGDIR "${CMAKE_INSTALL_LIBDIR}/cmake/${ABSL_SUBDIR}") + set(ABSL_INSTALL_INCLUDEDIR "${CMAKE_INSTALL_INCLUDEDIR}/{ABSL_SUBDIR}") + set(ABSL_INSTALL_LIBDIR "${CMAKE_INSTALL_LIBDIR}/${ABSL_SUBDIR}") +else() + set(ABSL_INSTALL_BINDIR "${CMAKE_INSTALL_BINDIR}") + set(ABSL_INSTALL_CONFIGDIR "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}") + set(ABSL_INSTALL_INCLUDEDIR "${CMAKE_INSTALL_INCLUDEDIR}") + set(ABSL_INSTALL_LIBDIR "${CMAKE_INSTALL_LIBDIR}") +endif() \ No newline at end of file
diff --git a/CMake/CMakeLists.txt.in b/CMake/Googletest/CMakeLists.txt.in similarity index 100% rename from CMake/CMakeLists.txt.in rename to CMake/Googletest/CMakeLists.txt.in
diff --git a/CMake/DownloadGTest.cmake b/CMake/Googletest/DownloadGTest.cmake similarity index 100% rename from CMake/DownloadGTest.cmake rename to CMake/Googletest/DownloadGTest.cmake
diff --git a/CMake/abslConfig.cmake.in b/CMake/abslConfig.cmake.in index bf8c4f6..60847fa 100644 --- a/CMake/abslConfig.cmake.in +++ b/CMake/abslConfig.cmake.in
@@ -1,5 +1,6 @@ -## absl CMake configuration file. Note that there is no corresponding -# abslConfigVersion.cmake since non-LTS Abseil isn't versioned. +# absl CMake configuration file. + +include(FindThreads) @PACKAGE_INIT@
diff --git a/CMake/install_test_project/test.sh b/CMake/install_test_project/test.sh index 3e77e79..99989b0 100755 --- a/CMake/install_test_project/test.sh +++ b/CMake/install_test_project/test.sh
@@ -24,15 +24,6 @@ # Fail on any error. Treat unset variables an error. Print commands as executed. set -euox pipefail -absl_dir=/abseil-cpp -absl_build_dir=/buildfs/absl-build -project_dir="${absl_dir}"/CMake/install_test_project -project_build_dir=/buildfs/project-build -install_dir="${project_build_dir}"/install - -mkdir -p "${absl_build_dir}" -mkdir -p "${project_build_dir}" -mkdir -p "${install_dir}" install_absl() { pushd "${absl_build_dir}" @@ -51,10 +42,41 @@ mkdir -p "${absl_build_dir}" } +lts_install="" + +while getopts ":l" lts; do + case "${lts}" in + l ) + lts_install="true" + ;; + esac +done + +absl_dir=/abseil-cpp +absl_build_dir=/buildfs/absl-build +project_dir="${absl_dir}"/CMake/install_test_project +project_build_dir=/buildfs/project-build + +mkdir -p "${absl_build_dir}" +mkdir -p "${project_build_dir}" + +if [[ "${lts_install}" ]]; then + install_dir="/usr/local" +else + install_dir="${project_build_dir}"/install +fi +mkdir -p "${install_dir}" + # Test build, install, and link against installed abseil -install_absl "${install_dir}" pushd "${project_build_dir}" -cmake "${project_dir}" -DCMAKE_PREFIX_PATH="${install_dir}" +if [[ "${lts_install}" ]]; then + install_absl + cmake "${project_dir}" +else + install_absl "${install_dir}" + cmake "${project_dir}" -DCMAKE_PREFIX_PATH="${install_dir}" +fi + cmake --build . --target simple output="$(${project_build_dir}/simple "printme" 2>&1)" @@ -64,14 +86,16 @@ exit 1 fi +popd + # Test that we haven't accidentally made absl::abslblah pushd "${install_dir}" # Starting in CMake 3.12 the default install dir is lib$bit_width -if [[ -d lib ]]; then - libdir="lib" -elif [[ -d lib64 ]]; then +if [[ -d lib64 ]]; then libdir="lib64" +elif [[ -d lib ]]; then + libdir="lib" else echo "ls *, */*, */*/*:" ls * @@ -80,7 +104,15 @@ echo "unknown lib dir" fi -if ! grep absl::strings "${libdir}"/cmake/absl/abslTargets.cmake; then +if [[ "${lts_install}" ]]; then + # LTS versions append the date of the release to the subdir. + # 9999/99/99 is the dummy date used in the local_lts workflow. + absl_subdir="absl_99999999" +else + absl_subdir="absl" +fi + +if ! grep absl::strings "${libdir}/cmake/${absl_subdir}/abslTargets.cmake"; then cat "${libdir}"/cmake/absl/abslTargets.cmake echo "CMake targets named incorrectly" exit 1 @@ -89,22 +121,24 @@ uninstall_absl popd -# Test that we warn if installed without a prefix or a system prefix -output="$(install_absl 2>&1)" -if [[ "${output}" != *"Please set CMAKE_INSTALL_PREFIX"* ]]; then - echo "Install without prefix didn't warn as expected. Output:" - echo "${output}" - exit 1 -fi -uninstall_absl +if [[ ! "${lts_install}" ]]; then + # Test that we warn if installed without a prefix or a system prefix + output="$(install_absl 2>&1)" + if [[ "${output}" != *"Please set CMAKE_INSTALL_PREFIX"* ]]; then + echo "Install without prefix didn't warn as expected. Output:" + echo "${output}" + exit 1 + fi + uninstall_absl -output="$(install_absl /usr 2>&1)" -if [[ "${output}" != *"Please set CMAKE_INSTALL_PREFIX"* ]]; then - echo "Install with /usr didn't warn as expected. Output:" - echo "${output}" - exit 1 + output="$(install_absl /usr 2>&1)" + if [[ "${output}" != *"Please set CMAKE_INSTALL_PREFIX"* ]]; then + echo "Install with /usr didn't warn as expected. Output:" + echo "${output}" + exit 1 + fi + uninstall_absl fi -uninstall_absl echo "Install test complete!" exit 0
diff --git a/CMakeLists.txt b/CMakeLists.txt index 3f4fbdc..e7587f7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt
@@ -22,13 +22,14 @@ cmake_minimum_required(VERSION 3.5) # Compiler id for Apple Clang is now AppleClang. -if (POLICY CMP0025) - cmake_policy(SET CMP0025 NEW) -endif() +cmake_policy(SET CMP0025 NEW) # if command can use IN_LIST cmake_policy(SET CMP0057 NEW) +# Project version variables are the empty std::string if version is unspecified +cmake_policy(SET CMP0048 NEW) + project(absl) # when absl is included as subproject (i.e. using add_subdirectory(abseil-cpp)) @@ -44,7 +45,7 @@ ${CMAKE_CURRENT_LIST_DIR}/absl/copts ) -include(GNUInstallDirs) +include(AbseilInstallDirs) include(CMakePackageConfigHelpers) include(AbseilHelpers) @@ -85,21 +86,11 @@ enable_testing() endif() -# We don't support system-wide installation -list(APPEND SYSTEM_INSTALL_DIRS "/usr/local" "/usr" "/opt/" "/opt/local" "c:/Program Files/${PROJECT_NAME}") -if(NOT DEFINED CMAKE_INSTALL_PREFIX OR CMAKE_INSTALL_PREFIX IN_LIST SYSTEM_INSTALL_DIRS) - message(WARNING "\ -The default and system-level install directories are unsupported except in LTS \ -releases of Abseil. Please set CMAKE_INSTALL_PREFIX to install Abseil in your \ -source or build tree directly.\ - ") -endif() - ## check targets if(BUILD_TESTING) if(${ABSL_USE_GOOGLETEST_HEAD}) - include(CMake/DownloadGTest.cmake) + include(CMake/Googletest/DownloadGTest.cmake) set(absl_gtest_src_dir ${CMAKE_BINARY_DIR}/googletest-src) set(absl_gtest_build_dir ${CMAKE_BINARY_DIR}/googletest-build) endif() @@ -118,25 +109,52 @@ add_subdirectory(absl) -# install as a subdirectory only -install(EXPORT ${PROJECT_NAME}Targets - NAMESPACE absl:: - DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}" -) +if(ABSL_ENABLE_INSTALL) + # absl:lts-remove-begin(system installation is supported for LTS releases) + # We don't support system-wide installation + list(APPEND SYSTEM_INSTALL_DIRS "/usr/local" "/usr" "/opt/" "/opt/local" "c:/Program Files/${PROJECT_NAME}") + if(NOT DEFINED CMAKE_INSTALL_PREFIX OR CMAKE_INSTALL_PREFIX IN_LIST SYSTEM_INSTALL_DIRS) + message(WARNING "\ + The default and system-level install directories are unsupported except in LTS \ + releases of Abseil. Please set CMAKE_INSTALL_PREFIX to install Abseil in your \ + source or build tree directly.\ + ") + endif() + # absl:lts-remove-end -configure_package_config_file( - CMake/abslConfig.cmake.in - "${PROJECT_BINARY_DIR}/${PROJECT_NAME}Config.cmake" - INSTALL_DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}" -) + # install as a subdirectory only + install(EXPORT ${PROJECT_NAME}Targets + NAMESPACE absl:: + DESTINATION "${ABSL_INSTALL_CONFIGDIR}" + ) -install(FILES "${PROJECT_BINARY_DIR}/${PROJECT_NAME}Config.cmake" - DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}" -) + configure_package_config_file( + CMake/abslConfig.cmake.in + "${PROJECT_BINARY_DIR}/${PROJECT_NAME}Config.cmake" + INSTALL_DESTINATION "${ABSL_INSTALL_CONFIGDIR}" + ) + install(FILES "${PROJECT_BINARY_DIR}/${PROJECT_NAME}Config.cmake" + DESTINATION "${ABSL_INSTALL_CONFIGDIR}" + ) -install(DIRECTORY absl - DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} - FILES_MATCHING - PATTERN "*.inc" - PATTERN "*.h" -) + # Abseil only has a version in LTS releases. This mechanism is accomplished + # Abseil's internal Copybara (https://github.com/google/copybara) workflows and + # isn't visible in the CMake buildsystem itself. + if(absl_VERSION) + write_basic_package_version_file( + "${PROJECT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake" + COMPATIBILITY ExactVersion + ) + + install(FILES "${PROJECT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake" + DESTINATION ${ABSL_INSTALL_CONFIGDIR} + ) + endif() # absl_VERSION + + install(DIRECTORY absl + DESTINATION ${ABSL_INSTALL_INCLUDEDIR} + FILES_MATCHING + PATTERN "*.inc" + PATTERN "*.h" + ) +endif() # ABSL_ENABLE_INSTALL
diff --git a/absl/BUILD.bazel b/absl/BUILD.bazel index 8e3c177..853330d 100644 --- a/absl/BUILD.bazel +++ b/absl/BUILD.bazel
@@ -25,13 +25,18 @@ visibility = [":__subpackages__"], ) -# following configs are based on mapping defined in: https://git.io/v5Ijz +config_setting( + name = "osx", + constraint_values = [ + "@bazel_tools//platforms:osx", + ], +) + config_setting( name = "ios", - values = { - "cpu": "darwin", - }, - visibility = [":__subpackages__"], + constraint_values = [ + "@bazel_tools//platforms:ios", + ], ) config_setting(
diff --git a/absl/algorithm/BUILD.bazel b/absl/algorithm/BUILD.bazel index 8d266db..c506f3b 100644 --- a/absl/algorithm/BUILD.bazel +++ b/absl/algorithm/BUILD.bazel
@@ -17,6 +17,7 @@ load( "//absl:copts/configure_copts.bzl", "ABSL_DEFAULT_COPTS", + "ABSL_DEFAULT_LINKOPTS", "ABSL_TEST_COPTS", ) @@ -28,6 +29,7 @@ name = "algorithm", hdrs = ["algorithm.h"], copts = ABSL_DEFAULT_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, ) cc_test( @@ -35,6 +37,7 @@ size = "small", srcs = ["algorithm_test.cc"], copts = ABSL_TEST_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, deps = [ ":algorithm", "@com_google_googletest//:gtest_main", @@ -45,6 +48,7 @@ name = "algorithm_benchmark", srcs = ["equal_benchmark.cc"], copts = ABSL_TEST_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, tags = ["benchmark"], deps = [ ":algorithm", @@ -59,6 +63,7 @@ "container.h", ], copts = ABSL_DEFAULT_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, deps = [ ":algorithm", "//absl/base:core_headers", @@ -70,6 +75,7 @@ name = "container_test", srcs = ["container_test.cc"], copts = ABSL_TEST_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, deps = [ ":container", "//absl/base",
diff --git a/absl/algorithm/CMakeLists.txt b/absl/algorithm/CMakeLists.txt index c51eb10..9fbe36f 100644 --- a/absl/algorithm/CMakeLists.txt +++ b/absl/algorithm/CMakeLists.txt
@@ -29,6 +29,8 @@ algorithm_test SRCS "algorithm_test.cc" + COPTS + ${ABSL_TEST_COPTS} DEPS absl::algorithm gmock_main @@ -53,6 +55,8 @@ container_test SRCS "container_test.cc" + COPTS + ${ABSL_TEST_COPTS} DEPS absl::algorithm_container absl::base
diff --git a/absl/base/BUILD.bazel b/absl/base/BUILD.bazel index 804f62a..9fb1d8c 100644 --- a/absl/base/BUILD.bazel +++ b/absl/base/BUILD.bazel
@@ -17,6 +17,7 @@ load( "//absl:copts/configure_copts.bzl", "ABSL_DEFAULT_COPTS", + "ABSL_DEFAULT_LINKOPTS", "ABSL_TEST_COPTS", "ABSL_EXCEPTIONS_FLAG", "ABSL_EXCEPTIONS_FLAG_LINKOPTS", @@ -40,6 +41,7 @@ "internal/spinlock_wait.h", ], copts = ABSL_DEFAULT_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, visibility = [ "//absl/base:__pkg__", ], @@ -53,6 +55,7 @@ "policy_checks.h", ], copts = ABSL_DEFAULT_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, ) cc_library( @@ -61,6 +64,7 @@ hdrs = ["dynamic_annotations.h"], copts = ABSL_DEFAULT_COPTS, defines = ["__CLANG_SUPPORT_DYN_ANNOTATION__"], + linkopts = ABSL_DEFAULT_LINKOPTS, ) cc_library( @@ -74,6 +78,7 @@ "thread_annotations.h", ], copts = ABSL_DEFAULT_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, deps = [ ":config", ], @@ -92,7 +97,7 @@ linkopts = select({ "//absl:windows": [], "//conditions:default": ["-pthread"], - }), + }) + ABSL_DEFAULT_LINKOPTS, visibility = [ "//absl:__subpackages__", ], @@ -115,6 +120,7 @@ "internal/scheduling_mode.h", ], copts = ABSL_DEFAULT_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, visibility = [ "//absl:__subpackages__", ], @@ -129,6 +135,7 @@ "internal/sysinfo.cc", "internal/thread_identity.cc", "internal/unscaledcycleclock.cc", + "log_severity.cc", ], hdrs = [ "call_once.h", @@ -149,13 +156,14 @@ linkopts = select({ "//absl:windows": [], "//conditions:default": ["-pthread"], - }), + }) + ABSL_DEFAULT_LINKOPTS, deps = [ ":base_internal", ":config", ":core_headers", ":dynamic_annotations", ":spinlock_wait", + "//absl/meta:type_traits", ], ) @@ -164,6 +172,7 @@ size = "small", srcs = ["internal/atomic_hook_test.cc"], copts = ABSL_TEST_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, deps = [ ":base", ":core_headers", @@ -178,6 +187,7 @@ "bit_cast_test.cc", ], copts = ABSL_TEST_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, deps = [ ":base", ":core_headers", @@ -190,7 +200,7 @@ srcs = ["internal/throw_delegate.cc"], hdrs = ["internal/throw_delegate.h"], copts = ABSL_DEFAULT_COPTS + ABSL_EXCEPTIONS_FLAG, - linkopts = ABSL_EXCEPTIONS_FLAG_LINKOPTS, + linkopts = ABSL_EXCEPTIONS_FLAG_LINKOPTS + ABSL_DEFAULT_LINKOPTS, visibility = [ "//absl:__subpackages__", ], @@ -204,7 +214,7 @@ name = "throw_delegate_test", srcs = ["throw_delegate_test.cc"], copts = ABSL_TEST_COPTS + ABSL_EXCEPTIONS_FLAG, - linkopts = ABSL_EXCEPTIONS_FLAG_LINKOPTS, + linkopts = ABSL_EXCEPTIONS_FLAG_LINKOPTS + ABSL_DEFAULT_LINKOPTS, deps = [ ":throw_delegate", "@com_google_googletest//:gtest_main", @@ -216,6 +226,7 @@ testonly = 1, hdrs = ["internal/exception_testing.h"], copts = ABSL_TEST_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, visibility = [ "//absl:__subpackages__", ], @@ -228,6 +239,7 @@ cc_library( name = "pretty_function", hdrs = ["internal/pretty_function.h"], + linkopts = ABSL_DEFAULT_LINKOPTS, visibility = ["//absl:__subpackages__"], ) @@ -237,7 +249,7 @@ srcs = ["internal/exception_safety_testing.cc"], hdrs = ["internal/exception_safety_testing.h"], copts = ABSL_TEST_COPTS + ABSL_EXCEPTIONS_FLAG, - linkopts = ABSL_EXCEPTIONS_FLAG_LINKOPTS, + linkopts = ABSL_EXCEPTIONS_FLAG_LINKOPTS + ABSL_DEFAULT_LINKOPTS, deps = [ ":config", ":pretty_function", @@ -253,7 +265,7 @@ name = "exception_safety_testing_test", srcs = ["exception_safety_testing_test.cc"], copts = ABSL_TEST_COPTS + ABSL_EXCEPTIONS_FLAG, - linkopts = ABSL_EXCEPTIONS_FLAG_LINKOPTS, + linkopts = ABSL_EXCEPTIONS_FLAG_LINKOPTS + ABSL_DEFAULT_LINKOPTS, deps = [ ":exception_safety_testing", "//absl/memory", @@ -271,6 +283,7 @@ "internal/inline_variable_testing.h", ], copts = ABSL_TEST_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, deps = [ ":base_internal", "@com_google_googletest//:gtest_main", @@ -282,6 +295,7 @@ size = "small", srcs = ["invoke_test.cc"], copts = ABSL_TEST_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, deps = [ ":base_internal", "//absl/memory", @@ -297,6 +311,7 @@ testonly = 1, srcs = ["spinlock_test_common.cc"], copts = ABSL_TEST_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, deps = [ ":base", ":core_headers", @@ -312,7 +327,7 @@ size = "medium", srcs = ["spinlock_test_common.cc"], copts = ABSL_TEST_COPTS, - tags = ["no_test_wasm"], + linkopts = ABSL_DEFAULT_LINKOPTS, deps = [ ":base", ":core_headers", @@ -327,6 +342,7 @@ testonly = 1, srcs = ["internal/spinlock_benchmark.cc"], copts = ABSL_TEST_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, visibility = [ "//absl/base:__pkg__", ], @@ -343,6 +359,7 @@ name = "spinlock_benchmark", testonly = 1, copts = ABSL_DEFAULT_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, visibility = ["//visibility:private"], deps = [ ":spinlock_benchmark_common", @@ -356,6 +373,7 @@ "internal/unaligned_access.h", ], copts = ABSL_DEFAULT_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, deps = [ ":config", ":core_headers", @@ -378,9 +396,7 @@ name = "config_test", srcs = ["config_test.cc"], copts = ABSL_TEST_COPTS, - tags = [ - "no_test_wasm", - ], + linkopts = ABSL_DEFAULT_LINKOPTS, deps = [ ":config", "//absl/synchronization:thread_pool", @@ -392,9 +408,7 @@ name = "call_once_test", srcs = ["call_once_test.cc"], copts = ABSL_TEST_COPTS, - tags = [ - "no_test_wasm", - ], + linkopts = ABSL_DEFAULT_LINKOPTS, deps = [ ":base", ":core_headers", @@ -407,6 +421,7 @@ name = "raw_logging_test", srcs = ["raw_logging_test.cc"], copts = ABSL_TEST_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, deps = [ ":base", "//absl/strings", @@ -419,6 +434,7 @@ size = "small", srcs = ["internal/sysinfo_test.cc"], copts = ABSL_TEST_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, deps = [ ":base", "//absl/synchronization", @@ -431,6 +447,7 @@ size = "small", srcs = ["internal/low_level_alloc_test.cc"], copts = ABSL_TEST_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, tags = ["no_test_ios_x86_64"], deps = [":malloc_internal"], ) @@ -440,9 +457,7 @@ size = "small", srcs = ["internal/thread_identity_test.cc"], copts = ABSL_TEST_COPTS, - tags = [ - "no_test_wasm", - ], + linkopts = ABSL_DEFAULT_LINKOPTS, deps = [ ":base", ":core_headers", @@ -455,6 +470,7 @@ name = "thread_identity_benchmark", srcs = ["internal/thread_identity_benchmark.cc"], copts = ABSL_TEST_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, tags = ["benchmark"], visibility = ["//visibility:private"], deps = [ @@ -467,6 +483,7 @@ cc_library( name = "bits", hdrs = ["internal/bits.h"], + linkopts = ABSL_DEFAULT_LINKOPTS, visibility = [ "//absl:__subpackages__", ], @@ -478,6 +495,7 @@ size = "small", srcs = ["internal/bits_test.cc"], copts = ABSL_TEST_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, deps = [ ":bits", "@com_google_googletest//:gtest_main", @@ -489,6 +507,7 @@ testonly = 1, srcs = ["internal/scoped_set_env.cc"], hdrs = ["internal/scoped_set_env.h"], + linkopts = ABSL_DEFAULT_LINKOPTS, visibility = [ "//absl:__subpackages__", ], @@ -500,8 +519,21 @@ size = "small", srcs = ["internal/scoped_set_env_test.cc"], copts = ABSL_TEST_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, deps = [ ":scoped_set_env", "@com_google_googletest//:gtest_main", ], ) + +cc_test( + name = "log_severity_test", + size = "small", + srcs = ["log_severity_test.cc"], + copts = ABSL_TEST_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, + deps = [ + ":base", + "@com_google_googletest//:gtest_main", + ], +)
diff --git a/absl/base/CMakeLists.txt b/absl/base/CMakeLists.txt index d8a311c..b9f35bc 100644 --- a/absl/base/CMakeLists.txt +++ b/absl/base/CMakeLists.txt
@@ -26,6 +26,8 @@ "internal/spinlock_posix.inc" "internal/spinlock_wait.cc" "internal/spinlock_win32.inc" + COPTS + ${ABSL_DEFAULT_COPTS} DEPS absl::core_headers ) @@ -88,6 +90,7 @@ absl::core_headers absl::dynamic_annotations absl::spinlock_wait + Threads::Threads ) absl_cc_library( @@ -126,6 +129,7 @@ "internal/sysinfo.cc" "internal/thread_identity.cc" "internal/unscaledcycleclock.cc" + "log_severity.cc" COPTS ${ABSL_DEFAULT_COPTS} DEPS @@ -134,6 +138,8 @@ absl::core_headers absl::dynamic_annotations absl::spinlock_wait + absl::type_traits + Threads::Threads PUBLIC ) @@ -217,6 +223,8 @@ atomic_hook_test SRCS "internal/atomic_hook_test.cc" + COPTS + ${ABSL_TEST_COPTS} DEPS absl::base absl::core_headers @@ -228,6 +236,8 @@ bit_cast_test SRCS "bit_cast_test.cc" + COPTS + ${ABSL_TEST_COPTS} DEPS absl::base absl::core_headers @@ -239,6 +249,8 @@ throw_delegate_test SRCS "throw_delegate_test.cc" + COPTS + ${ABSL_TEST_COPTS} DEPS absl::base absl::throw_delegate @@ -253,6 +265,8 @@ "inline_variable_test.cc" "inline_variable_test_a.cc" "inline_variable_test_b.cc" + COPTS + ${ABSL_TEST_COPTS} DEPS absl::base_internal gtest_main @@ -263,6 +277,8 @@ invoke_test SRCS "invoke_test.cc" + COPTS + ${ABSL_TEST_COPTS} DEPS absl::base_internal absl::memory @@ -293,6 +309,8 @@ spinlock_test SRCS "spinlock_test_common.cc" + COPTS + ${ABSL_TEST_COPTS} DEPS absl::base absl::core_headers @@ -320,6 +338,8 @@ endian_test SRCS "internal/endian_test.cc" + COPTS + ${ABSL_TEST_COPTS} DEPS absl::base absl::config @@ -332,6 +352,8 @@ config_test SRCS "config_test.cc" + COPTS + ${ABSL_TEST_COPTS} DEPS absl::config absl::synchronization @@ -343,6 +365,8 @@ call_once_test SRCS "call_once_test.cc" + COPTS + ${ABSL_TEST_COPTS} DEPS absl::base absl::core_headers @@ -355,6 +379,8 @@ raw_logging_test SRCS "raw_logging_test.cc" + COPTS + ${ABSL_TEST_COPTS} DEPS absl::base absl::strings @@ -366,6 +392,8 @@ sysinfo_test SRCS "internal/sysinfo_test.cc" + COPTS + ${ABSL_TEST_COPTS} DEPS absl::base absl::synchronization @@ -377,6 +405,8 @@ low_level_alloc_test SRCS "internal/low_level_alloc_test.cc" + COPTS + ${ABSL_TEST_COPTS} DEPS absl::malloc_internal Threads::Threads @@ -387,6 +417,8 @@ thread_identity_test SRCS "internal/thread_identity_test.cc" + COPTS + ${ABSL_TEST_COPTS} DEPS absl::base absl::core_headers @@ -411,6 +443,8 @@ bits_test SRCS "internal/bits_test.cc" + COPTS + ${ABSL_TEST_COPTS} DEPS absl::bits gtest_main @@ -434,7 +468,31 @@ scoped_set_env_test SRCS "internal/scoped_set_env_test.cc" + COPTS + ${ABSL_TEST_COPTS} DEPS absl::scoped_set_env gtest_main ) + +absl_cc_test( + NAME + cmake_thread_test + SRCS + "internal/cmake_thread_test.cc" + COPTS + ${ABSL_TEST_COPTS} + DEPS + absl::base +) + +absl_cc_test( + NAME + log_severity_test + SRCS + "log_severity_test.cc" + DEPS + absl::base + gmock + gtest_main +)
diff --git a/absl/base/casts.h b/absl/base/casts.h index 00196d2..a381c42 100644 --- a/absl/base/casts.h +++ b/absl/base/casts.h
@@ -30,28 +30,20 @@ #include "absl/base/internal/identity.h" #include "absl/base/macros.h" +#include "absl/meta/type_traits.h" namespace absl { 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> {}; + : std::integral_constant< + bool, + sizeof(Dest) == sizeof(Source) && + type_traits_internal::is_trivially_copyable<Source>::value && + type_traits_internal::is_trivially_copyable<Dest>::value && + std::is_default_constructible<Dest>::value> {}; } // namespace internal_casts
diff --git a/absl/base/dynamic_annotations.h b/absl/base/dynamic_annotations.h index ac33df9..65a54b4 100644 --- a/absl/base/dynamic_annotations.h +++ b/absl/base/dynamic_annotations.h
@@ -377,7 +377,7 @@ struct { char x[8] __attribute__ ((aligned (8))); } name #else #define ANNOTATE_CONTIGUOUS_CONTAINER(beg, end, old_mid, new_mid) -#define ADDRESS_SANITIZER_REDZONE(name) +#define ADDRESS_SANITIZER_REDZONE(name) static_assert(true, "") #endif // ADDRESS_SANITIZER /* Undefine the macros intended only in this file. */
diff --git a/absl/types/optional.cc b/absl/base/internal/cmake_thread_test.cc similarity index 65% copy from absl/types/optional.cc copy to absl/base/internal/cmake_thread_test.cc index 44ff829..f70bb24 100644 --- a/absl/types/optional.cc +++ b/absl/base/internal/cmake_thread_test.cc
@@ -1,4 +1,4 @@ -// Copyright 2017 The Abseil Authors. +// 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. @@ -12,13 +12,11 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "absl/types/optional.h" +#include <iostream> +#include "absl/base/internal/thread_identity.h" -#ifndef ABSL_HAVE_STD_OPTIONAL -namespace absl { - -nullopt_t::init_t nullopt_t::init; -extern const nullopt_t nullopt{nullopt_t::init}; - -} // namespace absl -#endif // ABSL_HAVE_STD_OPTIONAL +int main() { + auto* tid = absl::base_internal::CurrentThreadIdentityIfPresent(); + // Make sure the above call can't be optimized out + std::cout << (void*)tid << std::endl; +}
diff --git a/absl/base/internal/cycleclock.cc b/absl/base/internal/cycleclock.cc index 4b553c2..e9844b7 100644 --- a/absl/base/internal/cycleclock.cc +++ b/absl/base/internal/cycleclock.cc
@@ -55,10 +55,23 @@ static constexpr double kFrequencyScale = 1.0 / (1 << kShift); static std::atomic<CycleClockSourceFunc> cycle_clock_source; +CycleClockSourceFunc LoadCycleClockSource() { + // Optimize for the common case (no callback) by first doing a relaxed load; + // this is significantly faster on non-x86 platforms. + if (cycle_clock_source.load(std::memory_order_relaxed) == nullptr) { + return nullptr; + } + // This corresponds to the store(std::memory_order_release) in + // CycleClockSource::Register, and makes sure that any updates made prior to + // registering the callback are visible to this thread before the callback is + // invoked. + return cycle_clock_source.load(std::memory_order_acquire); +} + } // namespace int64_t CycleClock::Now() { - auto fn = cycle_clock_source.load(std::memory_order_relaxed); + auto fn = LoadCycleClockSource(); if (fn == nullptr) { return base_internal::UnscaledCycleClock::Now() >> kShift; } @@ -70,7 +83,8 @@ } void CycleClockSource::Register(CycleClockSourceFunc source) { - cycle_clock_source.store(source, std::memory_order_relaxed); + // Corresponds to the load(std::memory_order_acquire) in LoadCycleClockSource. + cycle_clock_source.store(source, std::memory_order_release); } #else
diff --git a/absl/base/internal/raw_logging.cc b/absl/base/internal/raw_logging.cc index b5a05e8..878fe6c 100644 --- a/absl/base/internal/raw_logging.cc +++ b/absl/base/internal/raw_logging.cc
@@ -36,7 +36,8 @@ // This preprocessor token is also defined in raw_io.cc. If you need to copy // this, consider moving both to config.h instead. #if defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__) || \ - defined(__Fuchsia__) || defined(__native_client__) + defined(__Fuchsia__) || defined(__native_client__) || \ + defined(__EMSCRIPTEN__) #include <unistd.h>
diff --git a/absl/base/internal/sysinfo_test.cc b/absl/base/internal/sysinfo_test.cc index 247f3d8..82bbcc2 100644 --- a/absl/base/internal/sysinfo_test.cc +++ b/absl/base/internal/sysinfo_test.cc
@@ -37,12 +37,12 @@ } TEST(SysinfoTest, NominalCPUFrequency) { -#if !(defined(__aarch64__) && defined(__linux__)) +#if !(defined(__aarch64__) && defined(__linux__)) && !defined(__EMSCRIPTEN__) EXPECT_GE(NominalCPUFrequency(), 1000.0) << "NominalCPUFrequency() did not return a reasonable value"; #else - // TODO(absl-team): Aarch64 cannot read the CPU frequency from sysfs, so we - // get back 1.0. Fix once the value is available. + // Aarch64 cannot read the CPU frequency from sysfs, so we get back 1.0. + // Emscripten does not have a sysfs to read from at all. EXPECT_EQ(NominalCPUFrequency(), 1.0) << "CPU frequency detection was fixed! Please update unittest."; #endif
diff --git a/absl/base/internal/unaligned_access.h b/absl/base/internal/unaligned_access.h index 2d66737..2cf7c1d 100644 --- a/absl/base/internal/unaligned_access.h +++ b/absl/base/internal/unaligned_access.h
@@ -25,15 +25,6 @@ // unaligned APIs // Portable handling of unaligned loads, stores, and copies. -// On some platforms, like ARM, the copy functions can be more efficient -// then a load and a store. -// -// It is possible to implement all of these these using constant-length memcpy -// calls, which is portable and will usually be inlined into simple loads and -// stores if the architecture supports it. However, such inlining usually -// happens in a pass that's quite late in compilation, which means the resulting -// loads and stores cannot participate in many other optimizations, leading to -// overall worse code. // The unaligned API is C++ only. The declarations use C++ features // (namespaces, inline) which are absent or incompatible in C. @@ -108,164 +99,8 @@ #define ABSL_INTERNAL_UNALIGNED_STORE64(_p, _val) \ (absl::base_internal::UnalignedStore64(_p, _val)) -#elif defined(UNDEFINED_BEHAVIOR_SANITIZER) - -namespace absl { -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 -} // namespace absl - -#define ABSL_INTERNAL_UNALIGNED_LOAD16(_p) \ - (absl::base_internal::UnalignedLoad16(_p)) -#define ABSL_INTERNAL_UNALIGNED_LOAD32(_p) \ - (absl::base_internal::UnalignedLoad32(_p)) -#define ABSL_INTERNAL_UNALIGNED_LOAD64(_p) \ - (absl::base_internal::UnalignedLoad64(_p)) - -#define ABSL_INTERNAL_UNALIGNED_STORE16(_p, _val) \ - (absl::base_internal::UnalignedStore16(_p, _val)) -#define ABSL_INTERNAL_UNALIGNED_STORE32(_p, _val) \ - (absl::base_internal::UnalignedStore32(_p, _val)) -#define ABSL_INTERNAL_UNALIGNED_STORE64(_p, _val) \ - (absl::base_internal::UnalignedStore64(_p, _val)) - -#elif defined(__x86_64__) || defined(_M_X64) || defined(__i386) || \ - defined(_M_IX86) || defined(__ppc__) || defined(__PPC__) || \ - defined(__ppc64__) || defined(__PPC64__) - -// x86 and x86-64 can perform unaligned loads/stores directly; -// modern PowerPC hardware can also do unaligned integer loads and stores; -// but note: the FPU still sends unaligned loads and stores to a trap handler! - -#define ABSL_INTERNAL_UNALIGNED_LOAD16(_p) \ - (*reinterpret_cast<const uint16_t *>(_p)) -#define ABSL_INTERNAL_UNALIGNED_LOAD32(_p) \ - (*reinterpret_cast<const uint32_t *>(_p)) -#define ABSL_INTERNAL_UNALIGNED_LOAD64(_p) \ - (*reinterpret_cast<const uint64_t *>(_p)) - -#define ABSL_INTERNAL_UNALIGNED_STORE16(_p, _val) \ - (*reinterpret_cast<uint16_t *>(_p) = (_val)) -#define ABSL_INTERNAL_UNALIGNED_STORE32(_p, _val) \ - (*reinterpret_cast<uint32_t *>(_p) = (_val)) -#define ABSL_INTERNAL_UNALIGNED_STORE64(_p, _val) \ - (*reinterpret_cast<uint64_t *>(_p) = (_val)) - -#elif defined(__arm__) && \ - !defined(__ARM_ARCH_5__) && \ - !defined(__ARM_ARCH_5T__) && \ - !defined(__ARM_ARCH_5TE__) && \ - !defined(__ARM_ARCH_5TEJ__) && \ - !defined(__ARM_ARCH_6__) && \ - !defined(__ARM_ARCH_6J__) && \ - !defined(__ARM_ARCH_6K__) && \ - !defined(__ARM_ARCH_6Z__) && \ - !defined(__ARM_ARCH_6ZK__) && \ - !defined(__ARM_ARCH_6T2__) - - -// ARMv7 and newer support native unaligned accesses, but only of 16-bit -// and 32-bit values (not 64-bit); older versions either raise a fatal signal, -// do an unaligned read and rotate the words around a bit, or do the reads very -// slowly (trip through kernel mode). There's no simple #define that says just -// "ARMv7 or higher", so we have to filter away all ARMv5 and ARMv6 -// sub-architectures. Newer gcc (>= 4.6) set an __ARM_FEATURE_ALIGNED #define, -// so in time, maybe we can move on to that. -// -// This is a mess, but there's not much we can do about it. -// -// To further complicate matters, only LDR instructions (single reads) are -// allowed to be unaligned, not LDRD (two reads) or LDM (many reads). Unless we -// explicitly tell the compiler that these accesses can be unaligned, it can and -// will combine accesses. On armcc, the way to signal this is done by accessing -// through the type (uint32_t __packed *), but GCC has no such attribute -// (it ignores __attribute__((packed)) on individual variables). However, -// we can tell it that a _struct_ is unaligned, which has the same effect, -// so we do that. - -namespace absl { -namespace base_internal { - -struct Unaligned16Struct { - uint16_t value; - uint8_t dummy; // To make the size non-power-of-two. -} ABSL_ATTRIBUTE_PACKED; - -struct Unaligned32Struct { - uint32_t value; - uint8_t dummy; // To make the size non-power-of-two. -} ABSL_ATTRIBUTE_PACKED; - -} // namespace base_internal -} // namespace absl - -#define ABSL_INTERNAL_UNALIGNED_LOAD16(_p) \ - ((reinterpret_cast<const ::absl::base_internal::Unaligned16Struct *>(_p)) \ - ->value) -#define ABSL_INTERNAL_UNALIGNED_LOAD32(_p) \ - ((reinterpret_cast<const ::absl::base_internal::Unaligned32Struct *>(_p)) \ - ->value) - -#define ABSL_INTERNAL_UNALIGNED_STORE16(_p, _val) \ - ((reinterpret_cast< ::absl::base_internal::Unaligned16Struct *>(_p)) \ - ->value = (_val)) -#define ABSL_INTERNAL_UNALIGNED_STORE32(_p, _val) \ - ((reinterpret_cast< ::absl::base_internal::Unaligned32Struct *>(_p)) \ - ->value = (_val)) - -namespace absl { -namespace base_internal { - -inline uint64_t UnalignedLoad64(const void *p) { - uint64_t t; - memcpy(&t, p, sizeof t); - return t; -} - -inline void UnalignedStore64(void *p, uint64_t v) { memcpy(p, &v, sizeof v); } - -} // namespace base_internal -} // namespace absl - -#define ABSL_INTERNAL_UNALIGNED_LOAD64(_p) \ - (absl::base_internal::UnalignedLoad64(_p)) -#define ABSL_INTERNAL_UNALIGNED_STORE64(_p, _val) \ - (absl::base_internal::UnalignedStore64(_p, _val)) - #else -// ABSL_INTERNAL_NEED_ALIGNED_LOADS is defined when the underlying platform -// doesn't support unaligned access. -#define ABSL_INTERNAL_NEED_ALIGNED_LOADS - -// These functions are provided for architectures that don't support -// unaligned loads and stores. - namespace absl { namespace base_internal {
diff --git a/absl/base/internal/unscaledcycleclock.h b/absl/base/internal/unscaledcycleclock.h index 58950cc..2d361e9 100644 --- a/absl/base/internal/unscaledcycleclock.h +++ b/absl/base/internal/unscaledcycleclock.h
@@ -59,7 +59,8 @@ // CycleClock that runs at atleast 1 MHz. We've found some Android // ARM64 devices where this is not the case, so we disable it by // default on Android ARM64. -#if defined(__native_client__) || TARGET_OS_IPHONE || \ +#if defined(__native_client__) || \ + (defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE) || \ (defined(__ANDROID__) && defined(__aarch64__)) #define ABSL_USE_UNSCALED_CYCLECLOCK_DEFAULT 0 #else
diff --git a/absl/types/optional.cc b/absl/base/log_severity.cc similarity index 69% rename from absl/types/optional.cc rename to absl/base/log_severity.cc index 44ff829..02a2a48 100644 --- a/absl/types/optional.cc +++ b/absl/base/log_severity.cc
@@ -12,13 +12,14 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "absl/types/optional.h" +#include "absl/base/log_severity.h" -#ifndef ABSL_HAVE_STD_OPTIONAL +#include <ostream> + namespace absl { -nullopt_t::init_t nullopt_t::init; -extern const nullopt_t nullopt{nullopt_t::init}; - +std::ostream& operator<<(std::ostream& os, absl::LogSeverity s) { + if (s == absl::NormalizeLogSeverity(s)) return os << absl::LogSeverityName(s); + return os << "absl::LogSeverity(" << static_cast<int>(s) << ")"; +} } // namespace absl -#endif // ABSL_HAVE_STD_OPTIONAL
diff --git a/absl/base/log_severity.h b/absl/base/log_severity.h index b19a7ff..5a1d557 100644 --- a/absl/base/log_severity.h +++ b/absl/base/log_severity.h
@@ -16,6 +16,7 @@ #define ABSL_BASE_INTERNAL_LOG_SEVERITY_H_ #include <array> +#include <ostream> #include "absl/base/attributes.h" @@ -61,6 +62,10 @@ return NormalizeLogSeverity(static_cast<absl::LogSeverity>(s)); } +// The exact representation of a streamed `absl::LogSeverity` is deliberately +// unspecified; do not rely on it. +std::ostream& operator<<(std::ostream& os, absl::LogSeverity s); + } // namespace absl #endif // ABSL_BASE_INTERNAL_LOG_SEVERITY_H_
diff --git a/absl/base/log_severity_test.cc b/absl/base/log_severity_test.cc new file mode 100644 index 0000000..1de2d10 --- /dev/null +++ b/absl/base/log_severity_test.cc
@@ -0,0 +1,43 @@ +// Copyright 2018 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "absl/base/log_severity.h" + +#include <sstream> +#include <string> + +#include "gmock/gmock.h" +#include "gtest/gtest.h" + +namespace { +using testing::Eq; + +std::string StreamHelper(absl::LogSeverity value) { + std::ostringstream stream; + stream << value; + return stream.str(); +} + +TEST(StreamTest, Works) { + EXPECT_THAT(StreamHelper(static_cast<absl::LogSeverity>(-100)), + Eq("absl::LogSeverity(-100)")); + EXPECT_THAT(StreamHelper(absl::LogSeverity::kInfo), Eq("INFO")); + EXPECT_THAT(StreamHelper(absl::LogSeverity::kWarning), Eq("WARNING")); + EXPECT_THAT(StreamHelper(absl::LogSeverity::kError), Eq("ERROR")); + EXPECT_THAT(StreamHelper(absl::LogSeverity::kFatal), Eq("FATAL")); + EXPECT_THAT(StreamHelper(static_cast<absl::LogSeverity>(4)), + Eq("absl::LogSeverity(4)")); +} + +} // namespace
diff --git a/absl/base/macros.h b/absl/base/macros.h index 5b43d7c..ca62079 100644 --- a/absl/base/macros.h +++ b/absl/base/macros.h
@@ -191,10 +191,11 @@ // This macro is inspired by // https://akrzemi1.wordpress.com/2017/05/18/asserts-in-constexpr-functions/ #if defined(NDEBUG) -#define ABSL_ASSERT(expr) (false ? (void)(expr) : (void)0) +#define ABSL_ASSERT(expr) \ + (false ? static_cast<void>(expr) : static_cast<void>(0)) #else -#define ABSL_ASSERT(expr) \ - (ABSL_PREDICT_TRUE((expr)) ? (void)0 \ +#define ABSL_ASSERT(expr) \ + (ABSL_PREDICT_TRUE((expr)) ? static_cast<void>(0) \ : [] { assert(false && #expr); }()) // NOLINT #endif
diff --git a/absl/container/BUILD.bazel b/absl/container/BUILD.bazel index cd914ba..f25a9ff 100644 --- a/absl/container/BUILD.bazel +++ b/absl/container/BUILD.bazel
@@ -17,6 +17,7 @@ load( "//absl:copts/configure_copts.bzl", "ABSL_DEFAULT_COPTS", + "ABSL_DEFAULT_LINKOPTS", "ABSL_EXCEPTIONS_FLAG", "ABSL_EXCEPTIONS_FLAG_LINKOPTS", "ABSL_TEST_COPTS", @@ -30,6 +31,7 @@ name = "compressed_tuple", hdrs = ["internal/compressed_tuple.h"], copts = ABSL_DEFAULT_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, deps = [ "//absl/utility", ], @@ -39,6 +41,7 @@ name = "compressed_tuple_test", srcs = ["internal/compressed_tuple_test.cc"], copts = ABSL_TEST_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, deps = [ ":compressed_tuple", "//absl/memory", @@ -51,6 +54,7 @@ name = "fixed_array", hdrs = ["fixed_array.h"], copts = ABSL_DEFAULT_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, deps = [ ":compressed_tuple", "//absl/algorithm", @@ -65,7 +69,7 @@ name = "fixed_array_test", srcs = ["fixed_array_test.cc"], copts = ABSL_TEST_COPTS + ABSL_EXCEPTIONS_FLAG, - linkopts = ABSL_EXCEPTIONS_FLAG_LINKOPTS, + linkopts = ABSL_EXCEPTIONS_FLAG_LINKOPTS + ABSL_DEFAULT_LINKOPTS, deps = [ ":fixed_array", "//absl/base:exception_testing", @@ -79,6 +83,7 @@ name = "fixed_array_test_noexceptions", srcs = ["fixed_array_test.cc"], copts = ABSL_TEST_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, deps = [ ":fixed_array", "//absl/base:exception_testing", @@ -92,7 +97,7 @@ name = "fixed_array_exception_safety_test", srcs = ["fixed_array_exception_safety_test.cc"], copts = ABSL_TEST_COPTS + ABSL_EXCEPTIONS_FLAG, - linkopts = ABSL_EXCEPTIONS_FLAG_LINKOPTS, + linkopts = ABSL_EXCEPTIONS_FLAG_LINKOPTS + ABSL_DEFAULT_LINKOPTS, deps = [ ":fixed_array", "//absl/base:exception_safety_testing", @@ -104,6 +109,7 @@ name = "fixed_array_benchmark", srcs = ["fixed_array_benchmark.cc"], copts = ABSL_TEST_COPTS + ["$(STACK_FRAME_UNLIMITED)"], + linkopts = ABSL_DEFAULT_LINKOPTS, tags = ["benchmark"], deps = [ ":fixed_array", @@ -115,7 +121,9 @@ name = "inlined_vector_internal", hdrs = ["internal/inlined_vector.h"], copts = ABSL_DEFAULT_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, deps = [ + ":compressed_tuple", "//absl/meta:type_traits", ], ) @@ -124,6 +132,7 @@ name = "inlined_vector", hdrs = ["inlined_vector.h"], copts = ABSL_DEFAULT_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, deps = [ ":inlined_vector_internal", "//absl/algorithm", @@ -138,6 +147,7 @@ testonly = 1, hdrs = ["internal/counting_allocator.h"], copts = ABSL_DEFAULT_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, visibility = ["//visibility:private"], ) @@ -145,7 +155,7 @@ name = "inlined_vector_test", srcs = ["inlined_vector_test.cc"], copts = ABSL_TEST_COPTS + ABSL_EXCEPTIONS_FLAG, - linkopts = ABSL_EXCEPTIONS_FLAG_LINKOPTS, + linkopts = ABSL_EXCEPTIONS_FLAG_LINKOPTS + ABSL_DEFAULT_LINKOPTS, deps = [ ":counting_allocator", ":inlined_vector", @@ -164,6 +174,7 @@ name = "inlined_vector_test_noexceptions", srcs = ["inlined_vector_test.cc"], copts = ABSL_TEST_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, deps = [ ":counting_allocator", ":inlined_vector", @@ -182,6 +193,7 @@ name = "inlined_vector_benchmark", srcs = ["inlined_vector_benchmark.cc"], copts = ABSL_TEST_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, tags = ["benchmark"], deps = [ ":inlined_vector", @@ -197,6 +209,7 @@ srcs = ["internal/test_instance_tracker.cc"], hdrs = ["internal/test_instance_tracker.h"], copts = ABSL_DEFAULT_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, visibility = [ "//absl:__subpackages__", ], @@ -206,6 +219,7 @@ name = "test_instance_tracker_test", srcs = ["internal/test_instance_tracker_test.cc"], copts = ABSL_TEST_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, deps = [ ":test_instance_tracker", "@com_google_googletest//:gtest_main", @@ -230,6 +244,7 @@ name = "flat_hash_map", hdrs = ["flat_hash_map.h"], copts = ABSL_DEFAULT_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, deps = [ ":container_memory", ":hash_function_defaults", @@ -243,6 +258,7 @@ name = "flat_hash_map_test", srcs = ["flat_hash_map_test.cc"], copts = ABSL_TEST_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, tags = NOTEST_TAGS_NONMOBILE, deps = [ ":flat_hash_map", @@ -260,6 +276,7 @@ name = "flat_hash_set", hdrs = ["flat_hash_set.h"], copts = ABSL_DEFAULT_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, deps = [ ":container_memory", ":hash_function_defaults", @@ -274,6 +291,7 @@ name = "flat_hash_set_test", srcs = ["flat_hash_set_test.cc"], copts = ABSL_TEST_COPTS + ["-DUNORDERED_SET_CXX17"], + linkopts = ABSL_DEFAULT_LINKOPTS, tags = NOTEST_TAGS_NONMOBILE, deps = [ ":flat_hash_set", @@ -292,6 +310,7 @@ name = "node_hash_map", hdrs = ["node_hash_map.h"], copts = ABSL_DEFAULT_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, deps = [ ":container_memory", ":hash_function_defaults", @@ -306,6 +325,7 @@ name = "node_hash_map_test", srcs = ["node_hash_map_test.cc"], copts = ABSL_TEST_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, tags = NOTEST_TAGS_NONMOBILE, deps = [ ":hash_generator_testing", @@ -323,6 +343,7 @@ name = "node_hash_set", hdrs = ["node_hash_set.h"], copts = ABSL_DEFAULT_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, deps = [ ":hash_function_defaults", ":node_hash_policy", @@ -336,6 +357,7 @@ name = "node_hash_set_test", srcs = ["node_hash_set_test.cc"], copts = ABSL_TEST_COPTS + ["-DUNORDERED_SET_CXX17"], + linkopts = ABSL_DEFAULT_LINKOPTS, tags = NOTEST_TAGS_NONMOBILE, deps = [ ":node_hash_set", @@ -351,6 +373,7 @@ name = "container_memory", hdrs = ["internal/container_memory.h"], copts = ABSL_DEFAULT_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, deps = [ "//absl/memory", "//absl/utility", @@ -361,6 +384,7 @@ name = "container_memory_test", srcs = ["internal/container_memory_test.cc"], copts = ABSL_TEST_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, tags = NOTEST_TAGS_NONMOBILE, deps = [ ":container_memory", @@ -373,6 +397,7 @@ name = "hash_function_defaults", hdrs = ["internal/hash_function_defaults.h"], copts = ABSL_DEFAULT_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, deps = [ "//absl/base:config", "//absl/hash", @@ -384,6 +409,7 @@ name = "hash_function_defaults_test", srcs = ["internal/hash_function_defaults_test.cc"], copts = ABSL_TEST_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, tags = NOTEST_TAGS, deps = [ ":hash_function_defaults", @@ -399,6 +425,7 @@ srcs = ["internal/hash_generator_testing.cc"], hdrs = ["internal/hash_generator_testing.h"], copts = ABSL_TEST_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, deps = [ ":hash_policy_testing", "//absl/meta:type_traits", @@ -411,6 +438,7 @@ testonly = 1, hdrs = ["internal/hash_policy_testing.h"], copts = ABSL_TEST_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, deps = [ "//absl/hash", "//absl/strings", @@ -421,6 +449,7 @@ name = "hash_policy_testing_test", srcs = ["internal/hash_policy_testing_test.cc"], copts = ABSL_TEST_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, deps = [ ":hash_policy_testing", "@com_google_googletest//:gtest_main", @@ -431,6 +460,7 @@ name = "hash_policy_traits", hdrs = ["internal/hash_policy_traits.h"], copts = ABSL_DEFAULT_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, deps = ["//absl/meta:type_traits"], ) @@ -438,6 +468,7 @@ name = "hash_policy_traits_test", srcs = ["internal/hash_policy_traits_test.cc"], copts = ABSL_TEST_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, deps = [ ":hash_policy_traits", "@com_google_googletest//:gtest_main", @@ -448,6 +479,7 @@ name = "hashtable_debug", hdrs = ["internal/hashtable_debug.h"], copts = ABSL_DEFAULT_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, deps = [ ":hashtable_debug_hooks", ], @@ -457,6 +489,7 @@ name = "hashtable_debug_hooks", hdrs = ["internal/hashtable_debug_hooks.h"], copts = ABSL_DEFAULT_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, ) cc_library( @@ -467,6 +500,7 @@ ], hdrs = ["internal/hashtablez_sampler.h"], copts = ABSL_DEFAULT_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, deps = [ ":have_sse", "//absl/base", @@ -481,6 +515,7 @@ cc_test( name = "hashtablez_sampler_test", srcs = ["internal/hashtablez_sampler_test.cc"], + linkopts = ABSL_DEFAULT_LINKOPTS, deps = [ ":hashtablez_sampler", ":have_sse", @@ -496,12 +531,14 @@ name = "node_hash_policy", hdrs = ["internal/node_hash_policy.h"], copts = ABSL_DEFAULT_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, ) cc_test( name = "node_hash_policy_test", srcs = ["internal/node_hash_policy_test.cc"], copts = ABSL_TEST_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, deps = [ ":hash_policy_traits", ":node_hash_policy", @@ -513,6 +550,7 @@ name = "raw_hash_map", hdrs = ["internal/raw_hash_map.h"], copts = ABSL_DEFAULT_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, deps = [ ":container_memory", ":raw_hash_set", @@ -523,6 +561,7 @@ name = "have_sse", hdrs = ["internal/have_sse.h"], copts = ABSL_DEFAULT_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, visibility = ["//visibility:private"], ) @@ -530,6 +569,7 @@ name = "common", hdrs = ["internal/common.h"], copts = ABSL_DEFAULT_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, deps = [ "//absl/meta:type_traits", "//absl/types:optional", @@ -541,6 +581,7 @@ srcs = ["internal/raw_hash_set.cc"], hdrs = ["internal/raw_hash_set.h"], copts = ABSL_DEFAULT_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, deps = [ ":common", ":compressed_tuple", @@ -584,6 +625,7 @@ size = "small", srcs = ["internal/raw_hash_set_allocator_test.cc"], copts = ABSL_TEST_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, deps = [ ":raw_hash_set", ":tracked", @@ -596,6 +638,7 @@ name = "layout", hdrs = ["internal/layout.h"], copts = ABSL_DEFAULT_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, deps = [ "//absl/base:core_headers", "//absl/meta:type_traits", @@ -610,6 +653,7 @@ size = "small", srcs = ["internal/layout_test.cc"], copts = ABSL_TEST_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, tags = NOTEST_TAGS, visibility = ["//visibility:private"], deps = [ @@ -626,6 +670,7 @@ testonly = 1, hdrs = ["internal/tracked.h"], copts = ABSL_TEST_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, ) cc_library( @@ -633,6 +678,7 @@ testonly = 1, hdrs = ["internal/unordered_map_constructor_test.h"], copts = ABSL_TEST_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, deps = [ ":hash_generator_testing", ":hash_policy_testing", @@ -645,6 +691,7 @@ testonly = 1, hdrs = ["internal/unordered_map_lookup_test.h"], copts = ABSL_TEST_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, deps = [ ":hash_generator_testing", ":hash_policy_testing", @@ -657,6 +704,7 @@ testonly = 1, hdrs = ["internal/unordered_map_modifiers_test.h"], copts = ABSL_TEST_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, deps = [ ":hash_generator_testing", ":hash_policy_testing", @@ -669,6 +717,7 @@ testonly = 1, hdrs = ["internal/unordered_set_constructor_test.h"], copts = ABSL_TEST_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, deps = [ ":hash_generator_testing", ":hash_policy_testing", @@ -682,6 +731,7 @@ testonly = 1, hdrs = ["internal/unordered_set_members_test.h"], copts = ABSL_TEST_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, deps = [ "//absl/meta:type_traits", "@com_google_googletest//:gtest", @@ -693,6 +743,7 @@ testonly = 1, hdrs = ["internal/unordered_map_members_test.h"], copts = ABSL_TEST_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, deps = [ "//absl/meta:type_traits", "@com_google_googletest//:gtest", @@ -704,6 +755,7 @@ testonly = 1, hdrs = ["internal/unordered_set_lookup_test.h"], copts = ABSL_TEST_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, deps = [ ":hash_generator_testing", ":hash_policy_testing", @@ -716,6 +768,7 @@ testonly = 1, hdrs = ["internal/unordered_set_modifiers_test.h"], copts = ABSL_TEST_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, deps = [ ":hash_generator_testing", ":hash_policy_testing", @@ -727,6 +780,7 @@ name = "unordered_set_test", srcs = ["internal/unordered_set_test.cc"], copts = ABSL_TEST_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, tags = NOTEST_TAGS_NONMOBILE, deps = [ ":unordered_set_constructor_test", @@ -741,6 +795,7 @@ name = "unordered_map_test", srcs = ["internal/unordered_map_test.cc"], copts = ABSL_TEST_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, tags = NOTEST_TAGS_NONMOBILE, deps = [ ":unordered_map_constructor_test",
diff --git a/absl/container/CMakeLists.txt b/absl/container/CMakeLists.txt index 292fea2..9531d7f 100644 --- a/absl/container/CMakeLists.txt +++ b/absl/container/CMakeLists.txt
@@ -27,7 +27,9 @@ NAME compressed_tuple HDRS - "internal/compressed_tuple.h" + "internal/compressed_tuple.h" + COPTS + ${ABSL_DEFAULT_COPTS} DEPS absl::utility PUBLIC @@ -38,6 +40,8 @@ compressed_tuple_test SRCS "internal/compressed_tuple_test.cc" + COPTS + ${ABSL_TEST_COPTS} DEPS absl::compressed_tuple absl::memory @@ -68,6 +72,7 @@ SRCS "fixed_array_test.cc" COPTS + ${ABSL_TEST_COPTS} ${ABSL_EXCEPTIONS_FLAG} LINKOPTS ${ABSL_EXCEPTIONS_FLAG_LINKOPTS} @@ -84,6 +89,8 @@ fixed_array_test_noexceptions SRCS "fixed_array_test.cc" + COPTS + ${ABSL_TEST_COPTS} DEPS absl::fixed_array absl::exception_testing @@ -98,6 +105,7 @@ SRCS "fixed_array_exception_safety_test.cc" COPTS + ${ABSL_TEST_COPTS} ${ABSL_EXCEPTIONS_FLAG} LINKOPTS ${ABSL_EXCEPTIONS_FLAG_LINKOPTS} @@ -115,6 +123,7 @@ COPTS ${ABSL_DEFAULT_COPTS} DEPS + absl::compressed_tuple absl::type_traits PUBLIC ) @@ -129,6 +138,7 @@ DEPS absl::algorithm absl::core_headers + absl::inlined_vector_internal absl::throw_delegate absl::memory PUBLIC @@ -149,6 +159,7 @@ SRCS "inlined_vector_test.cc" COPTS + ${ABSL_TEST_COPTS} ${ABSL_EXCEPTIONS_FLAG} LINKOPTS ${ABSL_EXCEPTIONS_FLAG_LINKOPTS} @@ -170,6 +181,8 @@ inlined_vector_test_noexceptions SRCS "inlined_vector_test.cc" + COPTS + ${ABSL_TEST_COPTS} DEPS absl::inlined_vector absl::test_instance_tracker @@ -199,6 +212,8 @@ test_instance_tracker_test SRCS "internal/test_instance_tracker_test.cc" + COPTS + ${ABSL_TEST_COPTS} DEPS absl::test_instance_tracker gmock_main @@ -225,6 +240,8 @@ flat_hash_map_test SRCS "flat_hash_map_test.cc" + COPTS + ${ABSL_TEST_COPTS} DEPS absl::flat_hash_map absl::hash_generator_testing @@ -259,6 +276,7 @@ SRCS "flat_hash_set_test.cc" COPTS + ${ABSL_TEST_COPTS} "-DUNORDERED_SET_CXX17" DEPS absl::flat_hash_set @@ -294,6 +312,8 @@ node_hash_map_test SRCS "node_hash_map_test.cc" + COPTS + ${ABSL_TEST_COPTS} DEPS absl::hash_generator_testing absl::node_hash_map @@ -327,6 +347,7 @@ SRCS "node_hash_set_test.cc" COPTS + ${ABSL_TEST_COPTS} "-DUNORDERED_SET_CXX17" DEPS absl::hash_generator_testing @@ -356,6 +377,8 @@ container_memory_test SRCS "internal/container_memory_test.cc" + COPTS + ${ABSL_TEST_COPTS} DEPS absl::container_memory absl::strings @@ -381,6 +404,8 @@ hash_function_defaults_test SRCS "internal/hash_function_defaults_test.cc" + COPTS + ${ABSL_TEST_COPTS} DEPS absl::hash_function_defaults absl::hash @@ -422,6 +447,8 @@ hash_policy_testing_test SRCS "internal/hash_policy_testing_test.cc" + COPTS + ${ABSL_TEST_COPTS} DEPS absl::hash_policy_testing gmock_main @@ -444,6 +471,8 @@ hash_policy_traits_test SRCS "internal/hash_policy_traits_test.cc" + COPTS + ${ABSL_TEST_COPTS} DEPS absl::hash_policy_traits gmock_main @@ -470,6 +499,8 @@ hashtablez_sampler_test SRCS "internal/hashtablez_sampler_test.cc" + COPTS + ${ABSL_TEST_COPTS} DEPS absl::hashtablez_sampler absl::have_sse @@ -521,6 +552,8 @@ node_hash_policy_test SRCS "internal/node_hash_policy_test.cc" + COPTS + ${ABSL_TEST_COPTS} DEPS absl::hash_policy_traits absl::node_hash_policy @@ -585,6 +618,8 @@ raw_hash_set_test SRCS "internal/raw_hash_set_test.cc" + COPTS + ${ABSL_TEST_COPTS} DEPS absl::container_memory absl::hash_function_defaults @@ -602,6 +637,8 @@ raw_hash_set_allocator_test SRCS "internal/raw_hash_set_allocator_test.cc" + COPTS + ${ABSL_TEST_COPTS} DEPS absl::raw_hash_set absl::tracked @@ -630,6 +667,8 @@ layout_test SRCS "internal/layout_test.cc" + COPTS + ${ABSL_TEST_COPTS} DEPS absl::layout absl::base @@ -763,6 +802,8 @@ unordered_set_test SRCS "internal/unordered_set_test.cc" + COPTS + ${ABSL_TEST_COPTS} DEPS absl::unordered_set_constructor_test absl::unordered_set_lookup_test @@ -776,6 +817,8 @@ unordered_map_test SRCS "internal/unordered_map_test.cc" + COPTS + ${ABSL_TEST_COPTS} DEPS absl::unordered_map_constructor_test absl::unordered_map_lookup_test
diff --git a/absl/container/inlined_vector.h b/absl/container/inlined_vector.h index 7798805..34e9aa0 100644 --- a/absl/container/inlined_vector.h +++ b/absl/container/inlined_vector.h
@@ -70,22 +70,15 @@ N > 0, "InlinedVector cannot be instantiated with `0` inlined elements."); using Storage = inlined_vector_internal::Storage<InlinedVector>; - using Tag = typename Storage::Tag; - using AllocatorAndTag = typename Storage::AllocatorAndTag; - using Allocation = typename Storage::Allocation; + using AllocatorTraits = typename Storage::AllocatorTraits; template <typename Iterator> - using IsAtLeastForwardIterator = std::is_convertible< - typename std::iterator_traits<Iterator>::iterator_category, - std::forward_iterator_tag>; + using EnableIfAtLeastForwardIterator = absl::enable_if_t< + inlined_vector_internal::IsAtLeastForwardIterator<Iterator>::value>; template <typename Iterator> - using EnableIfAtLeastForwardIterator = - absl::enable_if_t<IsAtLeastForwardIterator<Iterator>::value>; - - template <typename Iterator> - using DisableIfAtLeastForwardIterator = - absl::enable_if_t<!IsAtLeastForwardIterator<Iterator>::value>; + using DisableIfAtLeastForwardIterator = absl::enable_if_t< + !inlined_vector_internal::IsAtLeastForwardIterator<Iterator>::value>; using rvalue_reference = typename Storage::rvalue_reference; @@ -162,27 +155,28 @@ // Creates a copy of an `other` inlined vector using `other`'s allocator. InlinedVector(const InlinedVector& other) - : InlinedVector(other, other.allocator()) {} + : InlinedVector(other, other.storage_.GetAllocator()) {} // Creates a copy of an `other` inlined vector using a specified allocator. InlinedVector(const InlinedVector& other, const allocator_type& alloc) : storage_(alloc) { reserve(other.size()); - if (allocated()) { - UninitializedCopy(other.begin(), other.end(), allocated_space()); - tag().set_allocated_size(other.size()); + if (storage_.GetIsAllocated()) { + UninitializedCopy(other.begin(), other.end(), + storage_.GetAllocatedData()); + storage_.SetAllocatedSize(other.size()); } else { - UninitializedCopy(other.begin(), other.end(), inlined_space()); - tag().set_inline_size(other.size()); + UninitializedCopy(other.begin(), other.end(), storage_.GetInlinedData()); + storage_.SetInlinedSize(other.size()); } } // Creates an inlined vector by moving in the contents of an `other` inlined // vector without performing any allocations. If `other` contains allocated // memory, the newly-created instance will take ownership of that memory - // (leaving `other` itself empty). However, if `other` does not contain any - // allocated memory, the new inlined vector will will perform element-wise - // move construction of `other`s elements. + // (leaving `other` empty). However, if `other` does not contain allocated + // memory (i.e. is inlined), the new inlined vector will perform element-wise + // move construction of `other`'s elements. // // NOTE: since no allocation is performed for the inlined vector in either // case, the `noexcept(...)` specification depends on whether moving the @@ -195,19 +189,21 @@ InlinedVector(InlinedVector&& other) noexcept( absl::allocator_is_nothrow<allocator_type>::value || std::is_nothrow_move_constructible<value_type>::value) - : storage_(other.allocator()) { - if (other.allocated()) { + : storage_(other.storage_.GetAllocator()) { + if (other.storage_.GetIsAllocated()) { // We can just steal the underlying buffer from the source. // That leaves the source empty, so we clear its size. - init_allocation(other.allocation()); - tag().set_allocated_size(other.size()); - other.tag() = Tag(); + storage_.SetAllocatedData(other.storage_.GetAllocatedData()); + storage_.SetAllocatedCapacity(other.storage_.GetAllocatedCapacity()); + storage_.SetAllocatedSize(other.size()); + other.storage_.SetInlinedSize(0); } else { UninitializedCopy( - std::make_move_iterator(other.inlined_space()), - std::make_move_iterator(other.inlined_space() + other.size()), - inlined_space()); - tag().set_inline_size(other.size()); + std::make_move_iterator(other.storage_.GetInlinedData()), + std::make_move_iterator(other.storage_.GetInlinedData() + + other.size()), + storage_.GetInlinedData()); + storage_.SetInlinedSize(other.size()); } } @@ -227,26 +223,28 @@ InlinedVector(InlinedVector&& other, const allocator_type& alloc) noexcept( absl::allocator_is_nothrow<allocator_type>::value) : storage_(alloc) { - if (other.allocated()) { - if (alloc == other.allocator()) { + if (other.storage_.GetIsAllocated()) { + if (alloc == other.storage_.GetAllocator()) { // We can just steal the allocation from the source. - tag() = other.tag(); - init_allocation(other.allocation()); - other.tag() = Tag(); + storage_.SetAllocatedSize(other.size()); + storage_.SetAllocatedData(other.storage_.GetAllocatedData()); + storage_.SetAllocatedCapacity(other.storage_.GetAllocatedCapacity()); + other.storage_.SetInlinedSize(0); } else { // We need to use our own allocator reserve(other.size()); UninitializedCopy(std::make_move_iterator(other.begin()), std::make_move_iterator(other.end()), - allocated_space()); - tag().set_allocated_size(other.size()); + storage_.GetAllocatedData()); + storage_.SetAllocatedSize(other.size()); } } else { UninitializedCopy( - std::make_move_iterator(other.inlined_space()), - std::make_move_iterator(other.inlined_space() + other.size()), - inlined_space()); - tag().set_inline_size(other.size()); + std::make_move_iterator(other.storage_.GetInlinedData()), + std::make_move_iterator(other.storage_.GetInlinedData() + + other.size()), + storage_.GetInlinedData()); + storage_.SetInlinedSize(other.size()); } } @@ -264,7 +262,7 @@ // `InlinedVector::size()` // // Returns the number of elements in the inlined vector. - size_type size() const noexcept { return tag().size(); } + size_type size() const noexcept { return storage_.GetSize(); } // `InlinedVector::max_size()` // @@ -286,7 +284,8 @@ // will no longer be inlined and `capacity()` will equal its capacity on the // allocated heap. size_type capacity() const noexcept { - return allocated() ? allocation().capacity() : static_cast<size_type>(N); + return storage_.GetIsAllocated() ? storage_.GetAllocatedCapacity() + : static_cast<size_type>(N); } // `InlinedVector::data()` @@ -295,14 +294,16 @@ // used to access and modify the contained elements. // Only results within the range [`0`, `size()`) are defined. pointer data() noexcept { - return allocated() ? allocated_space() : inlined_space(); + return storage_.GetIsAllocated() ? storage_.GetAllocatedData() + : storage_.GetInlinedData(); } // Overload of `InlinedVector::data()` to return a `const_pointer` to elements // of the inlined vector. This pointer can be used to access (but not modify) // the contained elements. const_pointer data() const noexcept { - return allocated() ? allocated_space() : inlined_space(); + return storage_.GetIsAllocated() ? storage_.GetAllocatedData() + : storage_.GetInlinedData(); } // `InlinedVector::operator[]()` @@ -436,7 +437,7 @@ // `InlinedVector::get_allocator()` // // Returns a copy of the allocator of the inlined vector. - allocator_type get_allocator() const { return allocator(); } + allocator_type get_allocator() const { return storage_.GetAllocator(); } // --------------------------------------------------------------------------- // InlinedVector Member Mutators @@ -454,7 +455,7 @@ // Overload of `InlinedVector::operator=()` to replace the contents of the // inlined vector with the contents of `other`. InlinedVector& operator=(const InlinedVector& other) { - if (ABSL_PREDICT_FALSE(this == &other)) return *this; + if (ABSL_PREDICT_FALSE(this == std::addressof(other))) return *this; // Optimized to avoid reallocation. // Prefer reassignment to copy construction for elements. @@ -475,15 +476,16 @@ // NOTE: As a result of calling this overload, `other` may be empty or it's // contents may be left in a moved-from state. InlinedVector& operator=(InlinedVector&& other) { - if (ABSL_PREDICT_FALSE(this == &other)) return *this; + if (ABSL_PREDICT_FALSE(this == std::addressof(other))) return *this; - if (other.allocated()) { + if (other.storage_.GetIsAllocated()) { clear(); - tag().set_allocated_size(other.size()); - init_allocation(other.allocation()); - other.tag() = Tag(); + storage_.SetAllocatedSize(other.size()); + storage_.SetAllocatedData(other.storage_.GetAllocatedData()); + storage_.SetAllocatedCapacity(other.storage_.GetAllocatedCapacity()); + other.storage_.SetInlinedSize(0); } else { - if (allocated()) clear(); + if (storage_.GetIsAllocated()) clear(); // Both are inlined now. if (size() < other.size()) { auto mid = std::make_move_iterator(other.begin() + size()); @@ -494,7 +496,7 @@ std::make_move_iterator(other.end()), begin()); Destroy(new_end, end()); } - tag().set_inline_size(other.size()); + storage_.SetInlinedSize(other.size()); } return *this; } @@ -511,12 +513,14 @@ // Grow reserve(n); std::fill_n(begin(), size(), v); - if (allocated()) { - UninitializedFill(allocated_space() + size(), allocated_space() + n, v); - tag().set_allocated_size(n); + if (storage_.GetIsAllocated()) { + UninitializedFill(storage_.GetAllocatedData() + size(), + storage_.GetAllocatedData() + n, v); + storage_.SetAllocatedSize(n); } else { - UninitializedFill(inlined_space() + size(), inlined_space() + n, v); - tag().set_inline_size(n); + UninitializedFill(storage_.GetInlinedData() + size(), + storage_.GetInlinedData() + n, v); + storage_.SetInlinedSize(n); } } @@ -564,12 +568,14 @@ assert(capacity() >= n); // Fill new space with elements constructed in-place. - if (allocated()) { - UninitializedFill(allocated_space() + s, allocated_space() + n); - tag().set_allocated_size(n); + if (storage_.GetIsAllocated()) { + UninitializedFill(storage_.GetAllocatedData() + s, + storage_.GetAllocatedData() + n); + storage_.SetAllocatedSize(n); } else { - UninitializedFill(inlined_space() + s, inlined_space() + n); - tag().set_inline_size(n); + UninitializedFill(storage_.GetInlinedData() + s, + storage_.GetInlinedData() + n); + storage_.SetInlinedSize(n); } } @@ -586,12 +592,14 @@ assert(capacity() >= n); // Fill new space with copies of `v`. - if (allocated()) { - UninitializedFill(allocated_space() + s, allocated_space() + n, v); - tag().set_allocated_size(n); + if (storage_.GetIsAllocated()) { + UninitializedFill(storage_.GetAllocatedData() + s, + storage_.GetAllocatedData() + n, v); + storage_.SetAllocatedSize(n); } else { - UninitializedFill(inlined_space() + s, inlined_space() + n, v); - tag().set_inline_size(n); + UninitializedFill(storage_.GetInlinedData() + s, + storage_.GetInlinedData() + n, v); + storage_.SetInlinedSize(n); } } @@ -688,12 +696,12 @@ return GrowAndEmplaceBack(std::forward<Args>(args)...); } pointer space; - if (allocated()) { - tag().set_allocated_size(s + 1); - space = allocated_space(); + if (storage_.GetIsAllocated()) { + storage_.SetAllocatedSize(s + 1); + space = storage_.GetAllocatedData(); } else { - tag().set_inline_size(s + 1); - space = inlined_space(); + storage_.SetInlinedSize(s + 1); + space = storage_.GetInlinedData(); } return Construct(space + s, std::forward<Args>(args)...); } @@ -716,12 +724,13 @@ void pop_back() noexcept { assert(!empty()); size_type s = size(); - if (allocated()) { - Destroy(allocated_space() + s - 1, allocated_space() + s); - tag().set_allocated_size(s - 1); + if (storage_.GetIsAllocated()) { + Destroy(storage_.GetAllocatedData() + s - 1, + storage_.GetAllocatedData() + s); + storage_.SetAllocatedSize(s - 1); } else { - Destroy(inlined_space() + s - 1, inlined_space() + s); - tag().set_inline_size(s - 1); + Destroy(storage_.GetInlinedData() + s - 1, storage_.GetInlinedData() + s); + storage_.SetInlinedSize(s - 1); } } @@ -757,12 +766,12 @@ ptrdiff_t erase_gap = std::distance(range_start, range_end); if (erase_gap > 0) { pointer space; - if (allocated()) { - space = allocated_space(); - tag().set_allocated_size(s - erase_gap); + if (storage_.GetIsAllocated()) { + space = storage_.GetAllocatedData(); + storage_.SetAllocatedSize(s - erase_gap); } else { - space = inlined_space(); - tag().set_inline_size(s - erase_gap); + space = storage_.GetInlinedData(); + storage_.SetInlinedSize(s - erase_gap); } std::move(range_end, space + s, range_start); Destroy(space + s - erase_gap, space + s); @@ -776,13 +785,15 @@ // deallocates the heap allocation if the inlined vector was allocated. void clear() noexcept { size_type s = size(); - if (allocated()) { - Destroy(allocated_space(), allocated_space() + s); - allocation().Dealloc(allocator()); + if (storage_.GetIsAllocated()) { + Destroy(storage_.GetAllocatedData(), storage_.GetAllocatedData() + s); + AllocatorTraits::deallocate(storage_.GetAllocator(), + storage_.GetAllocatedData(), + storage_.GetAllocatedCapacity()); } else if (s != 0) { // do nothing for empty vectors - Destroy(inlined_space(), inlined_space() + s); + Destroy(storage_.GetInlinedData(), storage_.GetInlinedData() + s); } - tag() = Tag(); + storage_.SetInlinedSize(0); } // `InlinedVector::reserve()` @@ -814,7 +825,8 @@ // smaller heap allocation. void shrink_to_fit() { const auto s = size(); - if (ABSL_PREDICT_FALSE(!allocated() || s == capacity())) return; + if (ABSL_PREDICT_FALSE(!storage_.GetIsAllocated() || s == capacity())) + return; if (s <= N) { // Move the elements to the inlined storage. @@ -829,86 +841,48 @@ // Reallocate storage and move elements. // We can't simply use the same approach as above, because `assign()` would // call into `reserve()` internally and reserve larger capacity than we need - Allocation new_allocation(allocator(), s); - UninitializedCopy(std::make_move_iterator(allocated_space()), - std::make_move_iterator(allocated_space() + s), - new_allocation.buffer()); - ResetAllocation(new_allocation, s); + pointer new_data = AllocatorTraits::allocate(storage_.GetAllocator(), s); + UninitializedCopy(std::make_move_iterator(storage_.GetAllocatedData()), + std::make_move_iterator(storage_.GetAllocatedData() + s), + new_data); + ResetAllocation(new_data, s, s); } // `InlinedVector::swap()` // // Swaps the contents of this inlined vector with the contents of `other`. void swap(InlinedVector& other) { - if (ABSL_PREDICT_FALSE(this == &other)) return; + if (ABSL_PREDICT_FALSE(this == std::addressof(other))) return; SwapImpl(other); } private: template <typename H, typename TheT, size_t TheN, typename TheA> - friend auto AbslHashValue(H h, const InlinedVector<TheT, TheN, TheA>& v) -> H; + friend H AbslHashValue(H h, const absl::InlinedVector<TheT, TheN, TheA>& a); - const Tag& tag() const { return storage_.allocator_and_tag_.tag(); } - - Tag& tag() { return storage_.allocator_and_tag_.tag(); } - - Allocation& allocation() { - return reinterpret_cast<Allocation&>( - storage_.rep_.allocation_storage.allocation); - } - - const Allocation& allocation() const { - return reinterpret_cast<const Allocation&>( - storage_.rep_.allocation_storage.allocation); - } - - void init_allocation(const Allocation& allocation) { - new (&storage_.rep_.allocation_storage.allocation) Allocation(allocation); - } - - // TODO(absl-team): investigate whether the reinterpret_cast is appropriate. - pointer inlined_space() { - return reinterpret_cast<pointer>( - std::addressof(storage_.rep_.inlined_storage.inlined[0])); - } - - const_pointer inlined_space() const { - return reinterpret_cast<const_pointer>( - std::addressof(storage_.rep_.inlined_storage.inlined[0])); - } - - pointer allocated_space() { return allocation().buffer(); } - - const_pointer allocated_space() const { return allocation().buffer(); } - - const allocator_type& allocator() const { - return storage_.allocator_and_tag_.allocator(); - } - - allocator_type& allocator() { - return storage_.allocator_and_tag_.allocator(); - } - - bool allocated() const { return tag().allocated(); } - - void ResetAllocation(Allocation new_allocation, size_type new_size) { - if (allocated()) { - Destroy(allocated_space(), allocated_space() + size()); - assert(begin() == allocated_space()); - allocation().Dealloc(allocator()); - allocation() = new_allocation; + void ResetAllocation(pointer new_data, size_type new_capacity, + size_type new_size) { + if (storage_.GetIsAllocated()) { + Destroy(storage_.GetAllocatedData(), + storage_.GetAllocatedData() + size()); + assert(begin() == storage_.GetAllocatedData()); + AllocatorTraits::deallocate(storage_.GetAllocator(), + storage_.GetAllocatedData(), + storage_.GetAllocatedCapacity()); } else { - Destroy(inlined_space(), inlined_space() + size()); - init_allocation(new_allocation); // bug: only init once + Destroy(storage_.GetInlinedData(), storage_.GetInlinedData() + size()); } - tag().set_allocated_size(new_size); + + storage_.SetAllocatedData(new_data); + storage_.SetAllocatedCapacity(new_capacity); + storage_.SetAllocatedSize(new_size); } template <typename... Args> reference Construct(pointer p, Args&&... args) { std::allocator_traits<allocator_type>::construct( - allocator(), p, std::forward<Args>(args)...); + storage_.GetAllocator(), p, std::forward<Args>(args)...); return *p; } @@ -925,7 +899,8 @@ // Destroy [`from`, `to`) in place. void Destroy(pointer from, pointer to) { for (pointer cur = from; cur != to; ++cur) { - std::allocator_traits<allocator_type>::destroy(allocator(), cur); + std::allocator_traits<allocator_type>::destroy(storage_.GetAllocator(), + cur); } #if !defined(NDEBUG) // Overwrite unused memory with `0xab` so we can catch uninitialized usage. @@ -945,7 +920,7 @@ const size_type s = size(); assert(s <= capacity()); - size_type target = (std::max)(N, s + delta); + size_type target = (std::max)(static_cast<size_type>(N), s + delta); // Compute new capacity by repeatedly doubling current capacity // TODO(psrc): Check and avoid overflow? @@ -954,13 +929,13 @@ new_capacity <<= 1; } - Allocation new_allocation(allocator(), new_capacity); + pointer new_data = + AllocatorTraits::allocate(storage_.GetAllocator(), new_capacity); UninitializedCopy(std::make_move_iterator(data()), - std::make_move_iterator(data() + s), - new_allocation.buffer()); + std::make_move_iterator(data() + s), new_data); - ResetAllocation(new_allocation, s); + ResetAllocation(new_data, new_capacity, s); } // Shift all elements from `position` to `end()` by `n` places to the right. @@ -986,15 +961,15 @@ } // Move everyone into the new allocation, leaving a gap of `n` for the // requested shift. - Allocation new_allocation(allocator(), new_capacity); + pointer new_data = + AllocatorTraits::allocate(storage_.GetAllocator(), new_capacity); size_type index = position - begin(); UninitializedCopy(std::make_move_iterator(data()), - std::make_move_iterator(data() + index), - new_allocation.buffer()); + std::make_move_iterator(data() + index), new_data); UninitializedCopy(std::make_move_iterator(data() + index), std::make_move_iterator(data() + s), - new_allocation.buffer() + index + n); - ResetAllocation(new_allocation, s); + new_data + index + n); + ResetAllocation(new_data, new_capacity, s); // New allocation means our iterator is invalid, so we'll recalculate. // Since the entire gap is in new space, there's no used space to reuse. @@ -1025,7 +1000,7 @@ start_used = pos; start_raw = pos + new_elements_in_used_space; } - tag().add_size(n); + storage_.AddSize(n); return std::make_pair(start_used, start_raw); } @@ -1034,46 +1009,55 @@ assert(size() == capacity()); const size_type s = size(); - Allocation new_allocation(allocator(), 2 * capacity()); + size_type new_capacity = 2 * capacity(); + pointer new_data = + AllocatorTraits::allocate(storage_.GetAllocator(), new_capacity); reference new_element = - Construct(new_allocation.buffer() + s, std::forward<Args>(args)...); + Construct(new_data + s, std::forward<Args>(args)...); UninitializedCopy(std::make_move_iterator(data()), - std::make_move_iterator(data() + s), - new_allocation.buffer()); + std::make_move_iterator(data() + s), new_data); - ResetAllocation(new_allocation, s + 1); + ResetAllocation(new_data, new_capacity, s + 1); return new_element; } void InitAssign(size_type n) { - if (n > N) { - Allocation new_allocation(allocator(), n); - init_allocation(new_allocation); - UninitializedFill(allocated_space(), allocated_space() + n); - tag().set_allocated_size(n); + if (n > static_cast<size_type>(N)) { + pointer new_data = AllocatorTraits::allocate(storage_.GetAllocator(), n); + storage_.SetAllocatedData(new_data); + storage_.SetAllocatedCapacity(n); + UninitializedFill(storage_.GetAllocatedData(), + storage_.GetAllocatedData() + n); + storage_.SetAllocatedSize(n); } else { - UninitializedFill(inlined_space(), inlined_space() + n); - tag().set_inline_size(n); + UninitializedFill(storage_.GetInlinedData(), + storage_.GetInlinedData() + n); + storage_.SetInlinedSize(n); } } void InitAssign(size_type n, const_reference v) { - if (n > N) { - Allocation new_allocation(allocator(), n); - init_allocation(new_allocation); - UninitializedFill(allocated_space(), allocated_space() + n, v); - tag().set_allocated_size(n); + if (n > static_cast<size_type>(N)) { + pointer new_data = AllocatorTraits::allocate(storage_.GetAllocator(), n); + storage_.SetAllocatedData(new_data); + storage_.SetAllocatedCapacity(n); + UninitializedFill(storage_.GetAllocatedData(), + storage_.GetAllocatedData() + n, v); + storage_.SetAllocatedSize(n); } else { - UninitializedFill(inlined_space(), inlined_space() + n, v); - tag().set_inline_size(n); + UninitializedFill(storage_.GetInlinedData(), + storage_.GetInlinedData() + n, v); + storage_.SetInlinedSize(n); } } template <typename ForwardIt> void AssignForwardRange(ForwardIt first, ForwardIt last) { - static_assert(IsAtLeastForwardIterator<ForwardIt>::value, ""); + static_assert(absl::inlined_vector_internal::IsAtLeastForwardIterator< + ForwardIt>::value, + ""); auto length = std::distance(first, last); @@ -1086,27 +1070,29 @@ reserve(length); iterator out = begin(); for (; out != end(); ++first, ++out) *out = *first; - if (allocated()) { + if (storage_.GetIsAllocated()) { UninitializedCopy(first, last, out); - tag().set_allocated_size(length); + storage_.SetAllocatedSize(length); } else { UninitializedCopy(first, last, out); - tag().set_inline_size(length); + storage_.SetInlinedSize(length); } } template <typename ForwardIt> void AppendForwardRange(ForwardIt first, ForwardIt last) { - static_assert(IsAtLeastForwardIterator<ForwardIt>::value, ""); + static_assert(absl::inlined_vector_internal::IsAtLeastForwardIterator< + ForwardIt>::value, + ""); auto length = std::distance(first, last); reserve(size() + length); - if (allocated()) { - UninitializedCopy(first, last, allocated_space() + size()); - tag().set_allocated_size(size() + length); + if (storage_.GetIsAllocated()) { + UninitializedCopy(first, last, storage_.GetAllocatedData() + size()); + storage_.SetAllocatedSize(size() + length); } else { - UninitializedCopy(first, last, inlined_space() + size()); - tag().set_inline_size(size() + length); + UninitializedCopy(first, last, storage_.GetInlinedData() + size()); + storage_.SetInlinedSize(size() + length); } } @@ -1126,7 +1112,9 @@ template <typename ForwardIt> iterator InsertWithForwardRange(const_iterator position, ForwardIt first, ForwardIt last) { - static_assert(IsAtLeastForwardIterator<ForwardIt>::value, ""); + static_assert(absl::inlined_vector_internal::IsAtLeastForwardIterator< + ForwardIt>::value, + ""); assert(position >= begin() && position <= end()); if (ABSL_PREDICT_FALSE(first == last)) @@ -1142,19 +1130,24 @@ } void SwapImpl(InlinedVector& other) { - using std::swap; // Augment ADL with `std::swap`. + using std::swap; - if (allocated() && other.allocated()) { + bool is_allocated = storage_.GetIsAllocated(); + bool other_is_allocated = other.storage_.GetIsAllocated(); + + if (is_allocated && other_is_allocated) { // Both out of line, so just swap the tag, allocation, and allocator. - swap(tag(), other.tag()); - swap(allocation(), other.allocation()); - swap(allocator(), other.allocator()); + storage_.SwapSizeAndIsAllocated(std::addressof(other.storage_)); + storage_.SwapAllocatedSizeAndCapacity(std::addressof(other.storage_)); + swap(storage_.GetAllocator(), other.storage_.GetAllocator()); + return; } - if (!allocated() && !other.allocated()) { + + if (!is_allocated && !other_is_allocated) { // Both inlined: swap up to smaller size, then move remaining elements. InlinedVector* a = this; - InlinedVector* b = &other; + InlinedVector* b = std::addressof(other); if (size() < other.size()) { swap(a, b); } @@ -1163,18 +1156,21 @@ const size_type b_size = b->size(); assert(a_size >= b_size); // `a` is larger. Swap the elements up to the smaller array size. - std::swap_ranges(a->inlined_space(), a->inlined_space() + b_size, - b->inlined_space()); + std::swap_ranges(a->storage_.GetInlinedData(), + a->storage_.GetInlinedData() + b_size, + b->storage_.GetInlinedData()); // Move the remaining elements: // [`b_size`, `a_size`) from `a` -> [`b_size`, `a_size`) from `b` - b->UninitializedCopy(a->inlined_space() + b_size, - a->inlined_space() + a_size, - b->inlined_space() + b_size); - a->Destroy(a->inlined_space() + b_size, a->inlined_space() + a_size); + b->UninitializedCopy(a->storage_.GetInlinedData() + b_size, + a->storage_.GetInlinedData() + a_size, + b->storage_.GetInlinedData() + b_size); + a->Destroy(a->storage_.GetInlinedData() + b_size, + a->storage_.GetInlinedData() + a_size); - swap(a->tag(), b->tag()); - swap(a->allocator(), b->allocator()); + storage_.SwapSizeAndIsAllocated(std::addressof(other.storage_)); + swap(storage_.GetAllocator(), other.storage_.GetAllocator()); + assert(b->size() == a_size); assert(a->size() == b_size); return; @@ -1186,32 +1182,37 @@ // pointer/capacity into the originally inlined vector and swap // the tags. InlinedVector* a = this; - InlinedVector* b = &other; - if (a->allocated()) { + InlinedVector* b = std::addressof(other); + if (a->storage_.GetIsAllocated()) { swap(a, b); } - assert(!a->allocated()); - assert(b->allocated()); + + assert(!a->storage_.GetIsAllocated()); + assert(b->storage_.GetIsAllocated()); + const size_type a_size = a->size(); const size_type b_size = b->size(); // In an optimized build, `b_size` would be unused. static_cast<void>(b_size); - // Made Local copies of `size()`, don't need `tag()` accurate anymore - swap(a->tag(), b->tag()); + // Made Local copies of `size()`, these can now be swapped + a->storage_.SwapSizeAndIsAllocated(std::addressof(b->storage_)); - // Copy `b_allocation` out before `b`'s union gets clobbered by - // `inline_space` - Allocation b_allocation = b->allocation(); + // Copy out before `b`'s union gets clobbered by `inline_space` + pointer b_data = b->storage_.GetAllocatedData(); + size_type b_capacity = b->storage_.GetAllocatedCapacity(); - b->UninitializedCopy(a->inlined_space(), a->inlined_space() + a_size, - b->inlined_space()); - a->Destroy(a->inlined_space(), a->inlined_space() + a_size); + b->UninitializedCopy(a->storage_.GetInlinedData(), + a->storage_.GetInlinedData() + a_size, + b->storage_.GetInlinedData()); + a->Destroy(a->storage_.GetInlinedData(), + a->storage_.GetInlinedData() + a_size); - a->allocation() = b_allocation; + a->storage_.SetAllocatedData(b_data); + a->storage_.SetAllocatedCapacity(b_capacity); - if (a->allocator() != b->allocator()) { - swap(a->allocator(), b->allocator()); + if (a->storage_.GetAllocator() != b->storage_.GetAllocator()) { + swap(a->storage_.GetAllocator(), b->storage_.GetAllocator()); } assert(b->size() == a_size); @@ -1230,8 +1231,8 @@ // Swaps the contents of two inlined vectors. This convenience function // simply calls `InlinedVector::swap()`. template <typename T, size_t N, typename A> -auto swap(InlinedVector<T, N, A>& a, - InlinedVector<T, N, A>& b) noexcept(noexcept(a.swap(b))) -> void { +void swap(absl::InlinedVector<T, N, A>& a, + absl::InlinedVector<T, N, A>& b) noexcept(noexcept(a.swap(b))) { a.swap(b); } @@ -1239,17 +1240,21 @@ // // Tests the equivalency of the contents of two inlined vectors. template <typename T, size_t N, typename A> -auto operator==(const InlinedVector<T, N, A>& a, - const InlinedVector<T, N, A>& b) -> bool { - return absl::equal(a.begin(), a.end(), b.begin(), b.end()); +bool operator==(const absl::InlinedVector<T, N, A>& a, + const absl::InlinedVector<T, N, A>& b) { + auto a_data = a.data(); + auto a_size = a.size(); + auto b_data = b.data(); + auto b_size = b.size(); + return absl::equal(a_data, a_data + a_size, b_data, b_data + b_size); } // `operator!=()` // // Tests the inequality of the contents of two inlined vectors. template <typename T, size_t N, typename A> -auto operator!=(const InlinedVector<T, N, A>& a, - const InlinedVector<T, N, A>& b) -> bool { +bool operator!=(const absl::InlinedVector<T, N, A>& a, + const absl::InlinedVector<T, N, A>& b) { return !(a == b); } @@ -1258,9 +1263,14 @@ // Tests whether the contents of one inlined vector are less than the contents // of another through a lexicographical comparison operation. template <typename T, size_t N, typename A> -auto operator<(const InlinedVector<T, N, A>& a, const InlinedVector<T, N, A>& b) - -> bool { - return std::lexicographical_compare(a.begin(), a.end(), b.begin(), b.end()); +bool operator<(const absl::InlinedVector<T, N, A>& a, + const absl::InlinedVector<T, N, A>& b) { + auto a_data = a.data(); + auto a_size = a.size(); + auto b_data = b.data(); + auto b_size = b.size(); + return std::lexicographical_compare(a_data, a_data + a_size, b_data, + b_data + b_size); } // `operator>()` @@ -1268,8 +1278,8 @@ // Tests whether the contents of one inlined vector are greater than the // contents of another through a lexicographical comparison operation. template <typename T, size_t N, typename A> -auto operator>(const InlinedVector<T, N, A>& a, const InlinedVector<T, N, A>& b) - -> bool { +bool operator>(const absl::InlinedVector<T, N, A>& a, + const absl::InlinedVector<T, N, A>& b) { return b < a; } @@ -1278,8 +1288,8 @@ // Tests whether the contents of one inlined vector are less than or equal to // the contents of another through a lexicographical comparison operation. template <typename T, size_t N, typename A> -auto operator<=(const InlinedVector<T, N, A>& a, - const InlinedVector<T, N, A>& b) -> bool { +bool operator<=(const absl::InlinedVector<T, N, A>& a, + const absl::InlinedVector<T, N, A>& b) { return !(b < a); } @@ -1288,27 +1298,23 @@ // Tests whether the contents of one inlined vector are greater than or equal to // the contents of another through a lexicographical comparison operation. template <typename T, size_t N, typename A> -auto operator>=(const InlinedVector<T, N, A>& a, - const InlinedVector<T, N, A>& b) -> bool { +bool operator>=(const absl::InlinedVector<T, N, A>& a, + const absl::InlinedVector<T, N, A>& b) { return !(a < b); } -// AbslHashValue() +// `AbslHashValue()` // -// Provides `absl::Hash` support for inlined vectors. You do not normally call -// this function directly. +// Provides `absl::Hash` support for `absl::InlinedVector`. You do not normally +// call this function directly. template <typename H, typename TheT, size_t TheN, typename TheA> -auto AbslHashValue(H h, const InlinedVector<TheT, TheN, TheA>& v) -> H { - auto p = v.data(); - auto n = v.size(); - return H::combine(H::combine_contiguous(std::move(h), p, n), n); +H AbslHashValue(H h, const absl::InlinedVector<TheT, TheN, TheA>& a) { + auto a_data = a.data(); + auto a_size = a.size(); + return H::combine(H::combine_contiguous(std::move(h), a_data, a_size), + a_size); } -} // namespace absl -// ----------------------------------------------------------------------------- -// Implementation of InlinedVector -// -// Do not depend on any below implementation details! -// ----------------------------------------------------------------------------- +} // namespace absl #endif // ABSL_CONTAINER_INLINED_VECTOR_H_
diff --git a/absl/container/internal/compressed_tuple.h b/absl/container/internal/compressed_tuple.h index b9bd91a..bb3471f 100644 --- a/absl/container/internal/compressed_tuple.h +++ b/absl/container/internal/compressed_tuple.h
@@ -38,13 +38,13 @@ #include "absl/utility/utility.h" -#ifdef _MSC_VER +#if defined(_MSC_VER) && !defined(__NVCC__) // 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 +#else #define ABSL_INTERNAL_COMPRESSED_TUPLE_DECLSPEC -#endif // _MSC_VER +#endif namespace absl { namespace container_internal {
diff --git a/absl/container/internal/inlined_vector.h b/absl/container/internal/inlined_vector.h index 24059d9..b8b4f4c 100644 --- a/absl/container/internal/inlined_vector.h +++ b/absl/container/internal/inlined_vector.h
@@ -18,12 +18,19 @@ #include <cstddef> #include <iterator> #include <memory> +#include <utility> +#include "absl/container/internal/compressed_tuple.h" #include "absl/meta/type_traits.h" namespace absl { namespace inlined_vector_internal { +template <typename Iterator> +using IsAtLeastForwardIterator = std::is_convertible< + typename std::iterator_traits<Iterator>::iterator_category, + std::forward_iterator_tag>; + template <typename InlinedVector> class Storage; @@ -44,80 +51,93 @@ using const_iterator = const_pointer; using reverse_iterator = std::reverse_iterator<iterator>; using const_reverse_iterator = std::reverse_iterator<const_iterator>; + using AllocatorTraits = std::allocator_traits<allocator_type>; - explicit Storage(const allocator_type& a) : allocator_and_tag_(a) {} + explicit Storage(const allocator_type& alloc) + : metadata_(alloc, /* empty and inlined */ 0) {} - // TODO(johnsoncj): Make the below types and members private after migration + size_type GetSize() const { return GetSizeAndIsAllocated() >> 1; } - // Holds whether the vector is allocated or not in the lowest bit and the size - // in the high bits: - // `size_ = (size << 1) | is_allocated;` - class Tag { - size_type size_; + bool GetIsAllocated() const { return GetSizeAndIsAllocated() & 1; } - public: - Tag() : size_(0) {} - size_type size() const { return size_ / 2; } - void add_size(size_type n) { size_ += n * 2; } - void set_inline_size(size_type n) { size_ = n * 2; } - void set_allocated_size(size_type n) { size_ = (n * 2) + 1; } - bool allocated() const { return size_ % 2; } + pointer GetInlinedData() { + return reinterpret_cast<pointer>( + std::addressof(data_.inlined.inlined_data[0])); + } + + const_pointer GetInlinedData() const { + return reinterpret_cast<const_pointer>( + std::addressof(data_.inlined.inlined_data[0])); + } + + pointer GetAllocatedData() { return data_.allocated.allocated_data; } + + const_pointer GetAllocatedData() const { + return data_.allocated.allocated_data; + } + + size_type GetAllocatedCapacity() const { + return data_.allocated.allocated_capacity; + } + + allocator_type& GetAllocator() { return metadata_.template get<0>(); } + + const allocator_type& GetAllocator() const { + return metadata_.template get<0>(); + } + + void SetAllocatedSize(size_type size) { + GetSizeAndIsAllocated() = (size << 1) | static_cast<size_type>(1); + } + + void SetInlinedSize(size_type size) { GetSizeAndIsAllocated() = size << 1; } + + void AddSize(size_type count) { GetSizeAndIsAllocated() += count << 1; } + + void SetAllocatedData(pointer data) { data_.allocated.allocated_data = data; } + + void SetAllocatedCapacity(size_type capacity) { + data_.allocated.allocated_capacity = capacity; + } + + void SwapSizeAndIsAllocated(Storage* other) { + using std::swap; + swap(GetSizeAndIsAllocated(), other->GetSizeAndIsAllocated()); + } + + void SwapAllocatedSizeAndCapacity(Storage* other) { + using std::swap; + swap(data_.allocated, other->data_.allocated); + } + + private: + size_type& GetSizeAndIsAllocated() { return metadata_.template get<1>(); } + + const size_type& GetSizeAndIsAllocated() const { + return metadata_.template get<1>(); + } + + using Metadata = + container_internal::CompressedTuple<allocator_type, size_type>; + + struct Allocated { + pointer allocated_data; + size_type allocated_capacity; }; - // Derives from `allocator_type` to use the empty base class optimization. - // If the `allocator_type` is stateless, we can store our instance for free. - class AllocatorAndTag : private allocator_type { - Tag tag_; - - public: - explicit AllocatorAndTag(const allocator_type& a) : allocator_type(a) {} - Tag& tag() { return tag_; } - const Tag& tag() const { return tag_; } - allocator_type& allocator() { return *this; } - const allocator_type& allocator() const { return *this; } - }; - - class Allocation { - size_type capacity_; - pointer buffer_; - - public: - Allocation(allocator_type& a, size_type capacity) - : capacity_(capacity), buffer_(Create(a, capacity)) {} - void Dealloc(allocator_type& a) { - std::allocator_traits<allocator_type>::deallocate(a, buffer_, capacity_); - } - size_type capacity() const { return capacity_; } - const_pointer buffer() const { return buffer_; } - pointer buffer() { return buffer_; } - static pointer Create(allocator_type& a, size_type n) { - return std::allocator_traits<allocator_type>::allocate(a, n); - } - }; - - // Stores either the inlined or allocated representation - union Rep { - using ValueTypeBuffer = + struct Inlined { + using InlinedDataElement = absl::aligned_storage_t<sizeof(value_type), alignof(value_type)>; - using AllocationBuffer = - absl::aligned_storage_t<sizeof(Allocation), alignof(Allocation)>; - - // Structs wrap the buffers to perform indirection that solves a bizarre - // compilation error on Visual Studio (all known versions). - struct InlinedRep { - ValueTypeBuffer inlined[N]; - }; - - struct AllocatedRep { - AllocationBuffer allocation; - }; - - InlinedRep inlined_storage; - AllocatedRep allocation_storage; + InlinedDataElement inlined_data[N]; }; - AllocatorAndTag allocator_and_tag_; - Rep rep_; + union Data { + Allocated allocated; + Inlined inlined; + }; + + Metadata metadata_; + Data data_; }; } // namespace inlined_vector_internal
diff --git a/absl/container/internal/raw_hash_set.h b/absl/container/internal/raw_hash_set.h index 85e3334..8ac0dda 100644 --- a/absl/container/internal/raw_hash_set.h +++ b/absl/container/internal/raw_hash_set.h
@@ -1437,7 +1437,18 @@ void initialize_slots() { assert(capacity_); - if (slots_ == nullptr) { + // Folks with custom allocators often make unwarranted assumptions about the + // behavior of their classes vis-a-vis trivial destructability and what + // calls they will or wont make. Avoid sampling for people with custom + // allocators to get us out of this mess. This is not a hard guarantee but + // a workaround while we plan the exact guarantee we want to provide. + // + // People are often sloppy with the exact type of their allocator (sometimes + // it has an extra const or is missing the pair, but rebinds made it work + // anyway). To avoid the ambiguity, we work off SlotAlloc which we have + // bound more carefully. + if (std::is_same<SlotAlloc, std::allocator<slot_type>>::value && + slots_ == nullptr) { infoz_ = Sample(); }
diff --git a/absl/container/internal/raw_hash_set_test.cc b/absl/container/internal/raw_hash_set_test.cc index 02fd0bf..ed4ca8c 100644 --- a/absl/container/internal/raw_hash_set_test.cc +++ b/absl/container/internal/raw_hash_set_test.cc
@@ -343,7 +343,25 @@ : raw_hash_set<IntPolicy, container_internal::hash_default_hash<int64_t>, std::equal_to<int64_t>, std::allocator<int64_t>> { using Base = typename IntTable::raw_hash_set; - IntTable() {} + using Base::Base; +}; + +template <typename T> +struct CustomAlloc : std::allocator<T> { + CustomAlloc() {} + + template <typename U> + CustomAlloc(const CustomAlloc<U>& other) {} + + template<class U> struct rebind { + using other = CustomAlloc<U>; + }; +}; + +struct CustomAllocIntTable + : raw_hash_set<IntPolicy, container_internal::hash_default_hash<int64_t>, + std::equal_to<int64_t>, CustomAlloc<int64_t>> { + using Base = typename CustomAllocIntTable::raw_hash_set; using Base::Base; }; @@ -414,10 +432,11 @@ t.prefetch(2); // Do not run in debug mode, when prefetch is not implemented, or when - // sanitizers are enabled. -#if defined(NDEBUG) && defined(__GNUC__) && !defined(ADDRESS_SANITIZER) && \ - !defined(MEMORY_SANITIZER) && !defined(THREAD_SANITIZER) && \ - !defined(UNDEFINED_BEHAVIOR_SANITIZER) + // sanitizers are enabled, or on WebAssembly. +#if defined(NDEBUG) && defined(__GNUC__) && defined(__x86_64__) && \ + !defined(ADDRESS_SANITIZER) && !defined(MEMORY_SANITIZER) && \ + !defined(THREAD_SANITIZER) && !defined(UNDEFINED_BEHAVIOR_SANITIZER) && \ + !defined(__EMSCRIPTEN__) const auto now = [] { return absl::base_internal::CycleClock::Now(); }; // Make size enough to not fit in L2 cache (16.7 Mb) @@ -1062,7 +1081,7 @@ ExpectedStats XorSeedExpectedStats() { constexpr bool kRandomizesInserts = -#if NDEBUG +#ifdef NDEBUG false; #else // NDEBUG true; @@ -1156,7 +1175,7 @@ ExpectedStats LinearTransformExpectedStats() { constexpr bool kRandomizesInserts = -#if NDEBUG +#ifdef NDEBUG false; #else // NDEBUG true; @@ -1346,37 +1365,31 @@ TEST(Table, CopyConstruct) { IntTable t; - t.max_load_factor(.321f); t.emplace(0); EXPECT_EQ(1, t.size()); { IntTable u(t); EXPECT_EQ(1, u.size()); - EXPECT_EQ(t.max_load_factor(), u.max_load_factor()); EXPECT_THAT(*u.find(0), 0); } { IntTable u{t}; EXPECT_EQ(1, u.size()); - EXPECT_EQ(t.max_load_factor(), u.max_load_factor()); EXPECT_THAT(*u.find(0), 0); } { IntTable u = t; EXPECT_EQ(1, u.size()); - EXPECT_EQ(t.max_load_factor(), u.max_load_factor()); EXPECT_THAT(*u.find(0), 0); } } TEST(Table, CopyConstructWithAlloc) { StringTable t; - t.max_load_factor(.321f); t.emplace("a", "b"); EXPECT_EQ(1, t.size()); StringTable u(t, Alloc<std::pair<std::string, std::string>>()); EXPECT_EQ(1, u.size()); - EXPECT_EQ(t.max_load_factor(), u.max_load_factor()); EXPECT_THAT(*u.find("a"), Pair("a", "b")); } @@ -1394,88 +1407,68 @@ TEST(Table, MoveConstruct) { { StringTable t; - t.max_load_factor(.321f); - const float lf = t.max_load_factor(); t.emplace("a", "b"); EXPECT_EQ(1, t.size()); StringTable u(std::move(t)); EXPECT_EQ(1, u.size()); - EXPECT_EQ(lf, u.max_load_factor()); EXPECT_THAT(*u.find("a"), Pair("a", "b")); } { StringTable t; - t.max_load_factor(.321f); - const float lf = t.max_load_factor(); t.emplace("a", "b"); EXPECT_EQ(1, t.size()); StringTable u{std::move(t)}; EXPECT_EQ(1, u.size()); - EXPECT_EQ(lf, u.max_load_factor()); EXPECT_THAT(*u.find("a"), Pair("a", "b")); } { StringTable t; - t.max_load_factor(.321f); - const float lf = t.max_load_factor(); t.emplace("a", "b"); EXPECT_EQ(1, t.size()); StringTable u = std::move(t); EXPECT_EQ(1, u.size()); - EXPECT_EQ(lf, u.max_load_factor()); EXPECT_THAT(*u.find("a"), Pair("a", "b")); } } TEST(Table, MoveConstructWithAlloc) { StringTable t; - t.max_load_factor(.321f); - const float lf = t.max_load_factor(); t.emplace("a", "b"); EXPECT_EQ(1, t.size()); StringTable u(std::move(t), Alloc<std::pair<std::string, std::string>>()); EXPECT_EQ(1, u.size()); - EXPECT_EQ(lf, u.max_load_factor()); EXPECT_THAT(*u.find("a"), Pair("a", "b")); } TEST(Table, CopyAssign) { StringTable t; - t.max_load_factor(.321f); t.emplace("a", "b"); EXPECT_EQ(1, t.size()); StringTable u; u = t; EXPECT_EQ(1, u.size()); - EXPECT_EQ(t.max_load_factor(), u.max_load_factor()); EXPECT_THAT(*u.find("a"), Pair("a", "b")); } TEST(Table, CopySelfAssign) { StringTable t; - t.max_load_factor(.321f); - const float lf = t.max_load_factor(); t.emplace("a", "b"); EXPECT_EQ(1, t.size()); t = *&t; EXPECT_EQ(1, t.size()); - EXPECT_EQ(lf, t.max_load_factor()); EXPECT_THAT(*t.find("a"), Pair("a", "b")); } TEST(Table, MoveAssign) { StringTable t; - t.max_load_factor(.321f); - const float lf = t.max_load_factor(); t.emplace("a", "b"); EXPECT_EQ(1, t.size()); StringTable u; u = std::move(t); EXPECT_EQ(1, u.size()); - EXPECT_EQ(lf, u.max_load_factor()); EXPECT_THAT(*u.find("a"), Pair("a", "b")); } @@ -1785,7 +1778,7 @@ std::vector<IntTable> tables; bool found_difference = false; - for (int i = 0; !found_difference && i < 500; ++i) { + for (int i = 0; !found_difference && i < 5000; ++i) { tables.push_back(MakeSimpleTable(size)); found_difference = OrderOfIteration(tables.back()) != reference; } @@ -1799,7 +1792,7 @@ TEST(Table, IterationOrderChangesOnRehash) { std::vector<IntTable> garbage; - for (int i = 0; i < 500; ++i) { + for (int i = 0; i < 5000; ++i) { auto t = MakeSimpleTable(20); const auto reference = OrderOfIteration(t); // Force rehash to the same size. @@ -1869,6 +1862,27 @@ 0.01, 0.005); } +TEST(RawHashSamplerTest, DoNotSampleCustomAllocators) { + // Enable the feature even if the prod default is off. + SetHashtablezEnabled(true); + SetHashtablezSampleParameter(100); + + auto& sampler = HashtablezSampler::Global(); + size_t start_size = 0; + start_size += sampler.Iterate([&](const HashtablezInfo&) { ++start_size; }); + + std::vector<CustomAllocIntTable> tables; + for (int i = 0; i < 1000000; ++i) { + tables.emplace_back(); + tables.back().insert(1); + } + size_t end_size = 0; + end_size += sampler.Iterate([&](const HashtablezInfo&) { ++end_size; }); + + EXPECT_NEAR((end_size - start_size) / static_cast<double>(tables.size()), + 0.00, 0.001); +} + #ifdef ADDRESS_SANITIZER TEST(Sanitizer, PoisoningUnused) { IntTable t;
diff --git a/absl/copts/AbseilConfigureCopts.cmake b/absl/copts/AbseilConfigureCopts.cmake index 5084958..eaef30b 100644 --- a/absl/copts/AbseilConfigureCopts.cmake +++ b/absl/copts/AbseilConfigureCopts.cmake
@@ -3,23 +3,25 @@ set(ABSL_LSAN_LINKOPTS "") set(ABSL_HAVE_LSAN OFF) +set(ABSL_DEFAULT_LINKOPTS "") -if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") +if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") set(ABSL_DEFAULT_COPTS "${ABSL_GCC_FLAGS}") set(ABSL_TEST_COPTS "${ABSL_GCC_FLAGS};${ABSL_GCC_TEST_FLAGS}") set(ABSL_EXCEPTIONS_FLAG "${ABSL_GCC_EXCEPTIONS_FLAGS}") elseif("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") # MATCHES so we get both Clang and AppleClang - if (MSVC) + if(MSVC) # clang-cl is half MSVC, half LLVM set(ABSL_DEFAULT_COPTS "${ABSL_CLANG_CL_FLAGS}") set(ABSL_TEST_COPTS "${ABSL_CLANG_CL_FLAGS};${ABSL_CLANG_CL_TEST_FLAGS}") set(ABSL_EXCEPTIONS_FLAG "${ABSL_CLANG_CL_EXCEPTIONS_FLAGS}") + set(ABSL_DEFAULT_LINKOPTS "${ABSL_MSVC_LINKOPTS}") else() set(ABSL_DEFAULT_COPTS "${ABSL_LLVM_FLAGS}") set(ABSL_TEST_COPTS "${ABSL_LLVM_FLAGS};${ABSL_LLVM_TEST_FLAGS}") set(ABSL_EXCEPTIONS_FLAG "${ABSL_LLVM_EXCEPTIONS_FLAGS}") - if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") + if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") # AppleClang doesn't have lsan # https://developer.apple.com/documentation/code_diagnostics if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 3.5) @@ -32,6 +34,7 @@ set(ABSL_DEFAULT_COPTS "${ABSL_MSVC_FLAGS}") set(ABSL_TEST_COPTS "${ABSL_MSVC_FLAGS};${ABSL_MSVC_TEST_FLAGS}") set(ABSL_EXCEPTIONS_FLAG "${ABSL_MSVC_EXCEPTIONS_FLAGS}") + set(ABSL_DEFAULT_LINKOPTS "${ABSL_MSVC_LINKOPTS}") else() message(WARNING "Unknown compiler: ${CMAKE_CXX_COMPILER}. Building with no default flags") set(ABSL_DEFAULT_COPTS "")
diff --git a/absl/copts/GENERATED_AbseilCopts.cmake b/absl/copts/GENERATED_AbseilCopts.cmake index 9031bfa..27e6f5a 100644 --- a/absl/copts/GENERATED_AbseilCopts.cmake +++ b/absl/copts/GENERATED_AbseilCopts.cmake
@@ -37,7 +37,6 @@ "-Wno-shorten-64-to-32" "-Wno-switch-enum" "-Wno-thread-safety-negative" - "-Wno-undef" "-Wno-unknown-warning-option" "-Wno-unreachable-code" "-Wno-unused-macros" @@ -62,6 +61,7 @@ list(APPEND ABSL_CLANG_CL_TEST_FLAGS "-Wno-c99-extensions" + "-Wno-deprecated-declarations" "-Wno-missing-noreturn" "-Wno-missing-prototypes" "-Wno-missing-variable-declarations" @@ -76,6 +76,7 @@ "-Wno-unused-template" "-Wno-used-but-marked-unused" "-Wno-zero-as-null-pointer-constant" + "-Wno-gnu-include-next" "-Wno-gnu-zero-variadic-macro-arguments" ) @@ -102,6 +103,7 @@ list(APPEND ABSL_GCC_TEST_FLAGS "-Wno-conversion-null" + "-Wno-deprecated-declarations" "-Wno-missing-declarations" "-Wno-sign-compare" "-Wno-unused-function" @@ -143,7 +145,6 @@ "-Wno-shorten-64-to-32" "-Wno-switch-enum" "-Wno-thread-safety-negative" - "-Wno-undef" "-Wno-unknown-warning-option" "-Wno-unreachable-code" "-Wno-unused-macros" @@ -163,6 +164,7 @@ list(APPEND ABSL_LLVM_TEST_FLAGS "-Wno-c99-extensions" + "-Wno-deprecated-declarations" "-Wno-missing-noreturn" "-Wno-missing-prototypes" "-Wno-missing-variable-declarations" @@ -177,6 +179,7 @@ "-Wno-unused-template" "-Wno-used-but-marked-unused" "-Wno-zero-as-null-pointer-constant" + "-Wno-gnu-include-next" "-Wno-gnu-zero-variadic-macro-arguments" ) @@ -201,8 +204,14 @@ "/wd4800" ) +list(APPEND ABSL_MSVC_LINKOPTS + "-ignore:4221" +) + list(APPEND ABSL_MSVC_TEST_FLAGS "/wd4018" "/wd4101" "/wd4503" + "/wd4996" + "/DNOMINMAX" )
diff --git a/absl/copts/GENERATED_copts.bzl b/absl/copts/GENERATED_copts.bzl index e05a58e..0feb0f4 100644 --- a/absl/copts/GENERATED_copts.bzl +++ b/absl/copts/GENERATED_copts.bzl
@@ -38,7 +38,6 @@ "-Wno-shorten-64-to-32", "-Wno-switch-enum", "-Wno-thread-safety-negative", - "-Wno-undef", "-Wno-unknown-warning-option", "-Wno-unreachable-code", "-Wno-unused-macros", @@ -63,6 +62,7 @@ ABSL_CLANG_CL_TEST_FLAGS = [ "-Wno-c99-extensions", + "-Wno-deprecated-declarations", "-Wno-missing-noreturn", "-Wno-missing-prototypes", "-Wno-missing-variable-declarations", @@ -77,6 +77,7 @@ "-Wno-unused-template", "-Wno-used-but-marked-unused", "-Wno-zero-as-null-pointer-constant", + "-Wno-gnu-include-next", "-Wno-gnu-zero-variadic-macro-arguments", ] @@ -103,6 +104,7 @@ ABSL_GCC_TEST_FLAGS = [ "-Wno-conversion-null", + "-Wno-deprecated-declarations", "-Wno-missing-declarations", "-Wno-sign-compare", "-Wno-unused-function", @@ -144,7 +146,6 @@ "-Wno-shorten-64-to-32", "-Wno-switch-enum", "-Wno-thread-safety-negative", - "-Wno-undef", "-Wno-unknown-warning-option", "-Wno-unreachable-code", "-Wno-unused-macros", @@ -164,6 +165,7 @@ ABSL_LLVM_TEST_FLAGS = [ "-Wno-c99-extensions", + "-Wno-deprecated-declarations", "-Wno-missing-noreturn", "-Wno-missing-prototypes", "-Wno-missing-variable-declarations", @@ -178,6 +180,7 @@ "-Wno-unused-template", "-Wno-used-but-marked-unused", "-Wno-zero-as-null-pointer-constant", + "-Wno-gnu-include-next", "-Wno-gnu-zero-variadic-macro-arguments", ] @@ -202,8 +205,14 @@ "/wd4800", ] +ABSL_MSVC_LINKOPTS = [ + "-ignore:4221", +] + ABSL_MSVC_TEST_FLAGS = [ "/wd4018", "/wd4101", "/wd4503", + "/wd4996", + "/DNOMINMAX", ]
diff --git a/absl/copts/configure_copts.bzl b/absl/copts/configure_copts.bzl index 1655add..0015931 100644 --- a/absl/copts/configure_copts.bzl +++ b/absl/copts/configure_copts.bzl
@@ -14,6 +14,7 @@ "ABSL_LLVM_TEST_FLAGS", "ABSL_MSVC_EXCEPTIONS_FLAGS", "ABSL_MSVC_FLAGS", + "ABSL_MSVC_LINKOPTS", "ABSL_MSVC_TEST_FLAGS", ) @@ -40,3 +41,8 @@ ABSL_EXCEPTIONS_FLAG_LINKOPTS = select({ "//conditions:default": [], }) + +ABSL_DEFAULT_LINKOPTS = select({ + "//absl:windows": ABSL_MSVC_LINKOPTS, + "//conditions:default": [], +})
diff --git a/absl/copts/copts.py b/absl/copts/copts.py index 3c9d429..154c0ce 100644 --- a/absl/copts/copts.py +++ b/absl/copts/copts.py
@@ -65,7 +65,6 @@ "-Wno-shorten-64-to-32", "-Wno-switch-enum", "-Wno-thread-safety-negative", - "-Wno-undef", "-Wno-unknown-warning-option", "-Wno-unreachable-code", # Causes warnings on include guards @@ -89,6 +88,7 @@ LLVM_TEST_DISABLE_WARNINGS_FLAGS = [ "-Wno-c99-extensions", + "-Wno-deprecated-declarations", "-Wno-missing-noreturn", "-Wno-missing-prototypes", "-Wno-missing-variable-declarations", @@ -103,12 +103,16 @@ "-Wno-unused-template", "-Wno-used-but-marked-unused", "-Wno-zero-as-null-pointer-constant", + # For a libc++ bug fixed in r357267 + "-Wno-gnu-include-next", # gtest depends on this GNU extension being offered. "-Wno-gnu-zero-variadic-macro-arguments", ] MSVC_STYLE_EXCEPTIONS_FLAGS = [ - "/U_HAS_EXCEPTIONS", "/D_HAS_EXCEPTIONS=1", "/EHsc" + "/U_HAS_EXCEPTIONS", + "/D_HAS_EXCEPTIONS=1", + "/EHsc" ] MSVC_DEFINES = [ @@ -146,6 +150,7 @@ ], "ABSL_GCC_TEST_FLAGS": [ "-Wno-conversion-null", + "-Wno-deprecated-declarations", "-Wno-missing-declarations", "-Wno-sign-compare", "-Wno-unused-function", @@ -153,26 +158,41 @@ "-Wno-unused-private-field", ], "ABSL_GCC_EXCEPTIONS_FLAGS": ["-fexceptions"], - "ABSL_LLVM_FLAGS": LLVM_BIG_WARNING_FLAGS + LLVM_DISABLE_WARNINGS_FLAGS, - "ABSL_LLVM_TEST_FLAGS": LLVM_TEST_DISABLE_WARNINGS_FLAGS, + "ABSL_LLVM_FLAGS": + LLVM_BIG_WARNING_FLAGS + LLVM_DISABLE_WARNINGS_FLAGS, + "ABSL_LLVM_TEST_FLAGS": + LLVM_TEST_DISABLE_WARNINGS_FLAGS, "ABSL_LLVM_EXCEPTIONS_FLAGS": ["-fexceptions"], - "ABSL_CLANG_CL_FLAGS": (MSVC_BIG_WARNING_FLAGS + - LLVM_DISABLE_WARNINGS_FLAGS + MSVC_DEFINES), - "ABSL_CLANG_CL_TEST_FLAGS": LLVM_TEST_DISABLE_WARNINGS_FLAGS, - "ABSL_CLANG_CL_EXCEPTIONS_FLAGS": MSVC_STYLE_EXCEPTIONS_FLAGS, - "ABSL_MSVC_FLAGS": MSVC_BIG_WARNING_FLAGS + MSVC_DEFINES + [ - "/wd4005", # macro-redefinition - "/wd4068", # unknown pragma - "/wd4180", # qualifier applied to function type has no meaning; ignored - "/wd4244", # conversion from 'type1' to 'type2', possible loss of data - "/wd4267", # conversion from 'size_t' to 'type', possible loss of data - # forcing value to bool 'true' or 'false' (performance warning) - "/wd4800", - ], + "ABSL_CLANG_CL_FLAGS": ( + MSVC_BIG_WARNING_FLAGS + LLVM_DISABLE_WARNINGS_FLAGS + MSVC_DEFINES), + "ABSL_CLANG_CL_TEST_FLAGS": + LLVM_TEST_DISABLE_WARNINGS_FLAGS, + "ABSL_CLANG_CL_EXCEPTIONS_FLAGS": + MSVC_STYLE_EXCEPTIONS_FLAGS, + "ABSL_MSVC_FLAGS": + MSVC_BIG_WARNING_FLAGS + MSVC_DEFINES + [ + "/wd4005", # macro-redefinition + "/wd4068", # unknown pragma + # qualifier applied to function type has no meaning; ignored + "/wd4180", + # conversion from 'type1' to 'type2', possible loss of data + "/wd4244", + # conversion from 'size_t' to 'type', possible loss of data + "/wd4267", + # forcing value to bool 'true' or 'false' (performance warning) + "/wd4800", + ], "ABSL_MSVC_TEST_FLAGS": [ "/wd4018", # signed/unsigned mismatch "/wd4101", # unreferenced local variable "/wd4503", # decorated name length exceeded, name was truncated + "/wd4996", # use of deprecated symbol + "/DNOMINMAX", # disable the min() and max() macros from <windows.h> ], - "ABSL_MSVC_EXCEPTIONS_FLAGS": MSVC_STYLE_EXCEPTIONS_FLAGS, + "ABSL_MSVC_EXCEPTIONS_FLAGS": + MSVC_STYLE_EXCEPTIONS_FLAGS, + "ABSL_MSVC_LINKOPTS": [ + # Object file doesn't export any previously undefined symbols + "-ignore:4221", + ], }
diff --git a/absl/debugging/BUILD.bazel b/absl/debugging/BUILD.bazel index c9184f9..0854314 100644 --- a/absl/debugging/BUILD.bazel +++ b/absl/debugging/BUILD.bazel
@@ -17,6 +17,7 @@ load( "//absl:copts/configure_copts.bzl", "ABSL_DEFAULT_COPTS", + "ABSL_DEFAULT_LINKOPTS", "ABSL_TEST_COPTS", ) @@ -33,6 +34,7 @@ ], hdrs = ["stacktrace.h"], copts = ABSL_DEFAULT_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, deps = [ ":debugging_internal", "//absl/base", @@ -53,6 +55,7 @@ "symbolize.h", ], copts = ABSL_DEFAULT_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, deps = [ ":debugging_internal", ":demangle_internal", @@ -66,6 +69,7 @@ name = "symbolize_test", srcs = ["symbolize_test.cc"], copts = ABSL_TEST_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, deps = [ ":stack_consumption", ":symbolize", @@ -85,6 +89,7 @@ "internal/examine_stack.h", ], copts = ABSL_DEFAULT_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, visibility = ["//visibility:private"], deps = [ ":stacktrace", @@ -99,6 +104,7 @@ srcs = ["failure_signal_handler.cc"], hdrs = ["failure_signal_handler.h"], copts = ABSL_DEFAULT_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, deps = [ ":examine_stack", ":stacktrace", @@ -115,7 +121,7 @@ linkopts = select({ "//absl:windows": [], "//conditions:default": ["-pthread"], - }), + }) + ABSL_DEFAULT_LINKOPTS, deps = [ ":failure_signal_handler", ":stacktrace", @@ -147,6 +153,7 @@ "internal/vdso_support.h", ], copts = ABSL_DEFAULT_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, deps = [ "//absl/base", "//absl/base:core_headers", @@ -169,6 +176,7 @@ name = "demangle_test", srcs = ["internal/demangle_test.cc"], copts = ABSL_TEST_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, deps = [ ":demangle_internal", ":stack_consumption", @@ -183,6 +191,7 @@ name = "leak_check", srcs = ["leak_check.cc"], hdrs = ["leak_check.h"], + linkopts = ABSL_DEFAULT_LINKOPTS, deps = ["//absl/base:core_headers"], ) @@ -192,6 +201,7 @@ cc_library( name = "leak_check_disable", srcs = ["leak_check_disable.cc"], + linkopts = ABSL_DEFAULT_LINKOPTS, linkstatic = 1, alwayslink = 1, ) @@ -212,6 +222,7 @@ "//absl:llvm_compiler": ["-DLEAK_SANITIZER"], "//conditions:default": [], }), + linkopts = ABSL_DEFAULT_LINKOPTS, visibility = ["//visibility:private"], ) @@ -221,6 +232,7 @@ srcs = ["leak_check.cc"], hdrs = ["leak_check.h"], copts = ["-ULEAK_SANITIZER"], + linkopts = ABSL_DEFAULT_LINKOPTS, visibility = ["//visibility:private"], ) @@ -231,7 +243,7 @@ "//absl:llvm_compiler": ["-DABSL_EXPECT_LEAK_SANITIZER"], "//conditions:default": [], }), - linkopts = ABSL_LSAN_LINKOPTS, + linkopts = ABSL_LSAN_LINKOPTS + ABSL_DEFAULT_LINKOPTS, deps = [ ":leak_check_api_enabled_for_testing", "//absl/base", @@ -243,6 +255,7 @@ name = "leak_check_no_lsan_test", srcs = ["leak_check_test.cc"], copts = ["-UABSL_EXPECT_LEAK_SANITIZER"], + linkopts = ABSL_DEFAULT_LINKOPTS, deps = [ ":leak_check_api_disabled_for_testing", "//absl/base", # for raw_logging @@ -257,7 +270,7 @@ cc_test( name = "disabled_leak_check_test", srcs = ["leak_check_fail_test.cc"], - linkopts = ABSL_LSAN_LINKOPTS, + linkopts = ABSL_LSAN_LINKOPTS + ABSL_DEFAULT_LINKOPTS, deps = [ ":leak_check_api_enabled_for_testing", ":leak_check_disable", @@ -272,6 +285,7 @@ srcs = ["internal/stack_consumption.cc"], hdrs = ["internal/stack_consumption.h"], copts = ABSL_DEFAULT_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, visibility = ["//visibility:private"], deps = [ "//absl/base", @@ -283,6 +297,7 @@ name = "stack_consumption_test", srcs = ["internal/stack_consumption_test.cc"], copts = ABSL_TEST_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, deps = [ ":stack_consumption", "//absl/base",
diff --git a/absl/debugging/CMakeLists.txt b/absl/debugging/CMakeLists.txt index dccd4a5..d813fed 100644 --- a/absl/debugging/CMakeLists.txt +++ b/absl/debugging/CMakeLists.txt
@@ -43,6 +43,8 @@ "symbolize_win32.inc" COPTS ${ABSL_DEFAULT_COPTS} + LINKOPTS + ${ABSL_DEFAULT_LINKOPTS} DEPS absl::debugging_internal absl::demangle_internal @@ -196,6 +198,8 @@ leak_check_disable SRCS "leak_check_disable.cc" + COPTS + ${ABSL_DEFAULT_COPTS} PUBLIC ) @@ -207,6 +211,7 @@ SRCS "leak_check.cc" COPTS + ${ABSL_DEFAULT_COPTS} $<$<BOOL:${ABSL_HAVE_LSAN}>:-DLEAK_SANITIZER> TESTONLY ) @@ -219,6 +224,7 @@ SRCS "leak_check.cc" COPTS + ${ABSL_DEFAULT_COPTS} "-ULEAK_SANITIZER" TESTONLY ) @@ -229,6 +235,7 @@ SRCS "leak_check_test.cc" COPTS + ${ABSL_DEFAULT_COPTS} "$<$<BOOL:${ABSL_HAVE_LSAN}>:-DABSL_EXPECT_LEAK_SANITIZER>" LINKOPTS "${ABSL_LSAN_LINKOPTS}" @@ -244,6 +251,7 @@ SRCS "leak_check_test.cc" COPTS + ${ABSL_TEST_COPTS} "-UABSL_EXPECT_LEAK_SANITIZER" DEPS absl::leak_check_api_disabled_for_testing @@ -256,6 +264,8 @@ disabled_leak_check_test SRCS "leak_check_fail_test.cc" + COPTS + ${ABSL_TEST_COPTS} LINKOPTS "${ABSL_LSAN_LINKOPTS}" DEPS @@ -298,6 +308,8 @@ absl_cc_library( NAME debugging + COPTS + ${ABSL_DEFAULT_COPTS} DEPS absl::stacktrace absl::leak_check
diff --git a/absl/debugging/internal/demangle_test.cc b/absl/debugging/internal/demangle_test.cc index 883b92d..a68ce32 100644 --- a/absl/debugging/internal/demangle_test.cc +++ b/absl/debugging/internal/demangle_test.cc
@@ -81,8 +81,9 @@ // Tests that verify that Demangle footprint is within some limit. // They are not to be run under sanitizers as the sanitizers increase // stack consumption by about 4x. -#if defined(ABSL_INTERNAL_HAVE_DEBUGGING_STACK_CONSUMPTION) && \ - !ADDRESS_SANITIZER && !MEMORY_SANITIZER && !THREAD_SANITIZER +#if defined(ABSL_INTERNAL_HAVE_DEBUGGING_STACK_CONSUMPTION) && \ + !defined(ADDRESS_SANITIZER) && !defined(MEMORY_SANITIZER) && \ + !defined(THREAD_SANITIZER) static const char *g_mangled; static char g_demangle_buffer[4096];
diff --git a/absl/debugging/symbolize_elf.inc b/absl/debugging/symbolize_elf.inc index 05fc297..5ac7ff5 100644 --- a/absl/debugging/symbolize_elf.inc +++ b/absl/debugging/symbolize_elf.inc
@@ -305,7 +305,7 @@ char *tmp_buf, int tmp_buf_size); enum { - SYMBOL_BUF_SIZE = 2048, + SYMBOL_BUF_SIZE = 3072, TMP_BUF_SIZE = 1024, SYMBOL_CACHE_LINES = 128, };
diff --git a/absl/debugging/symbolize_win32.inc b/absl/debugging/symbolize_win32.inc index 17ea618..7ed3bd3 100644 --- a/absl/debugging/symbolize_win32.inc +++ b/absl/debugging/symbolize_win32.inc
@@ -16,7 +16,13 @@ // https://msdn.microsoft.com/en-us/library/windows/desktop/ms680578(v=vs.85).aspx #include <windows.h> + +// MSVC header DbgHelp.h has a warning for an ignored typedef. +#pragma warning(push) +#pragma warning(disable:4091) #include <DbgHelp.h> +#pragma warning(pop) + #pragma comment(lib, "DbgHelp") #include <algorithm>
diff --git a/absl/hash/BUILD.bazel b/absl/hash/BUILD.bazel index 69860d9..e1e6eae 100644 --- a/absl/hash/BUILD.bazel +++ b/absl/hash/BUILD.bazel
@@ -17,6 +17,7 @@ load( "//absl:copts/configure_copts.bzl", "ABSL_DEFAULT_COPTS", + "ABSL_DEFAULT_LINKOPTS", "ABSL_TEST_COPTS", ) @@ -32,11 +33,12 @@ ], hdrs = ["hash.h"], copts = ABSL_DEFAULT_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, deps = [ - ":city", "//absl/base:core_headers", "//absl/base:endian", "//absl/container:fixed_array", + "//absl/hash:city", "//absl/meta:type_traits", "//absl/numeric:int128", "//absl/strings", @@ -50,6 +52,7 @@ name = "hash_testing", testonly = 1, hdrs = ["hash_testing.h"], + linkopts = ABSL_DEFAULT_LINKOPTS, deps = [ ":spy_hash_state", "//absl/meta:type_traits", @@ -63,6 +66,7 @@ name = "hash_test", srcs = ["hash_test.cc"], copts = ABSL_TEST_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, deps = [ ":hash", ":hash_testing", @@ -80,6 +84,7 @@ testonly = 1, hdrs = ["internal/spy_hash_state.h"], copts = ABSL_DEFAULT_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, visibility = ["//visibility:private"], deps = [ ":hash", @@ -95,6 +100,7 @@ "internal/city.h", ], copts = ABSL_DEFAULT_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, deps = [ "//absl/base:config", "//absl/base:core_headers", @@ -106,6 +112,7 @@ name = "city_test", srcs = ["internal/city_test.cc"], copts = ABSL_TEST_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, deps = [ ":city", "@com_google_googletest//:gtest_main",
diff --git a/absl/hash/CMakeLists.txt b/absl/hash/CMakeLists.txt index 4cafc13..febc551 100644 --- a/absl/hash/CMakeLists.txt +++ b/absl/hash/CMakeLists.txt
@@ -43,6 +43,8 @@ hash_testing HDRS "hash_testing.h" + COPTS + ${ABSL_TEST_COPTS} DEPS absl::spy_hash_state absl::meta @@ -56,7 +58,9 @@ NAME hash_test SRCS - "hash_test.cc" + "hash_test.cc" + COPTS + ${ABSL_TEST_COPTS} DEPS absl::hash absl::hash_testing
diff --git a/absl/hash/hash.h b/absl/hash/hash.h index c0ede35..339b685 100644 --- a/absl/hash/hash.h +++ b/absl/hash/hash.h
@@ -36,6 +36,10 @@ // framework by simply combining its state with the state of known, hashable // types. Hashing of that combined state is separately done by `absl::Hash`. // +// One should assume that a hash algorithm is chosen randomly at the start of +// each process. E.g., absl::Hash<int>()(9) in one process and +// absl::Hash<int>()(9) in another process are likely to differ. +// // Example: // // // Suppose we have a class `Circle` for which we want to add hashing
diff --git a/absl/hash/hash_test.cc b/absl/hash/hash_test.cc index af95938..92c64ad 100644 --- a/absl/hash/hash_test.cc +++ b/absl/hash/hash_test.cc
@@ -425,10 +425,10 @@ } template <typename T, typename = void> -struct IsHashCallble : std::false_type {}; +struct IsHashCallable : std::false_type {}; template <typename T> -struct IsHashCallble<T, absl::void_t<decltype(std::declval<absl::Hash<T>>()( +struct IsHashCallable<T, absl::void_t<decltype(std::declval<absl::Hash<T>>()( std::declval<const T&>()))>> : std::true_type {}; template <typename T, typename = void> @@ -445,7 +445,7 @@ EXPECT_TRUE(std::is_move_constructible<absl::Hash<int>>::value); EXPECT_TRUE(absl::is_copy_assignable<absl::Hash<int>>::value); EXPECT_TRUE(absl::is_move_assignable<absl::Hash<int>>::value); - EXPECT_TRUE(IsHashCallble<int>::value); + EXPECT_TRUE(IsHashCallable<int>::value); EXPECT_TRUE(IsAggregateInitializable<absl::Hash<int>>::value); } @@ -458,7 +458,7 @@ EXPECT_FALSE(std::is_move_constructible<absl::Hash<X>>::value); EXPECT_FALSE(absl::is_copy_assignable<absl::Hash<X>>::value); EXPECT_FALSE(absl::is_move_assignable<absl::Hash<X>>::value); - EXPECT_FALSE(IsHashCallble<X>::value); + EXPECT_FALSE(IsHashCallable<X>::value); EXPECT_FALSE(IsAggregateInitializable<absl::Hash<X>>::value); } #endif // ABSL_META_INTERNAL_STD_HASH_SFINAE_FRIENDLY_
diff --git a/absl/hash/internal/hash.h b/absl/hash/internal/hash.h index 9ab9890..1866517 100644 --- a/absl/hash/internal/hash.h +++ b/absl/hash/internal/hash.h
@@ -615,7 +615,7 @@ public: // Probe each implementation in order. - // disjunction provides short circuting wrt instantiation. + // disjunction provides short circuiting wrt instantiation. template <typename T> using Apply = absl::disjunction< // Probe<UniquelyRepresentedProbe, T>, //
diff --git a/absl/memory/BUILD.bazel b/absl/memory/BUILD.bazel index 7c6366f..f815ef9 100644 --- a/absl/memory/BUILD.bazel +++ b/absl/memory/BUILD.bazel
@@ -17,6 +17,7 @@ load( "//absl:copts/configure_copts.bzl", "ABSL_DEFAULT_COPTS", + "ABSL_DEFAULT_LINKOPTS", "ABSL_TEST_COPTS", "ABSL_EXCEPTIONS_FLAG", "ABSL_EXCEPTIONS_FLAG_LINKOPTS", @@ -30,6 +31,7 @@ name = "memory", hdrs = ["memory.h"], copts = ABSL_DEFAULT_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, deps = [ "//absl/base:core_headers", "//absl/meta:type_traits", @@ -40,6 +42,7 @@ name = "memory_test", srcs = ["memory_test.cc"], copts = ABSL_TEST_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, deps = [ ":memory", "//absl/base", @@ -54,7 +57,7 @@ "memory_exception_safety_test.cc", ], copts = ABSL_TEST_COPTS + ABSL_EXCEPTIONS_FLAG, - linkopts = ABSL_EXCEPTIONS_FLAG_LINKOPTS, + linkopts = ABSL_EXCEPTIONS_FLAG_LINKOPTS + ABSL_DEFAULT_LINKOPTS, deps = [ ":memory", "//absl/base:exception_safety_testing",
diff --git a/absl/memory/memory_test.cc b/absl/memory/memory_test.cc index 8905433..c47820e 100644 --- a/absl/memory/memory_test.cc +++ b/absl/memory/memory_test.cc
@@ -620,7 +620,7 @@ } TEST(AllocatorNoThrowTest, DefaultAllocator) { -#if ABSL_ALLOCATOR_NOTHROW +#if defined(ABSL_ALLOCATOR_NOTHROW) && ABSL_ALLOCATOR_NOTHROW EXPECT_TRUE(absl::default_allocator_is_nothrow::value); #else EXPECT_FALSE(absl::default_allocator_is_nothrow::value); @@ -628,7 +628,7 @@ } TEST(AllocatorNoThrowTest, StdAllocator) { -#if ABSL_ALLOCATOR_NOTHROW +#if defined(ABSL_ALLOCATOR_NOTHROW) && ABSL_ALLOCATOR_NOTHROW EXPECT_TRUE(absl::allocator_is_nothrow<std::allocator<int>>::value); #else EXPECT_FALSE(absl::allocator_is_nothrow<std::allocator<int>>::value);
diff --git a/absl/meta/BUILD.bazel b/absl/meta/BUILD.bazel index 1c39fa9..e004b50 100644 --- a/absl/meta/BUILD.bazel +++ b/absl/meta/BUILD.bazel
@@ -1,6 +1,7 @@ load( "//absl:copts/configure_copts.bzl", "ABSL_DEFAULT_COPTS", + "ABSL_DEFAULT_LINKOPTS", "ABSL_TEST_COPTS", ) @@ -12,6 +13,7 @@ name = "type_traits", hdrs = ["type_traits.h"], copts = ABSL_DEFAULT_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, deps = [ "//absl/base:config", ], @@ -21,9 +23,9 @@ name = "type_traits_test", srcs = ["type_traits_test.cc"], copts = ABSL_TEST_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, deps = [ ":type_traits", - "//absl/base:core_headers", "@com_google_googletest//:gtest_main", ], )
diff --git a/absl/meta/CMakeLists.txt b/absl/meta/CMakeLists.txt index 74d4a54..672ead2 100644 --- a/absl/meta/CMakeLists.txt +++ b/absl/meta/CMakeLists.txt
@@ -35,8 +35,6 @@ ${ABSL_TEST_COPTS} DEPS absl::type_traits - absl::base - absl::core_headers gmock_main ) @@ -44,6 +42,8 @@ absl_cc_library( NAME meta + COPTS + ${ABSL_DEFAULT_COPTS} DEPS absl::type_traits PUBLIC
diff --git a/absl/meta/type_traits.h b/absl/meta/type_traits.h index fbdc921..c08e375 100644 --- a/absl/meta/type_traits.h +++ b/absl/meta/type_traits.h
@@ -43,8 +43,39 @@ namespace absl { +// Defined and documented later on in this file. +template <typename T> +struct is_trivially_move_assignable; + namespace type_traits_internal { +// Silence MSVC warnings about the destructor being defined as deleted. +#if defined(_MSC_VER) && !defined(__GNUC__) +#pragma warning(push) +#pragma warning(disable : 4624) +#endif // defined(_MSC_VER) && !defined(__GNUC__) + +template <class T> +union SingleMemberUnion { + T t; +}; + +// Restore the state of the destructor warning that was silenced above. +#if defined(_MSC_VER) && !defined(__GNUC__) +#pragma warning(pop) +#endif // defined(_MSC_VER) && !defined(__GNUC__) + +template <class T> +struct IsTriviallyMoveAssignableReference : std::false_type {}; + +template <class T> +struct IsTriviallyMoveAssignableReference<T&> + : absl::is_trivially_move_assignable<T>::type {}; + +template <class T> +struct IsTriviallyMoveAssignableReference<T&&> + : absl::is_trivially_move_assignable<T>::type {}; + template <typename... Ts> struct VoidTImpl { using type = void; @@ -275,6 +306,40 @@ #endif // ABSL_HAVE_STD_IS_TRIVIALLY_CONSTRUCTIBLE }; +// is_trivially_move_constructible() +// +// Determines whether the passed type `T` is trivially move constructible. +// +// This metafunction is designed to be a drop-in replacement for the C++11 +// `std::is_trivially_move_constructible()` metafunction for platforms that have +// incomplete C++11 support (such as libstdc++ 4.x). On any platforms that do +// fully support C++11, we check whether this yields the same result as the std +// implementation. +// +// NOTE: `T obj(declval<T>());` needs to be well-formed and not call any +// nontrivial operation. Nontrivially destructible types will cause the +// expression to be nontrivial. +template <typename T> +struct is_trivially_move_constructible + : std::conditional< + std::is_object<T>::value && !std::is_array<T>::value, + std::is_move_constructible< + type_traits_internal::SingleMemberUnion<T>>, + std::is_reference<T>>::type::type { +#ifdef ABSL_HAVE_STD_IS_TRIVIALLY_CONSTRUCTIBLE + private: + static constexpr bool compliant = + std::is_trivially_move_constructible<T>::value == + is_trivially_move_constructible::value; + static_assert(compliant || std::is_trivially_move_constructible<T>::value, + "Not compliant with std::is_trivially_move_constructible; " + "Standard: false, Implementation: true"); + static_assert(compliant || !std::is_trivially_move_constructible<T>::value, + "Not compliant with std::is_trivially_move_constructible; " + "Standard: true, Implementation: false"); +#endif // ABSL_HAVE_STD_IS_TRIVIALLY_CONSTRUCTIBLE +}; + // is_trivially_copy_constructible() // // Determines whether the passed type `T` is trivially copy constructible. @@ -290,9 +355,11 @@ // expression to be nontrivial. template <typename T> struct is_trivially_copy_constructible - : std::integral_constant<bool, __has_trivial_copy(T) && - std::is_copy_constructible<T>::value && - is_trivially_destructible<T>::value> { + : std::conditional< + std::is_object<T>::value && !std::is_array<T>::value, + std::is_copy_constructible< + type_traits_internal::SingleMemberUnion<T>>, + std::is_lvalue_reference<T>>::type::type { #ifdef ABSL_HAVE_STD_IS_TRIVIALLY_CONSTRUCTIBLE private: static constexpr bool compliant = @@ -307,6 +374,42 @@ #endif // ABSL_HAVE_STD_IS_TRIVIALLY_CONSTRUCTIBLE }; +// is_trivially_move_assignable() +// +// Determines whether the passed type `T` is trivially move assignable. +// +// This metafunction is designed to be a drop-in replacement for the C++11 +// `std::is_trivially_move_assignable()` metafunction for platforms that have +// incomplete C++11 support (such as libstdc++ 4.x). On any platforms that do +// fully support C++11, we check whether this yields the same result as the std +// implementation. +// +// NOTE: `is_assignable<T, U>::value` is `true` if the expression +// `declval<T>() = declval<U>()` is well-formed when treated as an unevaluated +// operand. `is_trivially_assignable<T, U>` requires the assignment to call no +// operation that is not trivial. `is_trivially_copy_assignable<T>` is simply +// `is_trivially_assignable<T&, T>`. +template <typename T> +struct is_trivially_move_assignable + : std::conditional< + std::is_object<T>::value && !std::is_array<T>::value, + std::is_move_assignable<type_traits_internal::SingleMemberUnion<T>>, + type_traits_internal::IsTriviallyMoveAssignableReference<T>>::type:: + type { +#ifdef ABSL_HAVE_STD_IS_TRIVIALLY_ASSIGNABLE + private: + static constexpr bool compliant = + std::is_trivially_move_assignable<T>::value == + is_trivially_move_assignable::value; + static_assert(compliant || std::is_trivially_move_assignable<T>::value, + "Not compliant with std::is_trivially_move_assignable; " + "Standard: false, Implementation: true"); + static_assert(compliant || !std::is_trivially_move_assignable<T>::value, + "Not compliant with std::is_trivially_move_assignable; " + "Standard: true, Implementation: false"); +#endif // ABSL_HAVE_STD_IS_TRIVIALLY_ASSIGNABLE +}; + // is_trivially_copy_assignable() // // Determines whether the passed type `T` is trivially copy assignable. @@ -341,6 +444,49 @@ #endif // ABSL_HAVE_STD_IS_TRIVIALLY_ASSIGNABLE }; +namespace type_traits_internal { +// is_trivially_copyable() +// +// Determines whether the passed type `T` is trivially copyable. +// +// This metafunction is designed to be a drop-in replacement for the C++11 +// `std::is_trivially_copyable()` metafunction for platforms that have +// incomplete C++11 support (such as libstdc++ 4.x). We use the C++17 definition +// of TriviallyCopyable. +// +// NOTE: `is_trivially_copyable<T>::value` is `true` if all of T's copy/move +// constructors/assignment operators are trivial or deleted, T has at least +// one non-deleted copy/move constructor/assignment operator, and T is trivially +// destructible. Arrays of trivially copyable types are trivially copyable. +// +// We expose this metafunction only for internal use within absl. +template <typename T> +class is_trivially_copyable_impl { + using ExtentsRemoved = typename std::remove_all_extents<T>::type; + static constexpr bool kIsCopyOrMoveConstructible = + std::is_copy_constructible<ExtentsRemoved>::value || + std::is_move_constructible<ExtentsRemoved>::value; + static constexpr bool kIsCopyOrMoveAssignable = + absl::is_copy_assignable<ExtentsRemoved>::value || + absl::is_move_assignable<ExtentsRemoved>::value; + + public: + static constexpr bool kValue = + (__has_trivial_copy(ExtentsRemoved) || !kIsCopyOrMoveConstructible) && + (__has_trivial_assign(ExtentsRemoved) || !kIsCopyOrMoveAssignable) && + (kIsCopyOrMoveConstructible || kIsCopyOrMoveAssignable) && + is_trivially_destructible<ExtentsRemoved>::value && + // We need to check for this explicitly because otherwise we'll say + // references are trivial copyable when compiled by MSVC. + !std::is_reference<ExtentsRemoved>::value; +}; + +template <typename T> +struct is_trivially_copyable + : std::integral_constant< + bool, type_traits_internal::is_trivially_copyable_impl<T>::kValue> {}; +} // namespace type_traits_internal + // ----------------------------------------------------------------------------- // C++14 "_t" trait aliases // -----------------------------------------------------------------------------
diff --git a/absl/meta/type_traits_test.cc b/absl/meta/type_traits_test.cc index 912336e..82b1be5 100644 --- a/absl/meta/type_traits_test.cc +++ b/absl/meta/type_traits_test.cc
@@ -214,6 +214,29 @@ int n_; }; +class TrivialMoveCtor { + public: + explicit TrivialMoveCtor(int n) : n_(n) {} + TrivialMoveCtor(TrivialMoveCtor&&) = default; + TrivialMoveCtor& operator=(const TrivialMoveCtor& t) { + n_ = t.n_; + return *this; + } + + private: + int n_; +}; + +class NontrivialMoveCtor { + public: + explicit NontrivialMoveCtor(int n) : n_(n) {} + NontrivialMoveCtor(NontrivialMoveCtor&& t) noexcept : n_(t.n_) {} + NontrivialMoveCtor& operator=(const NontrivialMoveCtor&) = default; + + private: + int n_; +}; + class TrivialCopyCtor { public: explicit TrivialCopyCtor(int n) : n_(n) {} @@ -247,6 +270,29 @@ int n_; }; +class TrivialMoveAssign { + public: + explicit TrivialMoveAssign(int n) : n_(n) {} + TrivialMoveAssign(const TrivialMoveAssign& t) : n_(t.n_) {} + TrivialMoveAssign& operator=(TrivialMoveAssign&&) = default; + ~TrivialMoveAssign() {} // can have nontrivial destructor + private: + int n_; +}; + +class NontrivialMoveAssign { + public: + explicit NontrivialMoveAssign(int n) : n_(n) {} + NontrivialMoveAssign(const NontrivialMoveAssign&) = default; + NontrivialMoveAssign& operator=(NontrivialMoveAssign&& t) noexcept { + n_ = t.n_; + return *this; + } + + private: + int n_; +}; + class TrivialCopyAssign { public: explicit TrivialCopyAssign(int n) : n_(n) {} @@ -280,10 +326,20 @@ int n_; }; -struct NonCopyable { - NonCopyable() = default; - NonCopyable(const NonCopyable&) = delete; - NonCopyable& operator=(const NonCopyable&) = delete; +struct MovableNonCopyable { + MovableNonCopyable() = default; + MovableNonCopyable(const MovableNonCopyable&) = delete; + MovableNonCopyable(MovableNonCopyable&&) = default; + MovableNonCopyable& operator=(const MovableNonCopyable&) = delete; + MovableNonCopyable& operator=(MovableNonCopyable&&) = default; +}; + +struct NonCopyableOrMovable { + NonCopyableOrMovable() = default; + NonCopyableOrMovable(const NonCopyableOrMovable&) = delete; + NonCopyableOrMovable(NonCopyableOrMovable&&) = delete; + NonCopyableOrMovable& operator=(const NonCopyableOrMovable&) = delete; + NonCopyableOrMovable& operator=(NonCopyableOrMovable&&) = delete; }; class Base { @@ -474,6 +530,79 @@ #endif } +TEST(TypeTraitsTest, TestTrivialMoveCtor) { + // Verify that arithmetic types and pointers have trivial move + // constructors. + EXPECT_TRUE(absl::is_trivially_move_constructible<bool>::value); + EXPECT_TRUE(absl::is_trivially_move_constructible<char>::value); + EXPECT_TRUE(absl::is_trivially_move_constructible<unsigned char>::value); + EXPECT_TRUE(absl::is_trivially_move_constructible<signed char>::value); + EXPECT_TRUE(absl::is_trivially_move_constructible<wchar_t>::value); + EXPECT_TRUE(absl::is_trivially_move_constructible<int>::value); + EXPECT_TRUE(absl::is_trivially_move_constructible<unsigned int>::value); + EXPECT_TRUE(absl::is_trivially_move_constructible<int16_t>::value); + EXPECT_TRUE(absl::is_trivially_move_constructible<uint16_t>::value); + EXPECT_TRUE(absl::is_trivially_move_constructible<int64_t>::value); + EXPECT_TRUE(absl::is_trivially_move_constructible<uint64_t>::value); + EXPECT_TRUE(absl::is_trivially_move_constructible<float>::value); + EXPECT_TRUE(absl::is_trivially_move_constructible<double>::value); + EXPECT_TRUE(absl::is_trivially_move_constructible<long double>::value); + EXPECT_TRUE(absl::is_trivially_move_constructible<std::string*>::value); + EXPECT_TRUE(absl::is_trivially_move_constructible<Trivial*>::value); + EXPECT_TRUE(absl::is_trivially_move_constructible<const std::string*>::value); + EXPECT_TRUE(absl::is_trivially_move_constructible<const Trivial*>::value); + EXPECT_TRUE(absl::is_trivially_move_constructible<std::string**>::value); + EXPECT_TRUE(absl::is_trivially_move_constructible<Trivial**>::value); + + // Reference types + EXPECT_TRUE(absl::is_trivially_move_constructible<int&>::value); + EXPECT_TRUE(absl::is_trivially_move_constructible<int&&>::value); + + // types with compiler generated move ctors + EXPECT_TRUE(absl::is_trivially_move_constructible<Trivial>::value); + EXPECT_TRUE(absl::is_trivially_move_constructible<TrivialMoveCtor>::value); + + // Verify that types without them (i.e. nontrivial or deleted) are not. + EXPECT_FALSE( + absl::is_trivially_move_constructible<NontrivialCopyCtor>::value); + EXPECT_FALSE(absl::is_trivially_move_constructible<DeletedCopyCtor>::value); + EXPECT_FALSE( + absl::is_trivially_move_constructible<NonCopyableOrMovable>::value); + +#ifdef ABSL_TRIVIALLY_CONSTRUCTIBLE_VERIFY_TRIVIALLY_DESTRUCTIBLE + // type with nontrivial destructor are nontrivial move construbtible + EXPECT_FALSE( + absl::is_trivially_move_constructible<NontrivialDestructor>::value); +#endif + + // types with vtables + EXPECT_FALSE(absl::is_trivially_move_constructible<Base>::value); + + // Verify that simple_pair of such types is trivially move constructible + EXPECT_TRUE( + (absl::is_trivially_move_constructible<simple_pair<int, char*>>::value)); + EXPECT_TRUE(( + absl::is_trivially_move_constructible<simple_pair<int, Trivial>>::value)); + EXPECT_TRUE((absl::is_trivially_move_constructible< + simple_pair<int, TrivialMoveCtor>>::value)); + + // Verify that types without trivial move constructors are + // correctly marked as such. + EXPECT_FALSE(absl::is_trivially_move_constructible<std::string>::value); + EXPECT_FALSE(absl::is_trivially_move_constructible<std::vector<int>>::value); + + // Verify that simple_pairs of types without trivial move constructors + // are not marked as trivial. + EXPECT_FALSE((absl::is_trivially_move_constructible< + simple_pair<int, std::string>>::value)); + EXPECT_FALSE((absl::is_trivially_move_constructible< + simple_pair<std::string, int>>::value)); + + // Verify that arrays are not + using int10 = int[10]; + EXPECT_FALSE(absl::is_trivially_move_constructible<int10>::value); +} + TEST(TypeTraitsTest, TestTrivialCopyCtor) { // Verify that arithmetic types and pointers have trivial copy // constructors. @@ -498,6 +627,10 @@ EXPECT_TRUE(absl::is_trivially_copy_constructible<std::string**>::value); EXPECT_TRUE(absl::is_trivially_copy_constructible<Trivial**>::value); + // Reference types + EXPECT_TRUE(absl::is_trivially_copy_constructible<int&>::value); + EXPECT_FALSE(absl::is_trivially_copy_constructible<int&&>::value); + // types with compiler generated copy ctors EXPECT_TRUE(absl::is_trivially_copy_constructible<Trivial>::value); EXPECT_TRUE(absl::is_trivially_copy_constructible<TrivialCopyCtor>::value); @@ -507,7 +640,9 @@ absl::is_trivially_copy_constructible<NontrivialCopyCtor>::value); EXPECT_FALSE(absl::is_trivially_copy_constructible<DeletedCopyCtor>::value); EXPECT_FALSE( - absl::is_trivially_copy_constructible<NonCopyable>::value); + absl::is_trivially_copy_constructible<MovableNonCopyable>::value); + EXPECT_FALSE( + absl::is_trivially_copy_constructible<NonCopyableOrMovable>::value); #ifdef ABSL_TRIVIALLY_CONSTRUCTIBLE_VERIFY_TRIVIALLY_DESTRUCTIBLE // type with nontrivial destructor are nontrivial copy construbtible @@ -543,6 +678,74 @@ EXPECT_FALSE(absl::is_trivially_copy_constructible<int10>::value); } +TEST(TypeTraitsTest, TestTrivialMoveAssign) { + // Verify that arithmetic types and pointers have trivial move + // assignment operators. + EXPECT_TRUE(absl::is_trivially_move_assignable<bool>::value); + EXPECT_TRUE(absl::is_trivially_move_assignable<char>::value); + EXPECT_TRUE(absl::is_trivially_move_assignable<unsigned char>::value); + EXPECT_TRUE(absl::is_trivially_move_assignable<signed char>::value); + EXPECT_TRUE(absl::is_trivially_move_assignable<wchar_t>::value); + EXPECT_TRUE(absl::is_trivially_move_assignable<int>::value); + EXPECT_TRUE(absl::is_trivially_move_assignable<unsigned int>::value); + EXPECT_TRUE(absl::is_trivially_move_assignable<int16_t>::value); + EXPECT_TRUE(absl::is_trivially_move_assignable<uint16_t>::value); + EXPECT_TRUE(absl::is_trivially_move_assignable<int64_t>::value); + EXPECT_TRUE(absl::is_trivially_move_assignable<uint64_t>::value); + EXPECT_TRUE(absl::is_trivially_move_assignable<float>::value); + EXPECT_TRUE(absl::is_trivially_move_assignable<double>::value); + EXPECT_TRUE(absl::is_trivially_move_assignable<long double>::value); + EXPECT_TRUE(absl::is_trivially_move_assignable<std::string*>::value); + EXPECT_TRUE(absl::is_trivially_move_assignable<Trivial*>::value); + EXPECT_TRUE(absl::is_trivially_move_assignable<const std::string*>::value); + EXPECT_TRUE(absl::is_trivially_move_assignable<const Trivial*>::value); + EXPECT_TRUE(absl::is_trivially_move_assignable<std::string**>::value); + EXPECT_TRUE(absl::is_trivially_move_assignable<Trivial**>::value); + + // const qualified types are not assignable + EXPECT_FALSE(absl::is_trivially_move_assignable<const int>::value); + + // types with compiler generated move assignment + EXPECT_TRUE(absl::is_trivially_move_assignable<Trivial>::value); + EXPECT_TRUE(absl::is_trivially_move_assignable<TrivialMoveAssign>::value); + + // Verify that types without them (i.e. nontrivial or deleted) are not. + EXPECT_FALSE(absl::is_trivially_move_assignable<NontrivialCopyAssign>::value); + EXPECT_FALSE(absl::is_trivially_move_assignable<DeletedCopyAssign>::value); + EXPECT_FALSE(absl::is_trivially_move_assignable<NonCopyableOrMovable>::value); + + // types with vtables + EXPECT_FALSE(absl::is_trivially_move_assignable<Base>::value); + + // Verify that simple_pair is trivially assignable + EXPECT_TRUE( + (absl::is_trivially_move_assignable<simple_pair<int, char*>>::value)); + EXPECT_TRUE( + (absl::is_trivially_move_assignable<simple_pair<int, Trivial>>::value)); + EXPECT_TRUE((absl::is_trivially_move_assignable< + simple_pair<int, TrivialMoveAssign>>::value)); + + // Verify that types not trivially move assignable are + // correctly marked as such. + EXPECT_FALSE(absl::is_trivially_move_assignable<std::string>::value); + EXPECT_FALSE(absl::is_trivially_move_assignable<std::vector<int>>::value); + + // Verify that simple_pairs of types not trivially move assignable + // are not marked as trivial. + EXPECT_FALSE((absl::is_trivially_move_assignable< + simple_pair<int, std::string>>::value)); + EXPECT_FALSE((absl::is_trivially_move_assignable< + simple_pair<std::string, int>>::value)); + + // Verify that arrays are not trivially move assignable + using int10 = int[10]; + EXPECT_FALSE(absl::is_trivially_move_assignable<int10>::value); + + // Verify that references are handled correctly + EXPECT_TRUE(absl::is_trivially_move_assignable<Trivial&&>::value); + EXPECT_TRUE(absl::is_trivially_move_assignable<Trivial&>::value); +} + TEST(TypeTraitsTest, TestTrivialCopyAssign) { // Verify that arithmetic types and pointers have trivial copy // assignment operators. @@ -577,7 +780,8 @@ // Verify that types without them (i.e. nontrivial or deleted) are not. EXPECT_FALSE(absl::is_trivially_copy_assignable<NontrivialCopyAssign>::value); EXPECT_FALSE(absl::is_trivially_copy_assignable<DeletedCopyAssign>::value); - EXPECT_FALSE(absl::is_trivially_copy_assignable<NonCopyable>::value); + EXPECT_FALSE(absl::is_trivially_copy_assignable<MovableNonCopyable>::value); + EXPECT_FALSE(absl::is_trivially_copy_assignable<NonCopyableOrMovable>::value); // types with vtables EXPECT_FALSE(absl::is_trivially_copy_assignable<Base>::value); @@ -611,6 +815,116 @@ EXPECT_TRUE(absl::is_trivially_copy_assignable<Trivial&>::value); } +TEST(TypeTraitsTest, TestTriviallyCopyable) { + // Verify that arithmetic types and pointers are trivially copyable. + EXPECT_TRUE(absl::type_traits_internal::is_trivially_copyable<bool>::value); + EXPECT_TRUE(absl::type_traits_internal::is_trivially_copyable<char>::value); + EXPECT_TRUE( + absl::type_traits_internal::is_trivially_copyable<unsigned char>::value); + EXPECT_TRUE( + absl::type_traits_internal::is_trivially_copyable<signed char>::value); + EXPECT_TRUE( + absl::type_traits_internal::is_trivially_copyable<wchar_t>::value); + EXPECT_TRUE(absl::type_traits_internal::is_trivially_copyable<int>::value); + EXPECT_TRUE( + absl::type_traits_internal::is_trivially_copyable<unsigned int>::value); + EXPECT_TRUE( + absl::type_traits_internal::is_trivially_copyable<int16_t>::value); + EXPECT_TRUE( + absl::type_traits_internal::is_trivially_copyable<uint16_t>::value); + EXPECT_TRUE( + absl::type_traits_internal::is_trivially_copyable<int64_t>::value); + EXPECT_TRUE( + absl::type_traits_internal::is_trivially_copyable<uint64_t>::value); + EXPECT_TRUE(absl::type_traits_internal::is_trivially_copyable<float>::value); + EXPECT_TRUE(absl::type_traits_internal::is_trivially_copyable<double>::value); + EXPECT_TRUE( + absl::type_traits_internal::is_trivially_copyable<long double>::value); + EXPECT_TRUE( + absl::type_traits_internal::is_trivially_copyable<std::string*>::value); + EXPECT_TRUE( + absl::type_traits_internal::is_trivially_copyable<Trivial*>::value); + EXPECT_TRUE(absl::type_traits_internal::is_trivially_copyable< + const std::string*>::value); + EXPECT_TRUE( + absl::type_traits_internal::is_trivially_copyable<const Trivial*>::value); + EXPECT_TRUE( + absl::type_traits_internal::is_trivially_copyable<std::string**>::value); + EXPECT_TRUE( + absl::type_traits_internal::is_trivially_copyable<Trivial**>::value); + + // const qualified types are not assignable but are constructible + EXPECT_TRUE( + absl::type_traits_internal::is_trivially_copyable<const int>::value); + + // Trivial copy constructor/assignment and destructor. + EXPECT_TRUE( + absl::type_traits_internal::is_trivially_copyable<Trivial>::value); + // Trivial copy assignment, but non-trivial copy constructor/destructor. + EXPECT_FALSE(absl::type_traits_internal::is_trivially_copyable< + TrivialCopyAssign>::value); + // Trivial copy constructor, but non-trivial assignment. + EXPECT_FALSE(absl::type_traits_internal::is_trivially_copyable< + TrivialCopyCtor>::value); + + // Types with a non-trivial copy constructor/assignment + EXPECT_FALSE(absl::type_traits_internal::is_trivially_copyable< + NontrivialCopyCtor>::value); + EXPECT_FALSE(absl::type_traits_internal::is_trivially_copyable< + NontrivialCopyAssign>::value); + + // Types without copy constructor/assignment, but with move + // MSVC disagrees with other compilers about this: + // EXPECT_TRUE(absl::type_traits_internal::is_trivially_copyable< + // MovableNonCopyable>::value); + + // Types without copy/move constructor/assignment + EXPECT_FALSE(absl::type_traits_internal::is_trivially_copyable< + NonCopyableOrMovable>::value); + + // No copy assign, but has trivial copy constructor. + EXPECT_TRUE(absl::type_traits_internal::is_trivially_copyable< + DeletedCopyAssign>::value); + + // types with vtables + EXPECT_FALSE(absl::type_traits_internal::is_trivially_copyable<Base>::value); + + // Verify that simple_pair is trivially copyable if members are + EXPECT_TRUE((absl::type_traits_internal::is_trivially_copyable< + simple_pair<int, char*>>::value)); + EXPECT_TRUE((absl::type_traits_internal::is_trivially_copyable< + simple_pair<int, Trivial>>::value)); + + // Verify that types not trivially copyable are + // correctly marked as such. + EXPECT_FALSE( + absl::type_traits_internal::is_trivially_copyable<std::string>::value); + EXPECT_FALSE(absl::type_traits_internal::is_trivially_copyable< + std::vector<int>>::value); + + // Verify that simple_pairs of types not trivially copyable + // are not marked as trivial. + EXPECT_FALSE((absl::type_traits_internal::is_trivially_copyable< + simple_pair<int, std::string>>::value)); + EXPECT_FALSE((absl::type_traits_internal::is_trivially_copyable< + simple_pair<std::string, int>>::value)); + EXPECT_FALSE((absl::type_traits_internal::is_trivially_copyable< + simple_pair<int, TrivialCopyAssign>>::value)); + + // Verify that arrays of trivially copyable types are trivially copyable + using int10 = int[10]; + EXPECT_TRUE(absl::type_traits_internal::is_trivially_copyable<int10>::value); + using int10x10 = int[10][10]; + EXPECT_TRUE( + absl::type_traits_internal::is_trivially_copyable<int10x10>::value); + + // Verify that references are handled correctly + EXPECT_FALSE( + absl::type_traits_internal::is_trivially_copyable<Trivial&&>::value); + EXPECT_FALSE( + absl::type_traits_internal::is_trivially_copyable<Trivial&>::value); +} + #define ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(trait_name, ...) \ EXPECT_TRUE((std::is_same<typename std::trait_name<__VA_ARGS__>::type, \ absl::trait_name##_t<__VA_ARGS__>>::value))
diff --git a/absl/numeric/BUILD.bazel b/absl/numeric/BUILD.bazel index 7cd7ee1..d9b561d 100644 --- a/absl/numeric/BUILD.bazel +++ b/absl/numeric/BUILD.bazel
@@ -15,6 +15,7 @@ load( "//absl:copts/configure_copts.bzl", "ABSL_DEFAULT_COPTS", + "ABSL_DEFAULT_LINKOPTS", "ABSL_TEST_COPTS", ) @@ -31,6 +32,7 @@ ], hdrs = ["int128.h"], copts = ABSL_DEFAULT_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, deps = [ "//absl/base:config", "//absl/base:core_headers", @@ -45,6 +47,7 @@ "int128_test.cc", ], copts = ABSL_TEST_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, deps = [ ":int128", "//absl/base", @@ -59,6 +62,7 @@ name = "int128_benchmark", srcs = ["int128_benchmark.cc"], copts = ABSL_TEST_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, tags = ["benchmark"], deps = [ ":int128",
diff --git a/absl/numeric/CMakeLists.txt b/absl/numeric/CMakeLists.txt index d26141c..242889f 100644 --- a/absl/numeric/CMakeLists.txt +++ b/absl/numeric/CMakeLists.txt
@@ -52,6 +52,8 @@ absl_cc_library( NAME numeric + COPTS + ${ABSL_DEFAULT_COPTS} DEPS absl::int128 PUBLIC
diff --git a/absl/strings/BUILD.bazel b/absl/strings/BUILD.bazel index 9640ff4..2b19473 100644 --- a/absl/strings/BUILD.bazel +++ b/absl/strings/BUILD.bazel
@@ -16,9 +16,9 @@ load( "//absl:copts/configure_copts.bzl", "ABSL_DEFAULT_COPTS", - "ABSL_TEST_COPTS", "ABSL_EXCEPTIONS_FLAG", "ABSL_EXCEPTIONS_FLAG_LINKOPTS", + "ABSL_TEST_COPTS", ) package(
diff --git a/absl/strings/CMakeLists.txt b/absl/strings/CMakeLists.txt index d3393a3..8515ec2 100644 --- a/absl/strings/CMakeLists.txt +++ b/absl/strings/CMakeLists.txt
@@ -501,6 +501,8 @@ "internal/pow10_helper.h" SRCS "internal/pow10_helper.cc" + COPTS + ${ABSL_TEST_COPTS} TESTONLY )
diff --git a/absl/strings/charconv.h b/absl/strings/charconv.h index 59f74bf..3f5891b 100644 --- a/absl/strings/charconv.h +++ b/absl/strings/charconv.h
@@ -49,9 +49,9 @@ // this only supports the `double` and `float` types. // // This interface incorporates the proposed resolutions for library issues -// DR 3800 and DR 3801. If these are adopted with different wording, +// DR 3080 and DR 3081. If these are adopted with different wording, // Abseil's behavior will change to match the standard. (The behavior most -// likely to change is for DR 3801, which says what `value` will be set to in +// likely to change is for DR 3081, which says what `value` will be set to in // the case of overflow and underflow. Code that wants to avoid possible // breaking changes in this area should not depend on `value` when the returned // from_chars_result indicates a range error.)
diff --git a/absl/strings/escaping.cc b/absl/strings/escaping.cc index bc8307e..0d336e3 100644 --- a/absl/strings/escaping.cc +++ b/absl/strings/escaping.cc
@@ -1055,10 +1055,10 @@ } // ---------------------------------------------------------------------- -// ptrdiff_t Base64Unescape() - base64 decoder -// ptrdiff_t Base64Escape() - base64 encoder -// ptrdiff_t WebSafeBase64Unescape() - Google's variation of base64 decoder -// ptrdiff_t WebSafeBase64Escape() - Google's variation of base64 encoder +// Base64Unescape() - base64 decoder +// Base64Escape() - base64 encoder +// WebSafeBase64Unescape() - Google's variation of base64 decoder +// WebSafeBase64Escape() - Google's variation of base64 encoder // // Check out // http://tools.ietf.org/html/rfc2045 for formal description, but what we @@ -1096,6 +1096,20 @@ src.size(), dest, false, kWebSafeBase64Chars); } +std::string Base64Escape(absl::string_view src) { + std::string dest; + Base64EscapeInternal(reinterpret_cast<const unsigned char*>(src.data()), + src.size(), &dest, true, kBase64Chars); + return dest; +} + +std::string WebSafeBase64Escape(absl::string_view src) { + std::string dest; + Base64EscapeInternal(reinterpret_cast<const unsigned char*>(src.data()), + src.size(), &dest, false, kWebSafeBase64Chars); + return dest; +} + std::string HexStringToBytes(absl::string_view from) { std::string result; const auto num = from.size() / 2;
diff --git a/absl/strings/escaping.h b/absl/strings/escaping.h index fd9be78..198b934 100644 --- a/absl/strings/escaping.h +++ b/absl/strings/escaping.h
@@ -132,16 +132,18 @@ // Base64Escape() // -// Encodes a `src` string into a `dest` buffer using base64 encoding, with -// padding characters. This function conforms with RFC 4648 section 4 (base64). +// Encodes a `src` string into a base64-encoded string, with padding characters. +// This function conforms with RFC 4648 section 4 (base64). void Base64Escape(absl::string_view src, std::string* dest); +std::string Base64Escape(absl::string_view src); // WebSafeBase64Escape() // -// Encodes a `src` string into a `dest` buffer using '-' instead of '+' and -// '_' instead of '/', and without padding. This function conforms with RFC 4648 -// section 5 (base64url). +// Encodes a `src` string into a base64-like string, using '-' instead of '+' +// and '_' instead of '/', and without padding. This function conforms with RFC +// 4648 section 5 (base64url). void WebSafeBase64Escape(absl::string_view src, std::string* dest); +std::string WebSafeBase64Escape(absl::string_view src); // HexStringToBytes() //
diff --git a/absl/strings/escaping_test.cc b/absl/strings/escaping_test.cc index d433b4c..6a633cd 100644 --- a/absl/strings/escaping_test.cc +++ b/absl/strings/escaping_test.cc
@@ -556,6 +556,7 @@ StringType encoded("this junk should be ignored"); absl::Base64Escape(tc.plaintext, &encoded); EXPECT_EQ(encoded, tc.cyphertext); + EXPECT_EQ(absl::Base64Escape(tc.plaintext), tc.cyphertext); StringType decoded("this junk should be ignored"); EXPECT_TRUE(absl::Base64Unescape(encoded, &decoded)); @@ -574,6 +575,7 @@ encoded = "this junk should be ignored"; absl::WebSafeBase64Escape(tc.plaintext, &encoded); EXPECT_EQ(encoded, websafe); + EXPECT_EQ(absl::WebSafeBase64Escape(tc.plaintext), websafe); // Let's try the std::string version of the decoder decoded = "this junk should be ignored"; @@ -586,6 +588,7 @@ StringType buffer; absl::WebSafeBase64Escape(tc.plaintext, &buffer); EXPECT_EQ(tc.cyphertext, buffer); + EXPECT_EQ(absl::WebSafeBase64Escape(tc.plaintext), tc.cyphertext); } // Verify the behavior when decoding bad data
diff --git a/absl/strings/internal/str_format/bind_test.cc b/absl/strings/internal/str_format/bind_test.cc index ba6470e..2574801 100644 --- a/absl/strings/internal/str_format/bind_test.cc +++ b/absl/strings/internal/str_format/bind_test.cc
@@ -9,16 +9,11 @@ namespace str_format_internal { namespace { -template <typename T, size_t N> -size_t ArraySize(T (&)[N]) { - return N; -} - class FormatBindTest : public ::testing::Test { public: bool Extract(const char *s, UnboundConversion *props, int *next) const { - absl::string_view src = s; - return ConsumeUnboundConversion(&src, props, next) && src.empty(); + return ConsumeUnboundConversion(s, s + strlen(s), props, next) == + s + strlen(s); } };
diff --git a/absl/strings/internal/str_format/convert_test.cc b/absl/strings/internal/str_format/convert_test.cc index 99cc0af..3b4d4b0 100644 --- a/absl/strings/internal/str_format/convert_test.cc +++ b/absl/strings/internal/str_format/convert_test.cc
@@ -1,6 +1,7 @@ #include <errno.h> #include <stdarg.h> #include <stdio.h> +#include <cctype> #include <cmath> #include <string> @@ -32,7 +33,9 @@ std::string LengthModFor(unsigned long long) { return "ll"; } // NOLINT std::string EscCharImpl(int v) { - if (isprint(v)) return std::string(1, static_cast<char>(v)); + if (std::isprint(static_cast<unsigned char>(v))) { + return std::string(1, static_cast<char>(v)); + } char buf[64]; int n = snprintf(buf, sizeof(buf), "\\%#.2x", static_cast<unsigned>(v & 0xff)); @@ -155,7 +158,7 @@ } TEST_F(FormatConvertTest, Pointer) { -#if _MSC_VER +#ifdef _MSC_VER // MSVC's printf implementation prints pointers differently. We can't easily // compare our implementation to theirs. return; @@ -390,7 +393,7 @@ } TEST_F(FormatConvertTest, Float) { -#if _MSC_VER +#ifdef _MSC_VER // MSVC has a different rounding policy than us so we can't test our // implementation against the native one there. return;
diff --git a/absl/strings/internal/str_format/parser.cc b/absl/strings/internal/str_format/parser.cc index 10487f2..9ef5615 100644 --- a/absl/strings/internal/str_format/parser.cc +++ b/absl/strings/internal/str_format/parser.cc
@@ -15,6 +15,44 @@ namespace absl { namespace str_format_internal { + +using CC = ConversionChar::Id; +using LM = LengthMod::Id; +ABSL_CONST_INIT const ConvTag kTags[256] = { + {}, {}, {}, {}, {}, {}, {}, {}, // 00-07 + {}, {}, {}, {}, {}, {}, {}, {}, // 08-0f + {}, {}, {}, {}, {}, {}, {}, {}, // 10-17 + {}, {}, {}, {}, {}, {}, {}, {}, // 18-1f + {}, {}, {}, {}, {}, {}, {}, {}, // 20-27 + {}, {}, {}, {}, {}, {}, {}, {}, // 28-2f + {}, {}, {}, {}, {}, {}, {}, {}, // 30-37 + {}, {}, {}, {}, {}, {}, {}, {}, // 38-3f + {}, CC::A, {}, CC::C, {}, CC::E, CC::F, CC::G, // @ABCDEFG + {}, {}, {}, {}, LM::L, {}, {}, {}, // HIJKLMNO + {}, {}, {}, CC::S, {}, {}, {}, {}, // PQRSTUVW + CC::X, {}, {}, {}, {}, {}, {}, {}, // XYZ[\]^_ + {}, CC::a, {}, CC::c, CC::d, CC::e, CC::f, CC::g, // `abcdefg + LM::h, CC::i, LM::j, {}, LM::l, {}, CC::n, CC::o, // hijklmno + CC::p, LM::q, {}, CC::s, LM::t, CC::u, {}, {}, // pqrstuvw + CC::x, {}, LM::z, {}, {}, {}, {}, {}, // xyz{|}! + {}, {}, {}, {}, {}, {}, {}, {}, // 80-87 + {}, {}, {}, {}, {}, {}, {}, {}, // 88-8f + {}, {}, {}, {}, {}, {}, {}, {}, // 90-97 + {}, {}, {}, {}, {}, {}, {}, {}, // 98-9f + {}, {}, {}, {}, {}, {}, {}, {}, // a0-a7 + {}, {}, {}, {}, {}, {}, {}, {}, // a8-af + {}, {}, {}, {}, {}, {}, {}, {}, // b0-b7 + {}, {}, {}, {}, {}, {}, {}, {}, // b8-bf + {}, {}, {}, {}, {}, {}, {}, {}, // c0-c7 + {}, {}, {}, {}, {}, {}, {}, {}, // c8-cf + {}, {}, {}, {}, {}, {}, {}, {}, // d0-d7 + {}, {}, {}, {}, {}, {}, {}, {}, // d8-df + {}, {}, {}, {}, {}, {}, {}, {}, // e0-e7 + {}, {}, {}, {}, {}, {}, {}, {}, // e8-ef + {}, {}, {}, {}, {}, {}, {}, {}, // f0-f7 + {}, {}, {}, {}, {}, {}, {}, {}, // f8-ff +}; + namespace { bool CheckFastPathSetting(const UnboundConversion& conv) { @@ -36,60 +74,17 @@ return should_be_basic == conv.flags.basic; } -// Keep a single table for all the conversion chars and length modifiers. -// We invert the length modifiers to make them negative so that we can easily -// test for them. -// Everything else is `none`, which is a negative constant. -using CC = ConversionChar::Id; -using LM = LengthMod::Id; -static constexpr std::int8_t none = -128; -static constexpr std::int8_t kIds[] = { - none, none, none, none, none, none, none, none, // 00-07 - none, none, none, none, none, none, none, none, // 08-0f - none, none, none, none, none, none, none, none, // 10-17 - none, none, none, none, none, none, none, none, // 18-1f - none, none, none, none, none, none, none, none, // 20-27 - none, none, none, none, none, none, none, none, // 28-2f - none, none, none, none, none, none, none, none, // 30-37 - none, none, none, none, none, none, none, none, // 38-3f - none, CC::A, none, CC::C, none, CC::E, CC::F, CC::G, // @ABCDEFG - none, none, none, none, ~LM::L, none, none, none, // HIJKLMNO - none, none, none, CC::S, none, none, none, none, // PQRSTUVW - CC::X, none, none, none, none, none, none, none, // XYZ[\]^_ - none, CC::a, none, CC::c, CC::d, CC::e, CC::f, CC::g, // `abcdefg - ~LM::h, CC::i, ~LM::j, none, ~LM::l, none, CC::n, CC::o, // hijklmno - CC::p, ~LM::q, none, CC::s, ~LM::t, CC::u, none, none, // pqrstuvw - CC::x, none, ~LM::z, none, none, none, none, none, // xyz{|}~! - none, none, none, none, none, none, none, none, // 80-87 - none, none, none, none, none, none, none, none, // 88-8f - none, none, none, none, none, none, none, none, // 90-97 - none, none, none, none, none, none, none, none, // 98-9f - none, none, none, none, none, none, none, none, // a0-a7 - none, none, none, none, none, none, none, none, // a8-af - none, none, none, none, none, none, none, none, // b0-b7 - none, none, none, none, none, none, none, none, // b8-bf - none, none, none, none, none, none, none, none, // c0-c7 - none, none, none, none, none, none, none, none, // c8-cf - none, none, none, none, none, none, none, none, // d0-d7 - none, none, none, none, none, none, none, none, // d8-df - none, none, none, none, none, none, none, none, // e0-e7 - none, none, none, none, none, none, none, none, // e8-ef - none, none, none, none, none, none, none, none, // f0-f7 - none, none, none, none, none, none, none, none, // f8-ff -}; - template <bool is_positional> -bool ConsumeConversion(string_view *src, UnboundConversion *conv, - int *next_arg) { - const char *pos = src->data(); - const char *const end = pos + src->size(); +const char *ConsumeConversion(const char *pos, const char *const end, + UnboundConversion *conv, int *next_arg) { + const char* const original_pos = pos; char c; // Read the next char into `c` and update `pos`. Returns false if there are // no more chars to read. -#define ABSL_FORMAT_PARSER_INTERNAL_GET_CHAR() \ - do { \ - if (ABSL_PREDICT_FALSE(pos == end)) return false; \ - c = *pos++; \ +#define ABSL_FORMAT_PARSER_INTERNAL_GET_CHAR() \ + do { \ + if (ABSL_PREDICT_FALSE(pos == end)) return nullptr; \ + c = *pos++; \ } while (0) const auto parse_digits = [&] { @@ -111,10 +106,10 @@ if (is_positional) { ABSL_FORMAT_PARSER_INTERNAL_GET_CHAR(); - if (ABSL_PREDICT_FALSE(c < '1' || c > '9')) return false; + if (ABSL_PREDICT_FALSE(c < '1' || c > '9')) return nullptr; conv->arg_position = parse_digits(); assert(conv->arg_position > 0); - if (ABSL_PREDICT_FALSE(c != '$')) return false; + if (ABSL_PREDICT_FALSE(c != '$')) return nullptr; } ABSL_FORMAT_PARSER_INTERNAL_GET_CHAR(); @@ -129,10 +124,9 @@ conv->flags.basic = false; for (; c <= '0';) { - // FIXME: We might be able to speed this up reusing the kIds lookup table - // from above. - // It might require changing Flags to be a plain integer where we can |= a - // value. + // FIXME: We might be able to speed this up reusing the lookup table from + // above. It might require changing Flags to be a plain integer where we + // can |= a value. switch (c) { case '-': conv->flags.left = true; @@ -160,20 +154,20 @@ if (c >= '0') { int maybe_width = parse_digits(); if (!is_positional && c == '$') { - if (ABSL_PREDICT_FALSE(*next_arg != 0)) return false; + if (ABSL_PREDICT_FALSE(*next_arg != 0)) return nullptr; // Positional conversion. *next_arg = -1; conv->flags = Flags(); conv->flags.basic = true; - return ConsumeConversion<true>(src, conv, next_arg); + return ConsumeConversion<true>(original_pos, end, conv, next_arg); } conv->width.set_value(maybe_width); } else if (c == '*') { ABSL_FORMAT_PARSER_INTERNAL_GET_CHAR(); if (is_positional) { - if (ABSL_PREDICT_FALSE(c < '1' || c > '9')) return false; + if (ABSL_PREDICT_FALSE(c < '1' || c > '9')) return nullptr; conv->width.set_from_arg(parse_digits()); - if (ABSL_PREDICT_FALSE(c != '$')) return false; + if (ABSL_PREDICT_FALSE(c != '$')) return nullptr; ABSL_FORMAT_PARSER_INTERNAL_GET_CHAR(); } else { conv->width.set_from_arg(++*next_arg); @@ -188,9 +182,9 @@ } else if (c == '*') { ABSL_FORMAT_PARSER_INTERNAL_GET_CHAR(); if (is_positional) { - if (ABSL_PREDICT_FALSE(c < '1' || c > '9')) return false; + if (ABSL_PREDICT_FALSE(c < '1' || c > '9')) return nullptr; conv->precision.set_from_arg(parse_digits()); - if (c != '$') return false; + if (c != '$') return nullptr; ABSL_FORMAT_PARSER_INTERNAL_GET_CHAR(); } else { conv->precision.set_from_arg(++*next_arg); @@ -201,14 +195,14 @@ } } - std::int8_t id = kIds[static_cast<unsigned char>(c)]; + auto tag = GetTagForChar(c); - if (id < 0) { - if (ABSL_PREDICT_FALSE(id == none)) return false; + if (ABSL_PREDICT_FALSE(!tag.is_conv())) { + if (ABSL_PREDICT_FALSE(!tag.is_length())) return nullptr; // It is a length modifier. using str_format_internal::LengthMod; - LengthMod length_mod = LengthMod::FromId(static_cast<LM>(~id)); + LengthMod length_mod = tag.as_length(); ABSL_FORMAT_PARSER_INTERNAL_GET_CHAR(); if (c == 'h' && length_mod.id() == LengthMod::h) { conv->length_mod = LengthMod::FromId(LengthMod::hh); @@ -219,25 +213,24 @@ } else { conv->length_mod = length_mod; } - id = kIds[static_cast<unsigned char>(c)]; - if (ABSL_PREDICT_FALSE(id < 0)) return false; + tag = GetTagForChar(c); + if (ABSL_PREDICT_FALSE(!tag.is_conv())) return nullptr; } assert(CheckFastPathSetting(*conv)); (void)(&CheckFastPathSetting); - conv->conv = ConversionChar::FromId(static_cast<CC>(id)); + conv->conv = tag.as_conv(); if (!is_positional) conv->arg_position = ++*next_arg; - *src = string_view(pos, end - pos); - return true; + return pos; } } // namespace -bool ConsumeUnboundConversion(string_view *src, UnboundConversion *conv, - int *next_arg) { - if (*next_arg < 0) return ConsumeConversion<true>(src, conv, next_arg); - return ConsumeConversion<false>(src, conv, next_arg); +const char *ConsumeUnboundConversion(const char *p, const char *end, + UnboundConversion *conv, int *next_arg) { + if (*next_arg < 0) return ConsumeConversion<true>(p, end, conv, next_arg); + return ConsumeConversion<false>(p, end, conv, next_arg); } struct ParsedFormatBase::ParsedFormatConsumer {
diff --git a/absl/strings/internal/str_format/parser.h b/absl/strings/internal/str_format/parser.h index 1022f06..b7614a0 100644 --- a/absl/strings/internal/str_format/parser.h +++ b/absl/strings/internal/str_format/parser.h
@@ -63,17 +63,45 @@ ConversionChar conv; }; -// Consume conversion spec prefix (not including '%') of '*src' if valid. +// Consume conversion spec prefix (not including '%') of [p, end) if valid. // Examples of valid specs would be e.g.: "s", "d", "-12.6f". -// If valid, the front of src is advanced such that src becomes the -// part following the conversion spec, and the spec part is broken down and -// returned in 'conv'. -// If invalid, returns false and leaves 'src' unmodified. -// For example: -// Given "d9", returns "d", and leaves src="9", -// Given "!", returns "" and leaves src="!". -bool ConsumeUnboundConversion(string_view* src, UnboundConversion* conv, - int* next_arg); +// If valid, it returns the first character following the conversion spec, +// and the spec part is broken down and returned in 'conv'. +// If invalid, returns nullptr. +const char* ConsumeUnboundConversion(const char* p, const char* end, + UnboundConversion* conv, int* next_arg); + +// Helper tag class for the table below. +// It allows fast `char -> ConversionChar/LengthMod` checking and conversions. +class ConvTag { + public: + constexpr ConvTag(ConversionChar::Id id) : tag_(id) {} // NOLINT + // We invert the length modifiers to make them negative so that we can easily + // test for them. + constexpr ConvTag(LengthMod::Id id) : tag_(~id) {} // NOLINT + // Everything else is -128, which is negative to make is_conv() simpler. + constexpr ConvTag() : tag_(-128) {} + + bool is_conv() const { return tag_ >= 0; } + bool is_length() const { return tag_ < 0 && tag_ != -128; } + ConversionChar as_conv() const { + assert(is_conv()); + return ConversionChar::FromId(static_cast<ConversionChar::Id>(tag_)); + } + LengthMod as_length() const { + assert(is_length()); + return LengthMod::FromId(static_cast<LengthMod::Id>(~tag_)); + } + + private: + std::int8_t tag_; +}; + +extern const ConvTag kTags[256]; +// Keep a single table for all the conversion chars and length modifiers. +inline ConvTag GetTagForChar(char c) { + return kTags[static_cast<unsigned char>(c)]; +} // Parse the format string provided in 'src' and pass the identified items into // 'consumer'. @@ -88,51 +116,53 @@ template <typename Consumer> bool ParseFormatString(string_view src, Consumer consumer) { int next_arg = 0; - while (!src.empty()) { - const char* percent = - static_cast<const char*>(memchr(src.data(), '%', src.size())); + const char* p = src.data(); + const char* const end = p + src.size(); + while (p != end) { + const char* percent = static_cast<const char*>(memchr(p, '%', end - p)); if (!percent) { // We found the last substring. - return consumer.Append(src); + return consumer.Append(string_view(p, end - p)); } // We found a percent, so push the text run then process the percent. - size_t percent_loc = percent - src.data(); - if (!consumer.Append(string_view(src.data(), percent_loc))) return false; - if (percent + 1 >= src.data() + src.size()) return false; - - UnboundConversion conv; - - switch (percent[1]) { - case '%': - if (!consumer.Append("%")) return false; - src.remove_prefix(percent_loc + 2); - continue; - -#define PARSER_CASE(ch) \ - case #ch[0]: \ - src.remove_prefix(percent_loc + 2); \ - conv.conv = ConversionChar::FromId(ConversionChar::ch); \ - conv.arg_position = ++next_arg; \ - break; - ABSL_CONVERSION_CHARS_EXPAND_(PARSER_CASE, ); -#undef PARSER_CASE - - default: - src.remove_prefix(percent_loc + 1); - if (!ConsumeUnboundConversion(&src, &conv, &next_arg)) return false; - break; - } - if (next_arg == 0) { - // This indicates an error in the format std::string. - // The only way to get next_arg == 0 is to have a positional argument - // first which sets next_arg to -1 and then a non-positional argument - // which does ++next_arg. - // Checking here seems to be the cheapeast place to do it. + if (ABSL_PREDICT_FALSE(!consumer.Append(string_view(p, percent - p)))) { return false; } - if (!consumer.ConvertOne( - conv, string_view(percent + 1, src.data() - (percent + 1)))) { - return false; + if (ABSL_PREDICT_FALSE(percent + 1 >= end)) return false; + + auto tag = GetTagForChar(percent[1]); + if (tag.is_conv()) { + if (ABSL_PREDICT_FALSE(next_arg < 0)) { + // This indicates an error in the format std::string. + // The only way to get `next_arg < 0` here is to have a positional + // argument first which sets next_arg to -1 and then a non-positional + // argument. + return false; + } + p = percent + 2; + + // Keep this case separate from the one below. + // ConvertOne is more efficient when the compiler can see that the `basic` + // flag is set. + UnboundConversion conv; + conv.conv = tag.as_conv(); + conv.arg_position = ++next_arg; + if (ABSL_PREDICT_FALSE( + !consumer.ConvertOne(conv, string_view(percent + 1, 1)))) { + return false; + } + } else if (percent[1] != '%') { + UnboundConversion conv; + p = ConsumeUnboundConversion(percent + 1, end, &conv, &next_arg); + if (ABSL_PREDICT_FALSE(p == nullptr)) return false; + if (ABSL_PREDICT_FALSE(!consumer.ConvertOne( + conv, string_view(percent + 1, p - (percent + 1))))) { + return false; + } + } else { + if (ABSL_PREDICT_FALSE(!consumer.Append("%"))) return false; + p = percent + 2; + continue; } } return true;
diff --git a/absl/strings/internal/str_format/parser_test.cc b/absl/strings/internal/str_format/parser_test.cc index ff70575..6d35609 100644 --- a/absl/strings/internal/str_format/parser_test.cc +++ b/absl/strings/internal/str_format/parser_test.cc
@@ -1,6 +1,8 @@ #include "absl/strings/internal/str_format/parser.h" #include <string.h> + +#include "gmock/gmock.h" #include "gtest/gtest.h" #include "absl/base/macros.h" @@ -9,6 +11,8 @@ namespace { +using testing::Pair; + TEST(LengthModTest, Names) { struct Expectation { int line; @@ -63,20 +67,21 @@ class ConsumeUnboundConversionTest : public ::testing::Test { public: - typedef UnboundConversion Props; - string_view Consume(string_view* src) { + std::pair<string_view, string_view> Consume(string_view src) { int next = 0; - const char* prev_begin = src->data(); o = UnboundConversion(); // refresh - ConsumeUnboundConversion(src, &o, &next); - return {prev_begin, static_cast<size_t>(src->data() - prev_begin)}; + const char* p = ConsumeUnboundConversion( + src.data(), src.data() + src.size(), &o, &next); + if (!p) return {{}, src}; + return {string_view(src.data(), p - src.data()), + string_view(p, src.data() + src.size() - p)}; } bool Run(const char *fmt, bool force_positional = false) { - string_view src = fmt; int next = force_positional ? -1 : 0; o = UnboundConversion(); // refresh - return ConsumeUnboundConversion(&src, &o, &next) && src.empty(); + return ConsumeUnboundConversion(fmt, fmt + strlen(fmt), &o, &next) == + fmt + strlen(fmt); } UnboundConversion o; }; @@ -104,11 +109,7 @@ }; for (const auto& e : kExpect) { SCOPED_TRACE(e.line); - string_view src = e.src; - EXPECT_EQ(e.src, src); - string_view out = Consume(&src); - EXPECT_EQ(e.out, out); - EXPECT_EQ(e.src_post, src); + EXPECT_THAT(Consume(e.src), Pair(e.out, e.src_post)); } }
diff --git a/absl/strings/numbers.cc b/absl/strings/numbers.cc index 558c339..38d1486 100644 --- a/absl/strings/numbers.cc +++ b/absl/strings/numbers.cc
@@ -54,7 +54,7 @@ // not all non-whitespace characters consumed return false; } - // from_chars() with DR 3801's current wording will return max() on + // from_chars() with DR 3081's current wording will return max() on // overflow. SimpleAtof returns infinity instead. if (result.ec == std::errc::result_out_of_range) { if (*out > 1.0) { @@ -80,7 +80,7 @@ // not all non-whitespace characters consumed return false; } - // from_chars() with DR 3801's current wording will return max() on + // from_chars() with DR 3081's current wording will return max() on // overflow. SimpleAtod returns infinity instead. if (result.ec == std::errc::result_out_of_range) { if (*out > 1.0) {
diff --git a/absl/strings/str_split_test.cc b/absl/strings/str_split_test.cc index 4b8e7d6..02f27bc 100644 --- a/absl/strings/str_split_test.cc +++ b/absl/strings/str_split_test.cc
@@ -71,8 +71,8 @@ // namespaces just like callers will need to use. TEST(Split, APIExamples) { { - // Passes std::string delimiter. Assumes the default of Literal. - std::vector<std::string> v = absl::StrSplit("a,b,c", ','); + // Passes std::string delimiter. Assumes the default of ByString. + std::vector<std::string> v = absl::StrSplit("a,b,c", ","); // NOLINT EXPECT_THAT(v, ElementsAre("a", "b", "c")); // Equivalent to... @@ -97,17 +97,6 @@ } { - // Same as above, but using std::string - std::vector<std::string> v = absl::StrSplit("a,b,c", ','); - EXPECT_THAT(v, ElementsAre("a", "b", "c")); - - // Equivalent to... - using absl::ByChar; - v = absl::StrSplit("a,b,c", ByChar(',')); - EXPECT_THAT(v, ElementsAre("a", "b", "c")); - } - - { // Uses the Literal std::string "=>" as the delimiter. const std::vector<std::string> v = absl::StrSplit("a=>b=>c", "=>"); EXPECT_THAT(v, ElementsAre("a", "b", "c")); @@ -797,7 +786,7 @@ } // -// Tests for Literal +// Tests for ByString // // Tests using any delimiter that represents a single comma. @@ -817,7 +806,7 @@ EXPECT_FALSE(IsFoundAt(";", d, -1)); } -TEST(Delimiter, Literal) { +TEST(Delimiter, ByString) { using absl::ByString; TestComma(ByString(","));
diff --git a/absl/synchronization/BUILD.bazel b/absl/synchronization/BUILD.bazel index 5e69847..67da9d4 100644 --- a/absl/synchronization/BUILD.bazel +++ b/absl/synchronization/BUILD.bazel
@@ -17,6 +17,7 @@ load( "//absl:copts/configure_copts.bzl", "ABSL_DEFAULT_COPTS", + "ABSL_DEFAULT_LINKOPTS", "ABSL_TEST_COPTS", ) @@ -34,6 +35,7 @@ "internal/graphcycles.h", ], copts = ABSL_DEFAULT_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, visibility = [ "//absl:__subpackages__", ], @@ -72,7 +74,7 @@ linkopts = select({ "//absl:windows": [], "//conditions:default": ["-pthread"], - }), + }) + ABSL_DEFAULT_LINKOPTS, deps = [ ":graphcycles_internal", "//absl/base", @@ -92,9 +94,7 @@ size = "small", srcs = ["barrier_test.cc"], copts = ABSL_TEST_COPTS, - tags = [ - "no_test_wasm", - ], + linkopts = ABSL_DEFAULT_LINKOPTS, deps = [ ":synchronization", "//absl/time", @@ -107,9 +107,7 @@ size = "small", srcs = ["blocking_counter_test.cc"], copts = ABSL_TEST_COPTS, - tags = [ - "no_test_wasm", - ], + linkopts = ABSL_DEFAULT_LINKOPTS, deps = [ ":synchronization", "//absl/time", @@ -122,6 +120,7 @@ size = "medium", srcs = ["internal/graphcycles_test.cc"], copts = ABSL_TEST_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, deps = [ ":graphcycles_internal", "//absl/base", @@ -134,6 +133,7 @@ name = "graphcycles_benchmark", srcs = ["internal/graphcycles_benchmark.cc"], copts = ABSL_TEST_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, tags = [ "benchmark", ], @@ -148,6 +148,7 @@ name = "thread_pool", testonly = 1, hdrs = ["internal/thread_pool.h"], + linkopts = ABSL_DEFAULT_LINKOPTS, visibility = [ "//absl:__subpackages__", ], @@ -162,6 +163,7 @@ size = "large", srcs = ["mutex_test.cc"], copts = ABSL_TEST_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, shard_count = 25, deps = [ ":synchronization", @@ -179,6 +181,7 @@ testonly = 1, srcs = ["mutex_benchmark.cc"], copts = ABSL_TEST_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, visibility = [ "//absl/synchronization:__pkg__", ], @@ -195,6 +198,7 @@ name = "mutex_benchmark", testonly = 1, copts = ABSL_DEFAULT_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, visibility = ["//visibility:private"], deps = [ ":mutex_benchmark_common", @@ -206,6 +210,7 @@ size = "small", srcs = ["notification_test.cc"], copts = ABSL_TEST_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, deps = [ ":synchronization", "//absl/time", @@ -218,6 +223,7 @@ testonly = 1, srcs = ["internal/per_thread_sem_test.cc"], copts = ABSL_TEST_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, deps = [ ":synchronization", "//absl/base", @@ -232,7 +238,7 @@ name = "per_thread_sem_test", size = "medium", copts = ABSL_TEST_COPTS, - tags = ["no_test_wasm"], + linkopts = ABSL_DEFAULT_LINKOPTS, deps = [ ":per_thread_sem_test_common", ":synchronization", @@ -249,6 +255,7 @@ "lifetime_test.cc", ], copts = ABSL_TEST_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, tags = ["no_test_ios_x86_64"], deps = [ ":synchronization",
diff --git a/absl/synchronization/CMakeLists.txt b/absl/synchronization/CMakeLists.txt index 68473b7..6fdbcb2 100644 --- a/absl/synchronization/CMakeLists.txt +++ b/absl/synchronization/CMakeLists.txt
@@ -64,6 +64,7 @@ absl::stacktrace absl::symbolize absl::time + Threads::Threads PUBLIC ) @@ -112,6 +113,8 @@ thread_pool HDRS "internal/thread_pool.h" + COPTS + ${ABSL_DEFAULT_COPTS} DEPS absl::synchronization absl::core_headers @@ -191,5 +194,4 @@ absl::synchronization absl::base absl::core_headers - Threads::Threads )
diff --git a/absl/synchronization/internal/waiter.cc b/absl/synchronization/internal/waiter.cc index 74b0965..f17ea56 100644 --- a/absl/synchronization/internal/waiter.cc +++ b/absl/synchronization/internal/waiter.cc
@@ -40,6 +40,8 @@ #include <atomic> #include <cassert> #include <cstdint> +#include <new> +#include <type_traits> #include "absl/base/internal/raw_logging.h" #include "absl/base/internal/thread_identity.h" @@ -328,6 +330,43 @@ #elif ABSL_WAITER_MODE == ABSL_WAITER_MODE_WIN32 +class Waiter::WinHelper { + public: + static SRWLOCK *GetLock(Waiter *w) { + return reinterpret_cast<SRWLOCK *>(&w->mu_storage_); + } + + static CONDITION_VARIABLE *GetCond(Waiter *w) { + return reinterpret_cast<CONDITION_VARIABLE *>(&w->cv_storage_); + } + + static_assert(sizeof(SRWLOCK) == sizeof(Waiter::SRWLockStorage), + "SRWLockStorage does not have the same size as SRWLOCK"); + static_assert( + alignof(SRWLOCK) == alignof(Waiter::SRWLockStorage), + "SRWLockStorage does not have the same alignment as SRWLOCK"); + + static_assert(sizeof(CONDITION_VARIABLE) == + sizeof(Waiter::ConditionVariableStorage), + "ABSL_CONDITION_VARIABLE_STORAGE does not have the same size " + "as CONDITION_VARIABLE"); + static_assert(alignof(CONDITION_VARIABLE) == + alignof(Waiter::ConditionVariableStorage), + "ConditionVariableStorage does not have the same " + "alignment as CONDITION_VARIABLE"); + + // The SRWLOCK and CONDITION_VARIABLE types must be trivially constuctible + // and destructible because we never call their constructors or destructors. + static_assert(std::is_trivially_constructible<SRWLOCK>::value, + "The SRWLOCK type must be trivially constructible"); + static_assert(std::is_trivially_constructible<CONDITION_VARIABLE>::value, + "The CONDITION_VARIABLE type must be trivially constructible"); + static_assert(std::is_trivially_destructible<SRWLOCK>::value, + "The SRWLOCK type must be trivially destructible"); + static_assert(std::is_trivially_destructible<CONDITION_VARIABLE>::value, + "The CONDITION_VARIABLE type must be trivially destructible"); +}; + class LockHolder { public: explicit LockHolder(SRWLOCK* mu) : mu_(mu) { @@ -346,14 +385,19 @@ }; void Waiter::Init() { - InitializeSRWLock(&mu_); - InitializeConditionVariable(&cv_); + auto *mu = ::new (static_cast<void *>(&mu_storage_)) SRWLOCK; + auto *cv = ::new (static_cast<void *>(&cv_storage_)) CONDITION_VARIABLE; + InitializeSRWLock(mu); + InitializeConditionVariable(cv); waiter_count_.store(0, std::memory_order_relaxed); wakeup_count_.store(0, std::memory_order_relaxed); } bool Waiter::Wait(KernelTimeout t) { - LockHolder h(&mu_); + SRWLOCK *mu = WinHelper::GetLock(this); + CONDITION_VARIABLE *cv = WinHelper::GetCond(this); + + LockHolder h(mu); waiter_count_.fetch_add(1, std::memory_order_relaxed); // Loop until we find a wakeup to consume or timeout. @@ -371,8 +415,7 @@ } // No wakeups available, time to wait. - if (!SleepConditionVariableSRW( - &cv_, &mu_, t.InMillisecondsFromNow(), 0)) { + if (!SleepConditionVariableSRW(cv, mu, t.InMillisecondsFromNow(), 0)) { // GetLastError() returns a Win32 DWORD, but we assign to // unsigned long to simplify the ABSL_RAW_LOG case below. The uniform // initialization guarantees this is not a narrowing conversion. @@ -399,11 +442,11 @@ return; } // Potentially a waker. Take the lock and check again. - LockHolder h(&mu_); + LockHolder h(WinHelper::GetLock(this)); if (waiter_count_.load(std::memory_order_relaxed) == 0) { return; } - WakeConditionVariable(&cv_); + WakeConditionVariable(WinHelper::GetCond(this)); } #else
diff --git a/absl/synchronization/internal/waiter.h b/absl/synchronization/internal/waiter.h index 66b4beb..a3e3124 100644 --- a/absl/synchronization/internal/waiter.h +++ b/absl/synchronization/internal/waiter.h
@@ -18,9 +18,7 @@ #include "absl/base/config.h" -#ifdef _WIN32 -#include <windows.h> -#else +#ifndef _WIN32 #include <pthread.h> #endif @@ -123,8 +121,20 @@ // primivitives. We are using SRWLOCK and CONDITION_VARIABLE // because they don't require a destructor to release system // resources. - SRWLOCK mu_; - CONDITION_VARIABLE cv_; + // + // However, we can't include Windows.h in our headers, so we use aligned + // storage buffers to define the storage. + using SRWLockStorage = + typename std::aligned_storage<sizeof(void*), alignof(void*)>::type; + using ConditionVariableStorage = + typename std::aligned_storage<sizeof(void*), alignof(void*)>::type; + + // WinHelper - Used to define utilities for accessing the lock and + // condition variable storage once the types are complete. + class WinHelper; + + SRWLockStorage mu_storage_; + ConditionVariableStorage cv_storage_; std::atomic<int> waiter_count_; std::atomic<int> wakeup_count_;
diff --git a/absl/time/BUILD.bazel b/absl/time/BUILD.bazel index a94be65..55e83a8 100644 --- a/absl/time/BUILD.bazel +++ b/absl/time/BUILD.bazel
@@ -17,6 +17,7 @@ load( "//absl:copts/configure_copts.bzl", "ABSL_DEFAULT_COPTS", + "ABSL_DEFAULT_LINKOPTS", "ABSL_TEST_COPTS", ) @@ -41,6 +42,7 @@ "time.h", ], copts = ABSL_DEFAULT_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, deps = [ "//absl/base", "//absl/base:core_headers", @@ -60,6 +62,7 @@ ], hdrs = ["internal/test_util.h"], copts = ABSL_DEFAULT_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, visibility = [ "//absl/time:__pkg__", ], @@ -82,6 +85,7 @@ "time_zone_test.cc", ], copts = ABSL_TEST_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, deps = [ ":test_util", ":time", @@ -103,6 +107,7 @@ "time_benchmark.cc", ], copts = ABSL_TEST_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, tags = [ "benchmark", ],
diff --git a/absl/time/internal/cctz/BUILD.bazel b/absl/time/internal/cctz/BUILD.bazel index 903499b..b05c234 100644 --- a/absl/time/internal/cctz/BUILD.bazel +++ b/absl/time/internal/cctz/BUILD.bazel
@@ -16,6 +16,20 @@ licenses(["notice"]) # Apache License +config_setting( + name = "osx", + constraint_values = [ + "@bazel_tools//platforms:osx", + ], +) + +config_setting( + name = "ios", + constraint_values = [ + "@bazel_tools//platforms:ios", + ], +) + ### libraries cc_library( @@ -62,6 +76,15 @@ "include/cctz/time_zone.h", "include/cctz/zone_info_source.h", ], + linkopts = select({ + ":osx": [ + "-framework Foundation", + ], + ":ios": [ + "-framework Foundation", + ], + "//conditions:default": [], + }), visibility = ["//visibility:public"], deps = [":civil_time"], ) @@ -87,7 +110,6 @@ "no_test_android_arm", "no_test_android_arm64", "no_test_android_x86", - "no_test_wasm", ], deps = [ ":civil_time", @@ -106,7 +128,6 @@ "no_test_android_arm", "no_test_android_arm64", "no_test_android_x86", - "no_test_wasm", ], deps = [ ":civil_time",
diff --git a/absl/time/internal/cctz/include/cctz/civil_time_detail.h b/absl/time/internal/cctz/include/cctz/civil_time_detail.h index a5923f1..bb191b3 100644 --- a/absl/time/internal/cctz/include/cctz/civil_time_detail.h +++ b/absl/time/internal/cctz/include/cctz/civil_time_detail.h
@@ -21,7 +21,7 @@ #include <type_traits> // Disable constexpr support unless we are in C++14 mode. -#if __cpp_constexpr >= 201304 || _MSC_VER >= 1910 +#if __cpp_constexpr >= 201304 || (defined(_MSC_VER) && _MSC_VER >= 1910) #define CONSTEXPR_D constexpr // data #define CONSTEXPR_F constexpr // function #define CONSTEXPR_M constexpr // member
diff --git a/absl/time/internal/cctz/src/civil_time_test.cc b/absl/time/internal/cctz/src/civil_time_test.cc index e590ee3..dc7e5a1 100644 --- a/absl/time/internal/cctz/src/civil_time_test.cc +++ b/absl/time/internal/cctz/src/civil_time_test.cc
@@ -37,7 +37,7 @@ } // namespace -#if __cpp_constexpr >= 201304 || _MSC_VER >= 1910 +#if __cpp_constexpr >= 201304 || (defined(_MSC_VER) && _MSC_VER >= 1910) // Construction constexpr tests TEST(CivilTime, Normal) { @@ -319,7 +319,7 @@ constexpr int yd = get_yearday(cd); static_assert(yd == 28, "YearDay"); } -#endif // __cpp_constexpr >= 201304 || _MSC_VER >= 1910 +#endif // __cpp_constexpr >= 201304 || (defined(_MSC_VER) && _MSC_VER >= 1910) // The remaining tests do not use constexpr.
diff --git a/absl/time/internal/cctz/src/time_zone_lookup.cc b/absl/time/internal/cctz/src/time_zone_lookup.cc index fd04e2d..3c53dd1 100644 --- a/absl/time/internal/cctz/src/time_zone_lookup.cc +++ b/absl/time/internal/cctz/src/time_zone_lookup.cc
@@ -16,13 +16,14 @@ #if defined(__ANDROID__) #include <sys/system_properties.h> -#if __ANDROID_API__ >= 21 +#if defined(__ANDROID_API__) && __ANDROID_API__ >= 21 #include <dlfcn.h> #endif #endif #if defined(__APPLE__) #include <CoreFoundation/CFTimeZone.h> +#include <vector> #endif #include <cstdlib> @@ -36,7 +37,7 @@ namespace time_internal { namespace cctz { -#if defined(__ANDROID__) && __ANDROID_API__ >= 21 +#if defined(__ANDROID__) && defined(__ANDROID_API__) && __ANDROID_API__ >= 21 namespace { // Android 'L' removes __system_property_get() from the NDK, however // it is still a hidden symbol in libc so we use dlsym() to access it. @@ -121,25 +122,33 @@ time_zone local_time_zone() { const char* zone = ":localtime"; +#if defined(__ANDROID__) + char sysprop[PROP_VALUE_MAX]; + if (__system_property_get("persist.sys.timezone", sysprop) > 0) { + zone = sysprop; + } +#endif +#if defined(__APPLE__) + std::vector<char> buffer; + CFTimeZoneRef tz_default = CFTimeZoneCopyDefault(); + if (CFStringRef tz_name = CFTimeZoneGetName(tz_default)) { + CFStringEncoding encoding = kCFStringEncodingUTF8; + CFIndex length = CFStringGetLength(tz_name); + buffer.resize(CFStringGetMaximumSizeForEncoding(length, encoding) + 1); + if (CFStringGetCString(tz_name, &buffer[0], buffer.size(), encoding)) { + zone = &buffer[0]; + } + } + CFRelease(tz_default); +#endif // Allow ${TZ} to override to default zone. char* tz_env = nullptr; #if defined(_MSC_VER) _dupenv_s(&tz_env, nullptr, "TZ"); -#elif defined(__APPLE__) - CFTimeZoneRef system_time_zone = CFTimeZoneCopyDefault(); - CFStringRef tz_name = CFTimeZoneGetName(system_time_zone); - tz_env = strdup(CFStringGetCStringPtr(tz_name, CFStringGetSystemEncoding())); - CFRelease(system_time_zone); #else tz_env = std::getenv("TZ"); #endif -#if defined(__ANDROID__) - char sysprop[PROP_VALUE_MAX]; - if (tz_env == nullptr) - if (__system_property_get("persist.sys.timezone", sysprop) > 0) - tz_env = sysprop; -#endif if (tz_env) zone = tz_env; // We only support the "[:]<zone-name>" form. @@ -163,8 +172,6 @@ #if defined(_MSC_VER) free(localtime_env); free(tz_env); -#elif defined(__APPLE__) - free(tz_env); #endif time_zone tz;
diff --git a/absl/time/internal/cctz/src/tzfile.h b/absl/time/internal/cctz/src/tzfile.h index 4485ba5..ef3feff 100644 --- a/absl/time/internal/cctz/src/tzfile.h +++ b/absl/time/internal/cctz/src/tzfile.h
@@ -33,6 +33,9 @@ #define TZDEFRULES "posixrules" #endif /* !defined TZDEFRULES */ + +/* See Internet RFC 8536 for more details about the following format. */ + /* ** Each file begins with. . . */
diff --git a/absl/time/internal/cctz/testdata/version b/absl/time/internal/cctz/testdata/version index 63f5800..149d790 100644 --- a/absl/time/internal/cctz/testdata/version +++ b/absl/time/internal/cctz/testdata/version
@@ -1 +1 @@ -2018i +2019a
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Metlakatla b/absl/time/internal/cctz/testdata/zoneinfo/America/Metlakatla index 85a7e16..1e94be3 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Metlakatla +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Metlakatla Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Gaza b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Gaza index cf54deb..32b4ed6 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Gaza +++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Gaza Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Hebron b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Hebron index 09c876a..0ed8b0d 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Hebron +++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Hebron Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Jerusalem b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Jerusalem index 2d14c99..93e9f19 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Jerusalem +++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Jerusalem Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tel_Aviv b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tel_Aviv index 2d14c99..93e9f19 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tel_Aviv +++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tel_Aviv Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/UCT b/absl/time/internal/cctz/testdata/zoneinfo/Etc/UCT index a88c4b6..5583f5b 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Etc/UCT +++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/UCT Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Israel b/absl/time/internal/cctz/testdata/zoneinfo/Israel index 2d14c99..93e9f19 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Israel +++ b/absl/time/internal/cctz/testdata/zoneinfo/Israel Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/UCT b/absl/time/internal/cctz/testdata/zoneinfo/UCT index a88c4b6..5583f5b 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/UCT +++ b/absl/time/internal/cctz/testdata/zoneinfo/UCT Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/iso3166.tab b/absl/time/internal/cctz/testdata/zoneinfo/iso3166.tab index 4e4a5c3..a4ff61a 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/iso3166.tab +++ b/absl/time/internal/cctz/testdata/zoneinfo/iso3166.tab
@@ -9,7 +9,7 @@ # All text uses UTF-8 encoding. The columns of the table are as follows: # # 1. ISO 3166-1 alpha-2 country code, current as of -# ISO 3166-1 N905 (2016-11-15). See: Updates on ISO 3166-1 +# ISO 3166-1 N976 (2018-11-06). See: Updates on ISO 3166-1 # https://isotc.iso.org/livelink/livelink/Open/16944257 # 2. The usual English name for the coded region, # chosen so that alphabetic sorting of subsets produces helpful lists. @@ -166,7 +166,7 @@ MF St Martin (French) MG Madagascar MH Marshall Islands -MK Macedonia +MK North Macedonia ML Mali MM Myanmar (Burma) MN Mongolia @@ -235,7 +235,7 @@ SV El Salvador SX St Maarten (Dutch) SY Syria -SZ Swaziland +SZ Eswatini (Swaziland) TC Turks & Caicos Is TD Chad TF French Southern & Antarctic Lands
diff --git a/absl/time/time_test.cc b/absl/time/time_test.cc index 74148d5..4d791f4 100644 --- a/absl/time/time_test.cc +++ b/absl/time/time_test.cc
@@ -28,7 +28,7 @@ namespace { -#if GTEST_USES_SIMPLE_RE +#if defined(GTEST_USES_SIMPLE_RE) && GTEST_USES_SIMPLE_RE const char kZoneAbbrRE[] = ".*"; // just punt #else const char kZoneAbbrRE[] = "[A-Za-z]{3,4}|[-+][0-9]{2}([0-9]{2})?";
diff --git a/absl/types/BUILD.bazel b/absl/types/BUILD.bazel index 7da0003..a254871 100644 --- a/absl/types/BUILD.bazel +++ b/absl/types/BUILD.bazel
@@ -17,6 +17,7 @@ load( "//absl:copts/configure_copts.bzl", "ABSL_DEFAULT_COPTS", + "ABSL_DEFAULT_LINKOPTS", "ABSL_TEST_COPTS", "ABSL_EXCEPTIONS_FLAG", "ABSL_EXCEPTIONS_FLAG_LINKOPTS", @@ -30,6 +31,7 @@ name = "any", hdrs = ["any.h"], copts = ABSL_DEFAULT_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, deps = [ ":bad_any_cast", "//absl/base:config", @@ -43,6 +45,7 @@ name = "bad_any_cast", hdrs = ["bad_any_cast.h"], copts = ABSL_DEFAULT_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, deps = [ ":bad_any_cast_impl", "//absl/base:config", @@ -56,7 +59,7 @@ "bad_any_cast.h", ], copts = ABSL_EXCEPTIONS_FLAG + ABSL_DEFAULT_COPTS, - linkopts = ABSL_EXCEPTIONS_FLAG_LINKOPTS, + linkopts = ABSL_EXCEPTIONS_FLAG_LINKOPTS + ABSL_DEFAULT_LINKOPTS, visibility = ["//visibility:private"], deps = [ "//absl/base", @@ -71,7 +74,7 @@ "any_test.cc", ], copts = ABSL_TEST_COPTS + ABSL_EXCEPTIONS_FLAG, - linkopts = ABSL_EXCEPTIONS_FLAG_LINKOPTS, + linkopts = ABSL_EXCEPTIONS_FLAG_LINKOPTS + ABSL_DEFAULT_LINKOPTS, deps = [ ":any", "//absl/base", @@ -89,6 +92,7 @@ "any_test.cc", ], copts = ABSL_TEST_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, deps = [ ":any", "//absl/base", @@ -103,7 +107,7 @@ name = "any_exception_safety_test", srcs = ["any_exception_safety_test.cc"], copts = ABSL_TEST_COPTS + ABSL_EXCEPTIONS_FLAG, - linkopts = ABSL_EXCEPTIONS_FLAG_LINKOPTS, + linkopts = ABSL_EXCEPTIONS_FLAG_LINKOPTS + ABSL_DEFAULT_LINKOPTS, deps = [ ":any", "//absl/base:exception_safety_testing", @@ -113,8 +117,14 @@ cc_library( name = "span", - hdrs = ["span.h"], + srcs = [ + "internal/span.h", + ], + hdrs = [ + "span.h", + ], copts = ABSL_DEFAULT_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, deps = [ "//absl/algorithm", "//absl/base:core_headers", @@ -128,7 +138,7 @@ size = "small", srcs = ["span_test.cc"], copts = ABSL_TEST_COPTS + ABSL_EXCEPTIONS_FLAG, - linkopts = ABSL_EXCEPTIONS_FLAG_LINKOPTS, + linkopts = ABSL_EXCEPTIONS_FLAG_LINKOPTS + ABSL_DEFAULT_LINKOPTS, deps = [ ":span", "//absl/base:config", @@ -147,6 +157,7 @@ size = "small", srcs = ["span_test.cc"], copts = ABSL_TEST_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, deps = [ ":span", "//absl/base:config", @@ -162,11 +173,13 @@ cc_library( name = "optional", - srcs = ["optional.cc"], + srcs = ["internal/optional.h"], hdrs = ["optional.h"], copts = ABSL_DEFAULT_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, deps = [ ":bad_optional_access", + "//absl/base:base_internal", "//absl/base:config", "//absl/base:core_headers", "//absl/memory", @@ -180,7 +193,7 @@ srcs = ["bad_optional_access.cc"], hdrs = ["bad_optional_access.h"], copts = ABSL_DEFAULT_COPTS + ABSL_EXCEPTIONS_FLAG, - linkopts = ABSL_EXCEPTIONS_FLAG_LINKOPTS, + linkopts = ABSL_EXCEPTIONS_FLAG_LINKOPTS + ABSL_DEFAULT_LINKOPTS, deps = [ "//absl/base", "//absl/base:config", @@ -192,7 +205,7 @@ srcs = ["bad_variant_access.cc"], hdrs = ["bad_variant_access.h"], copts = ABSL_EXCEPTIONS_FLAG + ABSL_DEFAULT_COPTS, - linkopts = ABSL_EXCEPTIONS_FLAG_LINKOPTS, + linkopts = ABSL_EXCEPTIONS_FLAG_LINKOPTS + ABSL_DEFAULT_LINKOPTS, deps = [ "//absl/base", "//absl/base:config", @@ -206,7 +219,7 @@ "optional_test.cc", ], copts = ABSL_TEST_COPTS + ABSL_EXCEPTIONS_FLAG, - linkopts = ABSL_EXCEPTIONS_FLAG_LINKOPTS, + linkopts = ABSL_EXCEPTIONS_FLAG_LINKOPTS + ABSL_DEFAULT_LINKOPTS, deps = [ ":optional", "//absl/base", @@ -223,7 +236,7 @@ "optional_exception_safety_test.cc", ], copts = ABSL_TEST_COPTS + ABSL_EXCEPTIONS_FLAG, - linkopts = ABSL_EXCEPTIONS_FLAG_LINKOPTS, + linkopts = ABSL_EXCEPTIONS_FLAG_LINKOPTS + ABSL_DEFAULT_LINKOPTS, deps = [ ":optional", "//absl/base:exception_safety_testing", @@ -236,6 +249,7 @@ srcs = ["internal/variant.h"], hdrs = ["variant.h"], copts = ABSL_DEFAULT_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, deps = [ ":bad_variant_access", "//absl/base:base_internal", @@ -251,7 +265,7 @@ size = "small", srcs = ["variant_test.cc"], copts = ABSL_TEST_COPTS + ABSL_EXCEPTIONS_FLAG, - linkopts = ABSL_EXCEPTIONS_FLAG_LINKOPTS, + linkopts = ABSL_EXCEPTIONS_FLAG_LINKOPTS + ABSL_DEFAULT_LINKOPTS, deps = [ ":variant", "//absl/base:config", @@ -269,6 +283,7 @@ "variant_benchmark.cc", ], copts = ABSL_TEST_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, tags = ["benchmark"], deps = [ ":variant", @@ -284,7 +299,7 @@ "variant_exception_safety_test.cc", ], copts = ABSL_TEST_COPTS + ABSL_EXCEPTIONS_FLAG, - linkopts = ABSL_EXCEPTIONS_FLAG_LINKOPTS, + linkopts = ABSL_EXCEPTIONS_FLAG_LINKOPTS + ABSL_DEFAULT_LINKOPTS, deps = [ ":variant", "//absl/base:config",
diff --git a/absl/types/CMakeLists.txt b/absl/types/CMakeLists.txt index 8afde46..9da94eb 100644 --- a/absl/types/CMakeLists.txt +++ b/absl/types/CMakeLists.txt
@@ -114,6 +114,8 @@ span HDRS "span.h" + SRCS + "internal/span.h" COPTS ${ABSL_DEFAULT_COPTS} DEPS @@ -173,11 +175,12 @@ HDRS "optional.h" SRCS - "optional.cc" + "internal/optional.h" COPTS ${ABSL_DEFAULT_COPTS} DEPS absl::bad_optional_access + absl::base_internal absl::config absl::core_headers absl::memory @@ -297,7 +300,8 @@ ) # TODO(cohenjon,zhangxy) Figure out why this test is failing on gcc 4.8 -if(CMAKE_COMPILER_IS_GNUCC AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 4.9) +if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.9) +else() absl_cc_test( NAME variant_exception_safety_test
diff --git a/absl/types/any_test.cc b/absl/types/any_test.cc index a6351bf..8710472 100644 --- a/absl/types/any_test.cc +++ b/absl/types/any_test.cc
@@ -154,6 +154,14 @@ EXPECT_EQ(5, v.value); } +TEST(AnyTest, InPlaceConstructionVariableTemplate) { + const CopyOnly copy_only{}; + absl::any o(absl::in_place_type<IntMoveOnlyCopyOnly>, 5, MoveOnly(), + copy_only); + auto& v = absl::any_cast<IntMoveOnlyCopyOnly&>(o); + EXPECT_EQ(5, v.value); +} + TEST(AnyTest, InPlaceConstructionWithCV) { const CopyOnly copy_only{}; absl::any o(absl::in_place_type_t<const volatile IntMoveOnlyCopyOnly>(), 5, @@ -162,12 +170,26 @@ EXPECT_EQ(5, v.value); } +TEST(AnyTest, InPlaceConstructionWithCVVariableTemplate) { + const CopyOnly copy_only{}; + absl::any o(absl::in_place_type<const volatile IntMoveOnlyCopyOnly>, 5, + MoveOnly(), copy_only); + auto& v = absl::any_cast<IntMoveOnlyCopyOnly&>(o); + EXPECT_EQ(5, v.value); +} + TEST(AnyTest, InPlaceConstructionWithFunction) { absl::any o(absl::in_place_type_t<FunctionType>(), FunctionToEmplace); FunctionType*& construction_result = absl::any_cast<FunctionType*&>(o); EXPECT_EQ(&FunctionToEmplace, construction_result); } +TEST(AnyTest, InPlaceConstructionWithFunctionVariableTemplate) { + absl::any o(absl::in_place_type<FunctionType>, FunctionToEmplace); + auto& construction_result = absl::any_cast<FunctionType*&>(o); + EXPECT_EQ(&FunctionToEmplace, construction_result); +} + TEST(AnyTest, InPlaceConstructionWithArray) { ArrayType ar = {5, 42}; absl::any o(absl::in_place_type_t<ArrayType>(), ar); @@ -175,6 +197,13 @@ EXPECT_EQ(&ar[0], construction_result); } +TEST(AnyTest, InPlaceConstructionWithArrayVariableTemplate) { + ArrayType ar = {5, 42}; + absl::any o(absl::in_place_type<ArrayType>, ar); + auto& construction_result = absl::any_cast<DecayedArray&>(o); + EXPECT_EQ(&ar[0], construction_result); +} + TEST(AnyTest, InPlaceConstructionIlist) { const CopyOnly copy_only{}; absl::any o(absl::in_place_type_t<ListMoveOnlyCopyOnly>(), {1, 2, 3, 4}, @@ -184,6 +213,15 @@ EXPECT_EQ(expected_values, v.values); } +TEST(AnyTest, InPlaceConstructionIlistVariableTemplate) { + const CopyOnly copy_only{}; + absl::any o(absl::in_place_type<ListMoveOnlyCopyOnly>, {1, 2, 3, 4}, + MoveOnly(), copy_only); + auto& v = absl::any_cast<ListMoveOnlyCopyOnly&>(o); + std::vector<int> expected_values = {1, 2, 3, 4}; + EXPECT_EQ(expected_values, v.values); +} + TEST(AnyTest, InPlaceConstructionIlistWithCV) { const CopyOnly copy_only{}; absl::any o(absl::in_place_type_t<const volatile ListMoveOnlyCopyOnly>(), @@ -193,11 +231,25 @@ EXPECT_EQ(expected_values, v.values); } +TEST(AnyTest, InPlaceConstructionIlistWithCVVariableTemplate) { + const CopyOnly copy_only{}; + absl::any o(absl::in_place_type<const volatile ListMoveOnlyCopyOnly>, + {1, 2, 3, 4}, MoveOnly(), copy_only); + auto& v = absl::any_cast<ListMoveOnlyCopyOnly&>(o); + std::vector<int> expected_values = {1, 2, 3, 4}; + EXPECT_EQ(expected_values, v.values); +} + TEST(AnyTest, InPlaceNoArgs) { absl::any o(absl::in_place_type_t<int>{}); EXPECT_EQ(0, absl::any_cast<int&>(o)); } +TEST(AnyTest, InPlaceNoArgsVariableTemplate) { + absl::any o(absl::in_place_type<int>); + EXPECT_EQ(0, absl::any_cast<int&>(o)); +} + template <typename Enabler, typename T, typename... Args> struct CanEmplaceAnyImpl : std::false_type {}; @@ -501,7 +553,7 @@ InstanceTracker tracker_raii; { - absl::any o(absl::in_place_type_t<CopyableOnlyInstance>{}, 123); + absl::any o(absl::in_place_type<CopyableOnlyInstance>, 123); CopyableOnlyInstance* f1 = absl::any_cast<CopyableOnlyInstance>(&o); absl::any o2(o); @@ -622,7 +674,7 @@ } { - absl::any a(absl::in_place_type_t<int>{}); + absl::any a(absl::in_place_type<int>); ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast<float&>(a)); ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast<const float&>(a)); ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast<float&&>(absl::any{})); @@ -665,7 +717,7 @@ } { - absl::any src(absl::in_place_type_t<BadCopyable>{}); + absl::any src(absl::in_place_type<BadCopyable>); ABSL_ANY_TEST_EXPECT_BAD_COPY(absl::any{src}); } @@ -677,21 +729,21 @@ { BadCopyable bad; - absl::any target(absl::in_place_type_t<BadCopyable>{}); + absl::any target(absl::in_place_type<BadCopyable>); ABSL_ANY_TEST_EXPECT_BAD_COPY(target = bad); EXPECT_TRUE(target.has_value()); } { - absl::any src(absl::in_place_type_t<BadCopyable>{}); + absl::any src(absl::in_place_type<BadCopyable>); absl::any target; ABSL_ANY_TEST_EXPECT_BAD_COPY(target = src); EXPECT_FALSE(target.has_value()); } { - absl::any src(absl::in_place_type_t<BadCopyable>{}); - absl::any target(absl::in_place_type_t<BadCopyable>{}); + absl::any src(absl::in_place_type<BadCopyable>); + absl::any target(absl::in_place_type<BadCopyable>); ABSL_ANY_TEST_EXPECT_BAD_COPY(target = src); EXPECT_TRUE(target.has_value()); } @@ -707,7 +759,7 @@ { BadCopyable bad; - absl::any target(absl::in_place_type_t<int>{}); + absl::any target(absl::in_place_type<int>); ABSL_ANY_TEST_EXPECT_BAD_COPY(target.emplace<BadCopyable>(bad)); #if defined(ABSL_HAVE_STD_ANY) && defined(__GLIBCXX__) // libstdc++ std::any::emplace() implementation (as of 7.2) has a bug: if an
diff --git a/absl/types/internal/optional.h b/absl/types/internal/optional.h new file mode 100644 index 0000000..8acbda2 --- /dev/null +++ b/absl/types/internal/optional.h
@@ -0,0 +1,394 @@ +// Copyright 2017 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#ifndef ABSL_TYPES_INTERNAL_OPTIONAL_H_ +#define ABSL_TYPES_INTERNAL_OPTIONAL_H_ + +#include <functional> +#include <new> +#include <type_traits> +#include <utility> + +#include "absl/base/internal/inline_variable.h" +#include "absl/memory/memory.h" +#include "absl/meta/type_traits.h" +#include "absl/utility/utility.h" + +// ABSL_OPTIONAL_USE_INHERITING_CONSTRUCTORS +// +// Inheriting constructors is supported in GCC 4.8+, Clang 3.3+ and MSVC 2015. +// __cpp_inheriting_constructors is a predefined macro and a recommended way to +// check for this language feature, but GCC doesn't support it until 5.0 and +// Clang doesn't support it until 3.6. +// Also, MSVC 2015 has a bug: it doesn't inherit the constexpr template +// constructor. For example, the following code won't work on MSVC 2015 Update3: +// struct Base { +// int t; +// template <typename T> +// constexpr Base(T t_) : t(t_) {} +// }; +// struct Foo : Base { +// using Base::Base; +// } +// constexpr Foo foo(0); // doesn't work on MSVC 2015 +#if defined(__clang__) +#if __has_feature(cxx_inheriting_constructors) +#define ABSL_OPTIONAL_USE_INHERITING_CONSTRUCTORS 1 +#endif +#elif (defined(__GNUC__) && \ + (__GNUC__ > 4 || __GNUC__ == 4 && __GNUC_MINOR__ >= 8)) || \ + (__cpp_inheriting_constructors >= 200802) || \ + (defined(_MSC_VER) && _MSC_VER >= 1910) +#define ABSL_OPTIONAL_USE_INHERITING_CONSTRUCTORS 1 +#endif + +namespace absl { + +// Forward declaration +template <typename T> +class optional; + +namespace optional_internal { + +// This tag type is used as a constructor parameter type for `nullopt_t`. +struct init_t { + explicit init_t() = default; +}; + +struct empty_struct {}; + +// This class stores the data in optional<T>. +// It is specialized based on whether T is trivially destructible. +// This is the specialization for non trivially destructible type. +template <typename T, bool unused = std::is_trivially_destructible<T>::value> +class optional_data_dtor_base { + struct dummy_type { + static_assert(sizeof(T) % sizeof(empty_struct) == 0, ""); + // Use an array to avoid GCC 6 placement-new warning. + empty_struct data[sizeof(T) / sizeof(empty_struct)]; + }; + + protected: + // Whether there is data or not. + bool engaged_; + // Data storage + union { + dummy_type dummy_; + T data_; + }; + + void destruct() noexcept { + if (engaged_) { + data_.~T(); + engaged_ = false; + } + } + + // dummy_ must be initialized for constexpr constructor. + constexpr optional_data_dtor_base() noexcept : engaged_(false), dummy_{{}} {} + + template <typename... Args> + constexpr explicit optional_data_dtor_base(in_place_t, Args&&... args) + : engaged_(true), data_(absl::forward<Args>(args)...) {} + + ~optional_data_dtor_base() { destruct(); } +}; + +// Specialization for trivially destructible type. +template <typename T> +class optional_data_dtor_base<T, true> { + struct dummy_type { + static_assert(sizeof(T) % sizeof(empty_struct) == 0, ""); + // Use array to avoid GCC 6 placement-new warning. + empty_struct data[sizeof(T) / sizeof(empty_struct)]; + }; + + protected: + // Whether there is data or not. + bool engaged_; + // Data storage + union { + dummy_type dummy_; + T data_; + }; + void destruct() noexcept { engaged_ = false; } + + // dummy_ must be initialized for constexpr constructor. + constexpr optional_data_dtor_base() noexcept : engaged_(false), dummy_{{}} {} + + template <typename... Args> + constexpr explicit optional_data_dtor_base(in_place_t, Args&&... args) + : engaged_(true), data_(absl::forward<Args>(args)...) {} +}; + +template <typename T> +class optional_data_base : public optional_data_dtor_base<T> { + protected: + using base = optional_data_dtor_base<T>; +#ifdef ABSL_OPTIONAL_USE_INHERITING_CONSTRUCTORS + using base::base; +#else + optional_data_base() = default; + + template <typename... Args> + constexpr explicit optional_data_base(in_place_t t, Args&&... args) + : base(t, absl::forward<Args>(args)...) {} +#endif + + template <typename... Args> + void construct(Args&&... args) { + // Use dummy_'s address to work around casting cv-qualified T* to void*. + ::new (static_cast<void*>(&this->dummy_)) T(std::forward<Args>(args)...); + this->engaged_ = true; + } + + template <typename U> + void assign(U&& u) { + if (this->engaged_) { + this->data_ = std::forward<U>(u); + } else { + construct(std::forward<U>(u)); + } + } +}; + +// TODO(absl-team): Add another class using +// std::is_trivially_move_constructible trait when available to match +// http://cplusplus.github.io/LWG/lwg-defects.html#2900, for types that +// have trivial move but nontrivial copy. +// Also, we should be checking is_trivially_copyable here, which is not +// supported now, so we use is_trivially_* traits instead. +template <typename T, + bool unused = absl::is_trivially_copy_constructible<T>::value&& + absl::is_trivially_copy_assignable<typename std::remove_cv< + T>::type>::value&& std::is_trivially_destructible<T>::value> +class optional_data; + +// Trivially copyable types +template <typename T> +class optional_data<T, true> : public optional_data_base<T> { + protected: +#ifdef ABSL_OPTIONAL_USE_INHERITING_CONSTRUCTORS + using optional_data_base<T>::optional_data_base; +#else + optional_data() = default; + + template <typename... Args> + constexpr explicit optional_data(in_place_t t, Args&&... args) + : optional_data_base<T>(t, absl::forward<Args>(args)...) {} +#endif +}; + +template <typename T> +class optional_data<T, false> : public optional_data_base<T> { + protected: +#ifdef ABSL_OPTIONAL_USE_INHERITING_CONSTRUCTORS + using optional_data_base<T>::optional_data_base; +#else + template <typename... Args> + constexpr explicit optional_data(in_place_t t, Args&&... args) + : optional_data_base<T>(t, absl::forward<Args>(args)...) {} +#endif + + optional_data() = default; + + optional_data(const optional_data& rhs) : optional_data_base<T>() { + if (rhs.engaged_) { + this->construct(rhs.data_); + } + } + + optional_data(optional_data&& rhs) noexcept( + absl::default_allocator_is_nothrow::value || + std::is_nothrow_move_constructible<T>::value) + : optional_data_base<T>() { + if (rhs.engaged_) { + this->construct(std::move(rhs.data_)); + } + } + + optional_data& operator=(const optional_data& rhs) { + if (rhs.engaged_) { + this->assign(rhs.data_); + } else { + this->destruct(); + } + return *this; + } + + optional_data& operator=(optional_data&& rhs) noexcept( + std::is_nothrow_move_assignable<T>::value&& + std::is_nothrow_move_constructible<T>::value) { + if (rhs.engaged_) { + this->assign(std::move(rhs.data_)); + } else { + this->destruct(); + } + return *this; + } +}; + +// Ordered by level of restriction, from low to high. +// Copyable implies movable. +enum class copy_traits { copyable = 0, movable = 1, non_movable = 2 }; + +// Base class for enabling/disabling copy/move constructor. +template <copy_traits> +class optional_ctor_base; + +template <> +class optional_ctor_base<copy_traits::copyable> { + public: + constexpr optional_ctor_base() = default; + optional_ctor_base(const optional_ctor_base&) = default; + optional_ctor_base(optional_ctor_base&&) = default; + optional_ctor_base& operator=(const optional_ctor_base&) = default; + optional_ctor_base& operator=(optional_ctor_base&&) = default; +}; + +template <> +class optional_ctor_base<copy_traits::movable> { + public: + constexpr optional_ctor_base() = default; + optional_ctor_base(const optional_ctor_base&) = delete; + optional_ctor_base(optional_ctor_base&&) = default; + optional_ctor_base& operator=(const optional_ctor_base&) = default; + optional_ctor_base& operator=(optional_ctor_base&&) = default; +}; + +template <> +class optional_ctor_base<copy_traits::non_movable> { + public: + constexpr optional_ctor_base() = default; + optional_ctor_base(const optional_ctor_base&) = delete; + optional_ctor_base(optional_ctor_base&&) = delete; + optional_ctor_base& operator=(const optional_ctor_base&) = default; + optional_ctor_base& operator=(optional_ctor_base&&) = default; +}; + +// Base class for enabling/disabling copy/move assignment. +template <copy_traits> +class optional_assign_base; + +template <> +class optional_assign_base<copy_traits::copyable> { + public: + constexpr optional_assign_base() = default; + optional_assign_base(const optional_assign_base&) = default; + optional_assign_base(optional_assign_base&&) = default; + optional_assign_base& operator=(const optional_assign_base&) = default; + optional_assign_base& operator=(optional_assign_base&&) = default; +}; + +template <> +class optional_assign_base<copy_traits::movable> { + public: + constexpr optional_assign_base() = default; + optional_assign_base(const optional_assign_base&) = default; + optional_assign_base(optional_assign_base&&) = default; + optional_assign_base& operator=(const optional_assign_base&) = delete; + optional_assign_base& operator=(optional_assign_base&&) = default; +}; + +template <> +class optional_assign_base<copy_traits::non_movable> { + public: + constexpr optional_assign_base() = default; + optional_assign_base(const optional_assign_base&) = default; + optional_assign_base(optional_assign_base&&) = default; + optional_assign_base& operator=(const optional_assign_base&) = delete; + optional_assign_base& operator=(optional_assign_base&&) = delete; +}; + +template <typename T> +struct ctor_copy_traits { + static constexpr copy_traits traits = + std::is_copy_constructible<T>::value + ? copy_traits::copyable + : std::is_move_constructible<T>::value ? copy_traits::movable + : copy_traits::non_movable; +}; + +template <typename T> +struct assign_copy_traits { + static constexpr copy_traits traits = + absl::is_copy_assignable<T>::value && std::is_copy_constructible<T>::value + ? copy_traits::copyable + : absl::is_move_assignable<T>::value && + std::is_move_constructible<T>::value + ? copy_traits::movable + : copy_traits::non_movable; +}; + +// Whether T is constructible or convertible from optional<U>. +template <typename T, typename U> +struct is_constructible_convertible_from_optional + : std::integral_constant< + bool, std::is_constructible<T, optional<U>&>::value || + std::is_constructible<T, optional<U>&&>::value || + std::is_constructible<T, const optional<U>&>::value || + std::is_constructible<T, const optional<U>&&>::value || + std::is_convertible<optional<U>&, T>::value || + std::is_convertible<optional<U>&&, T>::value || + std::is_convertible<const optional<U>&, T>::value || + std::is_convertible<const optional<U>&&, T>::value> {}; + +// Whether T is constructible or convertible or assignable from optional<U>. +template <typename T, typename U> +struct is_constructible_convertible_assignable_from_optional + : std::integral_constant< + bool, is_constructible_convertible_from_optional<T, U>::value || + std::is_assignable<T&, optional<U>&>::value || + std::is_assignable<T&, optional<U>&&>::value || + std::is_assignable<T&, const optional<U>&>::value || + std::is_assignable<T&, const optional<U>&&>::value> {}; + +// Helper function used by [optional.relops], [optional.comp_with_t], +// for checking whether an expression is convertible to bool. +bool convertible_to_bool(bool); + +// Base class for std::hash<absl::optional<T>>: +// If std::hash<std::remove_const_t<T>> is enabled, it provides operator() to +// compute the hash; Otherwise, it is disabled. +// Reference N4659 23.14.15 [unord.hash]. +template <typename T, typename = size_t> +struct optional_hash_base { + optional_hash_base() = delete; + optional_hash_base(const optional_hash_base&) = delete; + optional_hash_base(optional_hash_base&&) = delete; + optional_hash_base& operator=(const optional_hash_base&) = delete; + optional_hash_base& operator=(optional_hash_base&&) = delete; +}; + +template <typename T> +struct optional_hash_base<T, decltype(std::hash<absl::remove_const_t<T> >()( + std::declval<absl::remove_const_t<T> >()))> { + using argument_type = absl::optional<T>; + using result_type = size_t; + size_t operator()(const absl::optional<T>& opt) const { + absl::type_traits_internal::AssertHashEnabled<absl::remove_const_t<T>>(); + if (opt) { + return std::hash<absl::remove_const_t<T> >()(*opt); + } else { + return static_cast<size_t>(0x297814aaad196e6dULL); + } + } +}; + +} // namespace optional_internal +} // namespace absl + +#undef ABSL_OPTIONAL_USE_INHERITING_CONSTRUCTORS + +#endif // ABSL_TYPES_INTERNAL_OPTIONAL_H_
diff --git a/absl/types/internal/span.h b/absl/types/internal/span.h new file mode 100644 index 0000000..d203aad --- /dev/null +++ b/absl/types/internal/span.h
@@ -0,0 +1,126 @@ +// +// Copyright 2019 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#ifndef ABSL_TYPES_INTERNAL_SPAN_H_ +#define ABSL_TYPES_INTERNAL_SPAN_H_ + +#include <algorithm> +#include <cstddef> +#include <string> +#include <type_traits> + +#include "absl/algorithm/algorithm.h" +#include "absl/base/internal/throw_delegate.h" +#include "absl/meta/type_traits.h" + +namespace absl { + +namespace span_internal { +// A constexpr min function +constexpr size_t Min(size_t a, size_t b) noexcept { return a < b ? a : b; } + +// Wrappers for access to container data pointers. +template <typename C> +constexpr auto GetDataImpl(C& c, char) noexcept // NOLINT(runtime/references) + -> decltype(c.data()) { + return c.data(); +} + +// Before C++17, std::string::data returns a const char* in all cases. +inline char* GetDataImpl(std::string& s, // NOLINT(runtime/references) + int) noexcept { + return &s[0]; +} + +template <typename C> +constexpr auto GetData(C& c) noexcept // NOLINT(runtime/references) + -> decltype(GetDataImpl(c, 0)) { + return GetDataImpl(c, 0); +} + +// Detection idioms for size() and data(). +template <typename C> +using HasSize = + std::is_integral<absl::decay_t<decltype(std::declval<C&>().size())>>; + +// We want to enable conversion from vector<T*> to Span<const T* const> but +// disable conversion from vector<Derived> to Span<Base>. Here we use +// the fact that U** is convertible to Q* const* if and only if Q is the same +// type or a more cv-qualified version of U. We also decay the result type of +// data() to avoid problems with classes which have a member function data() +// which returns a reference. +template <typename T, typename C> +using HasData = + std::is_convertible<absl::decay_t<decltype(GetData(std::declval<C&>()))>*, + T* const*>; + +// Extracts value type from a Container +template <typename C> +struct ElementType { + using type = typename absl::remove_reference_t<C>::value_type; +}; + +template <typename T, size_t N> +struct ElementType<T (&)[N]> { + using type = T; +}; + +template <typename C> +using ElementT = typename ElementType<C>::type; + +template <typename T> +using EnableIfMutable = + typename std::enable_if<!std::is_const<T>::value, int>::type; + +template <template <typename> class SpanT, typename T> +bool EqualImpl(SpanT<T> a, SpanT<T> b) { + static_assert(std::is_const<T>::value, ""); + return absl::equal(a.begin(), a.end(), b.begin(), b.end()); +} + +template <template <typename> class SpanT, typename T> +bool LessThanImpl(SpanT<T> a, SpanT<T> b) { + // We can't use value_type since that is remove_cv_t<T>, so we go the long way + // around. + static_assert(std::is_const<T>::value, ""); + return std::lexicographical_compare(a.begin(), a.end(), b.begin(), b.end()); +} + +// The `IsConvertible` classes here are needed because of the +// `std::is_convertible` bug in libcxx when compiled with GCC. This build +// configuration is used by Android NDK toolchain. Reference link: +// https://bugs.llvm.org/show_bug.cgi?id=27538. +template <typename From, typename To> +struct IsConvertibleHelper { + private: + static std::true_type testval(To); + static std::false_type testval(...); + + public: + using type = decltype(testval(std::declval<From>())); +}; + +template <typename From, typename To> +struct IsConvertible : IsConvertibleHelper<From, To>::type {}; + +// TODO(zhangxy): replace `IsConvertible` with `std::is_convertible` once the +// older version of libcxx is not supported. +template <typename From, typename To> +using EnableIfConvertibleTo = + typename std::enable_if<IsConvertible<From, To>::value>::type; +} // namespace span_internal +} // namespace absl + +#endif // ABSL_TYPES_INTERNAL_SPAN_H_
diff --git a/absl/types/optional.h b/absl/types/optional.h index f0ae9a1..5798331 100644 --- a/absl/types/optional.h +++ b/absl/types/optional.h
@@ -35,8 +35,7 @@ #ifndef ABSL_TYPES_OPTIONAL_H_ #define ABSL_TYPES_OPTIONAL_H_ -#include "absl/base/config.h" -#include "absl/memory/memory.h" +#include "absl/base/config.h" // TODO(calabrese) IWYU removal? #include "absl/utility/utility.h" #ifdef ABSL_HAVE_STD_OPTIONAL @@ -56,44 +55,33 @@ #include <cassert> #include <functional> #include <initializer_list> -#include <new> #include <type_traits> #include <utility> #include "absl/base/attributes.h" +#include "absl/base/internal/inline_variable.h" #include "absl/meta/type_traits.h" #include "absl/types/bad_optional_access.h" - -// ABSL_OPTIONAL_USE_INHERITING_CONSTRUCTORS -// -// Inheriting constructors is supported in GCC 4.8+, Clang 3.3+ and MSVC 2015. -// __cpp_inheriting_constructors is a predefined macro and a recommended way to -// check for this language feature, but GCC doesn't support it until 5.0 and -// Clang doesn't support it until 3.6. -// Also, MSVC 2015 has a bug: it doesn't inherit the constexpr template -// constructor. For example, the following code won't work on MSVC 2015 Update3: -// struct Base { -// int t; -// template <typename T> -// constexpr Base(T t_) : t(t_) {} -// }; -// struct Foo : Base { -// using Base::Base; -// } -// constexpr Foo foo(0); // doesn't work on MSVC 2015 -#if defined(__clang__) -#if __has_feature(cxx_inheriting_constructors) -#define ABSL_OPTIONAL_USE_INHERITING_CONSTRUCTORS 1 -#endif -#elif (defined(__GNUC__) && \ - (__GNUC__ > 4 || __GNUC__ == 4 && __GNUC_MINOR__ >= 8)) || \ - (__cpp_inheriting_constructors >= 200802) || \ - (defined(_MSC_VER) && _MSC_VER >= 1910) -#define ABSL_OPTIONAL_USE_INHERITING_CONSTRUCTORS 1 -#endif +#include "absl/types/internal/optional.h" namespace absl { +// nullopt_t +// +// Class type for `absl::nullopt` used to indicate an `absl::optional<T>` type +// that does not contain a value. +struct nullopt_t { + // It must not be default-constructible to avoid ambiguity for opt = {}. + explicit constexpr nullopt_t(optional_internal::init_t) noexcept {} +}; + +// nullopt +// +// A tag constant of type `absl::nullopt_t` used to indicate an empty +// `absl::optional` in certain functions, such as construction or assignment. +ABSL_INTERNAL_INLINE_CONSTEXPR(nullopt_t, nullopt, + nullopt_t(optional_internal::init_t())); + // ----------------------------------------------------------------------------- // absl::optional // ----------------------------------------------------------------------------- @@ -123,363 +111,7 @@ // a) move constructors should only throw due to allocation failure and // b) if T's move constructor allocates, it uses the same allocation // function as the default allocator. -template <typename T> -class optional; - -// nullopt_t // -// Class type for `absl::nullopt` used to indicate an `absl::optional<T>` type -// that does not contain a value. -struct nullopt_t { - struct init_t {}; - static init_t init; - - // It must not be default-constructible to avoid ambiguity for opt = {}. - // Note the non-const reference, which is to eliminate ambiguity for code - // like: - // - // struct S { int value; }; - // - // void Test() { - // optional<S> opt; - // opt = {{}}; - // } - explicit constexpr nullopt_t(init_t& /*unused*/) {} -}; - -// nullopt -// -// A tag constant of type `absl::nullopt_t` used to indicate an empty -// `absl::optional` in certain functions, such as construction or assignment. -extern const nullopt_t nullopt; - -namespace optional_internal { - -struct empty_struct {}; -// This class stores the data in optional<T>. -// It is specialized based on whether T is trivially destructible. -// This is the specialization for non trivially destructible type. -template <typename T, bool unused = std::is_trivially_destructible<T>::value> -class optional_data_dtor_base { - struct dummy_type { - static_assert(sizeof(T) % sizeof(empty_struct) == 0, ""); - // Use an array to avoid GCC 6 placement-new warning. - empty_struct data[sizeof(T) / sizeof(empty_struct)]; - }; - - protected: - // Whether there is data or not. - bool engaged_; - // Data storage - union { - dummy_type dummy_; - T data_; - }; - - void destruct() noexcept { - if (engaged_) { - data_.~T(); - engaged_ = false; - } - } - - // dummy_ must be initialized for constexpr constructor. - constexpr optional_data_dtor_base() noexcept : engaged_(false), dummy_{{}} {} - - template <typename... Args> - constexpr explicit optional_data_dtor_base(in_place_t, Args&&... args) - : engaged_(true), data_(absl::forward<Args>(args)...) {} - - ~optional_data_dtor_base() { destruct(); } -}; - -// Specialization for trivially destructible type. -template <typename T> -class optional_data_dtor_base<T, true> { - struct dummy_type { - static_assert(sizeof(T) % sizeof(empty_struct) == 0, ""); - // Use array to avoid GCC 6 placement-new warning. - empty_struct data[sizeof(T) / sizeof(empty_struct)]; - }; - - protected: - // Whether there is data or not. - bool engaged_; - // Data storage - union { - dummy_type dummy_; - T data_; - }; - void destruct() noexcept { engaged_ = false; } - - // dummy_ must be initialized for constexpr constructor. - constexpr optional_data_dtor_base() noexcept : engaged_(false), dummy_{{}} {} - - template <typename... Args> - constexpr explicit optional_data_dtor_base(in_place_t, Args&&... args) - : engaged_(true), data_(absl::forward<Args>(args)...) {} -}; - -template <typename T> -class optional_data_base : public optional_data_dtor_base<T> { - protected: - using base = optional_data_dtor_base<T>; -#if ABSL_OPTIONAL_USE_INHERITING_CONSTRUCTORS - using base::base; -#else - optional_data_base() = default; - - template <typename... Args> - constexpr explicit optional_data_base(in_place_t t, Args&&... args) - : base(t, absl::forward<Args>(args)...) {} -#endif - - template <typename... Args> - void construct(Args&&... args) { - // Use dummy_'s address to work around casting cv-qualified T* to void*. - ::new (static_cast<void*>(&this->dummy_)) T(std::forward<Args>(args)...); - this->engaged_ = true; - } - - template <typename U> - void assign(U&& u) { - if (this->engaged_) { - this->data_ = std::forward<U>(u); - } else { - construct(std::forward<U>(u)); - } - } -}; - -// TODO(absl-team): Add another class using -// std::is_trivially_move_constructible trait when available to match -// http://cplusplus.github.io/LWG/lwg-defects.html#2900, for types that -// have trivial move but nontrivial copy. -// Also, we should be checking is_trivially_copyable here, which is not -// supported now, so we use is_trivially_* traits instead. -template <typename T, - bool unused = absl::is_trivially_copy_constructible<T>::value&& - absl::is_trivially_copy_assignable<typename std::remove_cv< - T>::type>::value&& std::is_trivially_destructible<T>::value> -class optional_data; - -// Trivially copyable types -template <typename T> -class optional_data<T, true> : public optional_data_base<T> { - protected: -#if ABSL_OPTIONAL_USE_INHERITING_CONSTRUCTORS - using optional_data_base<T>::optional_data_base; -#else - optional_data() = default; - - template <typename... Args> - constexpr explicit optional_data(in_place_t t, Args&&... args) - : optional_data_base<T>(t, absl::forward<Args>(args)...) {} -#endif -}; - -template <typename T> -class optional_data<T, false> : public optional_data_base<T> { - protected: -#if ABSL_OPTIONAL_USE_INHERITING_CONSTRUCTORS - using optional_data_base<T>::optional_data_base; -#else - template <typename... Args> - constexpr explicit optional_data(in_place_t t, Args&&... args) - : optional_data_base<T>(t, absl::forward<Args>(args)...) {} -#endif - - optional_data() = default; - - optional_data(const optional_data& rhs) : optional_data_base<T>() { - if (rhs.engaged_) { - this->construct(rhs.data_); - } - } - - optional_data(optional_data&& rhs) noexcept( - absl::default_allocator_is_nothrow::value || - std::is_nothrow_move_constructible<T>::value) - : optional_data_base<T>() { - if (rhs.engaged_) { - this->construct(std::move(rhs.data_)); - } - } - - optional_data& operator=(const optional_data& rhs) { - if (rhs.engaged_) { - this->assign(rhs.data_); - } else { - this->destruct(); - } - return *this; - } - - optional_data& operator=(optional_data&& rhs) noexcept( - std::is_nothrow_move_assignable<T>::value&& - std::is_nothrow_move_constructible<T>::value) { - if (rhs.engaged_) { - this->assign(std::move(rhs.data_)); - } else { - this->destruct(); - } - return *this; - } -}; - -// Ordered by level of restriction, from low to high. -// Copyable implies movable. -enum class copy_traits { copyable = 0, movable = 1, non_movable = 2 }; - -// Base class for enabling/disabling copy/move constructor. -template <copy_traits> -class optional_ctor_base; - -template <> -class optional_ctor_base<copy_traits::copyable> { - public: - constexpr optional_ctor_base() = default; - optional_ctor_base(const optional_ctor_base&) = default; - optional_ctor_base(optional_ctor_base&&) = default; - optional_ctor_base& operator=(const optional_ctor_base&) = default; - optional_ctor_base& operator=(optional_ctor_base&&) = default; -}; - -template <> -class optional_ctor_base<copy_traits::movable> { - public: - constexpr optional_ctor_base() = default; - optional_ctor_base(const optional_ctor_base&) = delete; - optional_ctor_base(optional_ctor_base&&) = default; - optional_ctor_base& operator=(const optional_ctor_base&) = default; - optional_ctor_base& operator=(optional_ctor_base&&) = default; -}; - -template <> -class optional_ctor_base<copy_traits::non_movable> { - public: - constexpr optional_ctor_base() = default; - optional_ctor_base(const optional_ctor_base&) = delete; - optional_ctor_base(optional_ctor_base&&) = delete; - optional_ctor_base& operator=(const optional_ctor_base&) = default; - optional_ctor_base& operator=(optional_ctor_base&&) = default; -}; - -// Base class for enabling/disabling copy/move assignment. -template <copy_traits> -class optional_assign_base; - -template <> -class optional_assign_base<copy_traits::copyable> { - public: - constexpr optional_assign_base() = default; - optional_assign_base(const optional_assign_base&) = default; - optional_assign_base(optional_assign_base&&) = default; - optional_assign_base& operator=(const optional_assign_base&) = default; - optional_assign_base& operator=(optional_assign_base&&) = default; -}; - -template <> -class optional_assign_base<copy_traits::movable> { - public: - constexpr optional_assign_base() = default; - optional_assign_base(const optional_assign_base&) = default; - optional_assign_base(optional_assign_base&&) = default; - optional_assign_base& operator=(const optional_assign_base&) = delete; - optional_assign_base& operator=(optional_assign_base&&) = default; -}; - -template <> -class optional_assign_base<copy_traits::non_movable> { - public: - constexpr optional_assign_base() = default; - optional_assign_base(const optional_assign_base&) = default; - optional_assign_base(optional_assign_base&&) = default; - optional_assign_base& operator=(const optional_assign_base&) = delete; - optional_assign_base& operator=(optional_assign_base&&) = delete; -}; - -template <typename T> -struct ctor_copy_traits { - static constexpr copy_traits traits = - std::is_copy_constructible<T>::value - ? copy_traits::copyable - : std::is_move_constructible<T>::value ? copy_traits::movable - : copy_traits::non_movable; -}; - -template <typename T> -struct assign_copy_traits { - static constexpr copy_traits traits = - absl::is_copy_assignable<T>::value && std::is_copy_constructible<T>::value - ? copy_traits::copyable - : absl::is_move_assignable<T>::value && - std::is_move_constructible<T>::value - ? copy_traits::movable - : copy_traits::non_movable; -}; - -// Whether T is constructible or convertible from optional<U>. -template <typename T, typename U> -struct is_constructible_convertible_from_optional - : std::integral_constant< - bool, std::is_constructible<T, optional<U>&>::value || - std::is_constructible<T, optional<U>&&>::value || - std::is_constructible<T, const optional<U>&>::value || - std::is_constructible<T, const optional<U>&&>::value || - std::is_convertible<optional<U>&, T>::value || - std::is_convertible<optional<U>&&, T>::value || - std::is_convertible<const optional<U>&, T>::value || - std::is_convertible<const optional<U>&&, T>::value> {}; - -// Whether T is constructible or convertible or assignable from optional<U>. -template <typename T, typename U> -struct is_constructible_convertible_assignable_from_optional - : std::integral_constant< - bool, is_constructible_convertible_from_optional<T, U>::value || - std::is_assignable<T&, optional<U>&>::value || - std::is_assignable<T&, optional<U>&&>::value || - std::is_assignable<T&, const optional<U>&>::value || - std::is_assignable<T&, const optional<U>&&>::value> {}; - -// Helper function used by [optional.relops], [optional.comp_with_t], -// for checking whether an expression is convertible to bool. -bool convertible_to_bool(bool); - -// Base class for std::hash<absl::optional<T>>: -// If std::hash<std::remove_const_t<T>> is enabled, it provides operator() to -// compute the hash; Otherwise, it is disabled. -// Reference N4659 23.14.15 [unord.hash]. -template <typename T, typename = size_t> -struct optional_hash_base { - optional_hash_base() = delete; - optional_hash_base(const optional_hash_base&) = delete; - optional_hash_base(optional_hash_base&&) = delete; - optional_hash_base& operator=(const optional_hash_base&) = delete; - optional_hash_base& operator=(optional_hash_base&&) = delete; -}; - -template <typename T> -struct optional_hash_base<T, decltype(std::hash<absl::remove_const_t<T> >()( - std::declval<absl::remove_const_t<T> >()))> { - using argument_type = absl::optional<T>; - using result_type = size_t; - size_t operator()(const absl::optional<T>& opt) const { - absl::type_traits_internal::AssertHashEnabled<absl::remove_const_t<T>>(); - if (opt) { - return std::hash<absl::remove_const_t<T> >()(*opt); - } else { - return static_cast<size_t>(0x297814aaad196e6dULL); - } - } -}; - -} // namespace optional_internal - -// ----------------------------------------------------------------------------- -// absl::optional class definition -// ----------------------------------------------------------------------------- - template <typename T> class optional : private optional_internal::optional_data<T>, private optional_internal::optional_ctor_base< @@ -1131,7 +763,6 @@ } // namespace std -#undef ABSL_OPTIONAL_USE_INHERITING_CONSTRUCTORS #undef ABSL_MSVC_CONSTEXPR_BUG_IN_UNION_LIKE_CLASS #endif // ABSL_HAVE_STD_OPTIONAL
diff --git a/absl/types/optional_test.cc b/absl/types/optional_test.cc index 0665488..221c314 100644 --- a/absl/types/optional_test.cc +++ b/absl/types/optional_test.cc
@@ -179,15 +179,7 @@ TEST(optionalTest, nulloptConstructor) { absl::optional<int> empty(absl::nullopt); EXPECT_FALSE(empty); - -#ifdef ABSL_HAVE_STD_OPTIONAL constexpr absl::optional<int> cempty{absl::nullopt}; -#else - // Creating a temporary absl::nullopt_t object instead of using absl::nullopt - // because absl::nullopt cannot be constexpr and have external linkage at the - // same time. - constexpr absl::optional<int> cempty{absl::nullopt_t(absl::nullopt_t::init)}; -#endif static_assert(!cempty.has_value(), ""); EXPECT_TRUE((std::is_nothrow_constructible<absl::optional<int>, absl::nullopt_t>::value)); @@ -1636,7 +1628,6 @@ EXPECT_TRUE(absl::is_copy_assignable<absl::optional<AnyLike>>::value); } -#if !defined(ABSL_HAVE_STD_OPTIONAL) && !defined(_LIBCPP_VERSION) struct NestedClassBug { struct Inner { bool dummy = false; @@ -1659,6 +1650,5 @@ o.emplace(); EXPECT_TRUE(o.has_value()); } -#endif // !defined(ABSL_HAVE_STD_OPTIONAL) && !defined(_LIBCPP_VERSION) } // namespace
diff --git a/absl/types/span.h b/absl/types/span.h index d7f48d9..b007fc1 100644 --- a/absl/types/span.h +++ b/absl/types/span.h
@@ -60,115 +60,18 @@ #include <cstddef> #include <initializer_list> #include <iterator> -#include <string> #include <type_traits> #include <utility> -#include "absl/algorithm/algorithm.h" #include "absl/base/internal/throw_delegate.h" #include "absl/base/macros.h" #include "absl/base/optimization.h" -#include "absl/base/port.h" +#include "absl/base/port.h" // TODO(strel): remove this include #include "absl/meta/type_traits.h" +#include "absl/types/internal/span.h" namespace absl { -template <typename T> -class Span; - -namespace span_internal { -// A constexpr min function -constexpr size_t Min(size_t a, size_t b) noexcept { return a < b ? a : b; } - -// Wrappers for access to container data pointers. -template <typename C> -constexpr auto GetDataImpl(C& c, char) noexcept // NOLINT(runtime/references) - -> decltype(c.data()) { - return c.data(); -} - -// Before C++17, std::string::data returns a const char* in all cases. -inline char* GetDataImpl(std::string& s, // NOLINT(runtime/references) - int) noexcept { - return &s[0]; -} - -template <typename C> -constexpr auto GetData(C& c) noexcept // NOLINT(runtime/references) - -> decltype(GetDataImpl(c, 0)) { - return GetDataImpl(c, 0); -} - -// Detection idioms for size() and data(). -template <typename C> -using HasSize = - std::is_integral<absl::decay_t<decltype(std::declval<C&>().size())>>; - -// We want to enable conversion from vector<T*> to Span<const T* const> but -// disable conversion from vector<Derived> to Span<Base>. Here we use -// the fact that U** is convertible to Q* const* if and only if Q is the same -// type or a more cv-qualified version of U. We also decay the result type of -// data() to avoid problems with classes which have a member function data() -// which returns a reference. -template <typename T, typename C> -using HasData = - std::is_convertible<absl::decay_t<decltype(GetData(std::declval<C&>()))>*, - T* const*>; - -// Extracts value type from a Container -template <typename C> -struct ElementType { - using type = typename absl::remove_reference_t<C>::value_type; -}; - -template <typename T, size_t N> -struct ElementType<T (&)[N]> { - using type = T; -}; - -template <typename C> -using ElementT = typename ElementType<C>::type; - -template <typename T> -using EnableIfMutable = - typename std::enable_if<!std::is_const<T>::value, int>::type; - -template <typename T> -bool EqualImpl(Span<T> a, Span<T> b) { - static_assert(std::is_const<T>::value, ""); - return absl::equal(a.begin(), a.end(), b.begin(), b.end()); -} - -template <typename T> -bool LessThanImpl(Span<T> a, Span<T> b) { - static_assert(std::is_const<T>::value, ""); - return std::lexicographical_compare(a.begin(), a.end(), b.begin(), b.end()); -} - -// The `IsConvertible` classes here are needed because of the -// `std::is_convertible` bug in libcxx when compiled with GCC. This build -// configuration is used by Android NDK toolchain. Reference link: -// https://bugs.llvm.org/show_bug.cgi?id=27538. -template <typename From, typename To> -struct IsConvertibleHelper { - private: - static std::true_type testval(To); - static std::false_type testval(...); - - public: - using type = decltype(testval(std::declval<From>())); -}; - -template <typename From, typename To> -struct IsConvertible : IsConvertibleHelper<From, To>::type {}; - -// TODO(zhangxy): replace `IsConvertible` with `std::is_convertible` once the -// older version of libcxx is not supported. -template <typename From, typename To> -using EnableIfConvertibleToSpanConst = - typename std::enable_if<IsConvertible<From, Span<const To>>::value>::type; -} // namespace span_internal - //------------------------------------------------------------------------------ // Span //------------------------------------------------------------------------------ @@ -551,25 +454,27 @@ // operator== template <typename T> bool operator==(Span<T> a, Span<T> b) { - return span_internal::EqualImpl<const T>(a, b); + return span_internal::EqualImpl<Span, const T>(a, b); } template <typename T> bool operator==(Span<const T> a, Span<T> b) { - return span_internal::EqualImpl<const T>(a, b); + return span_internal::EqualImpl<Span, const T>(a, b); } template <typename T> bool operator==(Span<T> a, Span<const T> b) { - return span_internal::EqualImpl<const T>(a, b); + return span_internal::EqualImpl<Span, const T>(a, b); } -template <typename T, typename U, - typename = span_internal::EnableIfConvertibleToSpanConst<U, T>> +template < + typename T, typename U, + typename = span_internal::EnableIfConvertibleTo<U, absl::Span<const T>>> bool operator==(const U& a, Span<T> b) { - return span_internal::EqualImpl<const T>(a, b); + return span_internal::EqualImpl<Span, const T>(a, b); } -template <typename T, typename U, - typename = span_internal::EnableIfConvertibleToSpanConst<U, T>> +template < + typename T, typename U, + typename = span_internal::EnableIfConvertibleTo<U, absl::Span<const T>>> bool operator==(Span<T> a, const U& b) { - return span_internal::EqualImpl<const T>(a, b); + return span_internal::EqualImpl<Span, const T>(a, b); } // operator!= @@ -585,13 +490,15 @@ bool operator!=(Span<T> a, Span<const T> b) { return !(a == b); } -template <typename T, typename U, - typename = span_internal::EnableIfConvertibleToSpanConst<U, T>> +template < + typename T, typename U, + typename = span_internal::EnableIfConvertibleTo<U, absl::Span<const T>>> bool operator!=(const U& a, Span<T> b) { return !(a == b); } -template <typename T, typename U, - typename = span_internal::EnableIfConvertibleToSpanConst<U, T>> +template < + typename T, typename U, + typename = span_internal::EnableIfConvertibleTo<U, absl::Span<const T>>> bool operator!=(Span<T> a, const U& b) { return !(a == b); } @@ -599,25 +506,27 @@ // operator< template <typename T> bool operator<(Span<T> a, Span<T> b) { - return span_internal::LessThanImpl<const T>(a, b); + return span_internal::LessThanImpl<Span, const T>(a, b); } template <typename T> bool operator<(Span<const T> a, Span<T> b) { - return span_internal::LessThanImpl<const T>(a, b); + return span_internal::LessThanImpl<Span, const T>(a, b); } template <typename T> bool operator<(Span<T> a, Span<const T> b) { - return span_internal::LessThanImpl<const T>(a, b); + return span_internal::LessThanImpl<Span, const T>(a, b); } -template <typename T, typename U, - typename = span_internal::EnableIfConvertibleToSpanConst<U, T>> +template < + typename T, typename U, + typename = span_internal::EnableIfConvertibleTo<U, absl::Span<const T>>> bool operator<(const U& a, Span<T> b) { - return span_internal::LessThanImpl<const T>(a, b); + return span_internal::LessThanImpl<Span, const T>(a, b); } -template <typename T, typename U, - typename = span_internal::EnableIfConvertibleToSpanConst<U, T>> +template < + typename T, typename U, + typename = span_internal::EnableIfConvertibleTo<U, absl::Span<const T>>> bool operator<(Span<T> a, const U& b) { - return span_internal::LessThanImpl<const T>(a, b); + return span_internal::LessThanImpl<Span, const T>(a, b); } // operator> @@ -633,13 +542,15 @@ bool operator>(Span<T> a, Span<const T> b) { return b < a; } -template <typename T, typename U, - typename = span_internal::EnableIfConvertibleToSpanConst<U, T>> +template < + typename T, typename U, + typename = span_internal::EnableIfConvertibleTo<U, absl::Span<const T>>> bool operator>(const U& a, Span<T> b) { return b < a; } -template <typename T, typename U, - typename = span_internal::EnableIfConvertibleToSpanConst<U, T>> +template < + typename T, typename U, + typename = span_internal::EnableIfConvertibleTo<U, absl::Span<const T>>> bool operator>(Span<T> a, const U& b) { return b < a; } @@ -657,13 +568,15 @@ bool operator<=(Span<T> a, Span<const T> b) { return !(b < a); } -template <typename T, typename U, - typename = span_internal::EnableIfConvertibleToSpanConst<U, T>> +template < + typename T, typename U, + typename = span_internal::EnableIfConvertibleTo<U, absl::Span<const T>>> bool operator<=(const U& a, Span<T> b) { return !(b < a); } -template <typename T, typename U, - typename = span_internal::EnableIfConvertibleToSpanConst<U, T>> +template < + typename T, typename U, + typename = span_internal::EnableIfConvertibleTo<U, absl::Span<const T>>> bool operator<=(Span<T> a, const U& b) { return !(b < a); } @@ -681,13 +594,15 @@ bool operator>=(Span<T> a, Span<const T> b) { return !(a < b); } -template <typename T, typename U, - typename = span_internal::EnableIfConvertibleToSpanConst<U, T>> +template < + typename T, typename U, + typename = span_internal::EnableIfConvertibleTo<U, absl::Span<const T>>> bool operator>=(const U& a, Span<T> b) { return !(a < b); } -template <typename T, typename U, - typename = span_internal::EnableIfConvertibleToSpanConst<U, T>> +template < + typename T, typename U, + typename = span_internal::EnableIfConvertibleTo<U, absl::Span<const T>>> bool operator>=(Span<T> a, const U& b) { return !(a < b); }
diff --git a/absl/types/variant_test.cc b/absl/types/variant_test.cc index ab40ed2..b9c9811 100644 --- a/absl/types/variant_test.cc +++ b/absl/types/variant_test.cc
@@ -384,7 +384,7 @@ TEST(VariantTest, TestMoveConstruct) { using V = variant<MoveOnly<class A>, MoveOnly<class B>, MoveOnly<class C>>; - V v(in_place_index_t<1>{}, 10); + V v(in_place_index<1>, 10); V v2 = absl::move(v); EXPECT_EQ(10, absl::get<1>(v2).value); } @@ -483,6 +483,29 @@ EXPECT_THAT(absl::get<std::vector<int>>(v5), ::testing::ElementsAre(1, 2, 3)); } +TEST(VariantTest, InPlaceTypeVariableTemplate) { + using Var = variant<int, std::string, NonCopyable, std::vector<int>>; + + Var v1(in_place_type<int>, 7); + ASSERT_TRUE(absl::holds_alternative<int>(v1)); + EXPECT_EQ(7, absl::get<int>(v1)); + + Var v2(in_place_type<std::string>, "ABC"); + ASSERT_TRUE(absl::holds_alternative<std::string>(v2)); + EXPECT_EQ("ABC", absl::get<std::string>(v2)); + + Var v3(in_place_type<std::string>, "ABC", 2); + ASSERT_TRUE(absl::holds_alternative<std::string>(v3)); + EXPECT_EQ("AB", absl::get<std::string>(v3)); + + Var v4(in_place_type<NonCopyable>); + ASSERT_TRUE(absl::holds_alternative<NonCopyable>(v4)); + + Var v5(in_place_type<std::vector<int>>, {1, 2, 3}); + ASSERT_TRUE(absl::holds_alternative<std::vector<int>>(v5)); + EXPECT_THAT(absl::get<std::vector<int>>(v5), ::testing::ElementsAre(1, 2, 3)); +} + TEST(VariantTest, InPlaceTypeInitializerList) { using Var = variant<int, std::string, NonCopyable, MoveOnlyWithListConstructor>; @@ -492,6 +515,15 @@ EXPECT_EQ(6, absl::get<MoveOnlyWithListConstructor>(v1).value); } +TEST(VariantTest, InPlaceTypeInitializerListVariabletemplate) { + using Var = + variant<int, std::string, NonCopyable, MoveOnlyWithListConstructor>; + + Var v1(in_place_type<MoveOnlyWithListConstructor>, {1, 2, 3, 4, 5}, 6); + ASSERT_TRUE(absl::holds_alternative<MoveOnlyWithListConstructor>(v1)); + EXPECT_EQ(6, absl::get<MoveOnlyWithListConstructor>(v1).value); +} + TEST(VariantTest, InPlaceIndex) { using Var = variant<int, std::string, NonCopyable, std::vector<int>>; @@ -519,6 +551,33 @@ EXPECT_THAT(absl::get<std::vector<int>>(v5), ::testing::ElementsAre(1, 2, 3)); } +TEST(VariantTest, InPlaceIndexVariableTemplate) { + using Var = variant<int, std::string, NonCopyable, std::vector<int>>; + + Var v1(in_place_index<0>, 7); + ASSERT_TRUE(absl::holds_alternative<int>(v1)); + EXPECT_EQ(7, absl::get<int>(v1)); + + Var v2(in_place_index<1>, "ABC"); + ASSERT_TRUE(absl::holds_alternative<std::string>(v2)); + EXPECT_EQ("ABC", absl::get<std::string>(v2)); + + Var v3(in_place_index<1>, "ABC", 2); + ASSERT_TRUE(absl::holds_alternative<std::string>(v3)); + EXPECT_EQ("AB", absl::get<std::string>(v3)); + + Var v4(in_place_index<2>); + EXPECT_TRUE(absl::holds_alternative<NonCopyable>(v4)); + + // Verify that a variant with only non-copyables can still be constructed. + EXPECT_TRUE(absl::holds_alternative<NonCopyable>( + variant<NonCopyable>(in_place_index<0>))); + + Var v5(in_place_index<3>, {1, 2, 3}); + ASSERT_TRUE(absl::holds_alternative<std::vector<int>>(v5)); + EXPECT_THAT(absl::get<std::vector<int>>(v5), ::testing::ElementsAre(1, 2, 3)); +} + TEST(VariantTest, InPlaceIndexInitializerList) { using Var = variant<int, std::string, NonCopyable, MoveOnlyWithListConstructor>; @@ -528,6 +587,15 @@ EXPECT_EQ(6, absl::get<MoveOnlyWithListConstructor>(v1).value); } +TEST(VariantTest, InPlaceIndexInitializerListVariableTemplate) { + using Var = + variant<int, std::string, NonCopyable, MoveOnlyWithListConstructor>; + + Var v1(in_place_index<3>, {1, 2, 3, 4, 5}, 6); + ASSERT_TRUE(absl::holds_alternative<MoveOnlyWithListConstructor>(v1)); + EXPECT_EQ(6, absl::get<MoveOnlyWithListConstructor>(v1).value); +} + //////////////////// // [variant.dtor] // //////////////////// @@ -576,7 +644,7 @@ { using Variant = VariantFactory<IncrementInDtor>::Type; - Variant v(in_place_index_t<0>(), counter_adjuster); + Variant v(in_place_index<0>, counter_adjuster); EXPECT_EQ(0, counter); ToValuelessByException(v); @@ -810,7 +878,7 @@ TEST(VariantTest, TestEmplaceBasic) { using Variant = variant<int, char>; - Variant v(absl::in_place_index_t<0>{}, 0); + Variant v(absl::in_place_index<0>, 0); { char& emplace_result = v.emplace<char>(); @@ -837,7 +905,7 @@ using Var = variant<int, std::string, NonCopyable, MoveOnlyWithListConstructor>; - Var v1(absl::in_place_index_t<0>{}, 555); + Var v1(absl::in_place_index<0>, 555); MoveOnlyWithListConstructor& emplace_result = v1.emplace<MoveOnlyWithListConstructor>({1, 2, 3, 4, 5}, 6); ASSERT_TRUE(absl::holds_alternative<MoveOnlyWithListConstructor>(v1)); @@ -848,7 +916,7 @@ TEST(VariantTest, TestEmplaceIndex) { using Variant = variant<int, char>; - Variant v(absl::in_place_index_t<0>{}, 555); + Variant v(absl::in_place_index<0>, 555); { char& emplace_result = v.emplace<1>(); @@ -875,7 +943,7 @@ using Var = variant<int, std::string, NonCopyable, MoveOnlyWithListConstructor>; - Var v1(absl::in_place_index_t<0>{}, 555); + Var v1(absl::in_place_index<0>, 555); MoveOnlyWithListConstructor& emplace_result = v1.emplace<3>({1, 2, 3, 4, 5}, 6); ASSERT_TRUE(absl::holds_alternative<MoveOnlyWithListConstructor>(v1)); @@ -924,7 +992,7 @@ TEST(VariantTest, IndexValuelessByException) { using Var = variant<MoveCanThrow, std::string, double>; - Var v(absl::in_place_index_t<0>{}); + Var v(absl::in_place_index<0>); EXPECT_EQ(0, v.index()); ToValuelessByException(v); EXPECT_EQ(absl::variant_npos, v.index()); @@ -935,7 +1003,7 @@ TEST(VariantTest, ValuelessByException) { using Var = variant<MoveCanThrow, std::string, double>; - Var v(absl::in_place_index_t<0>{}); + Var v(absl::in_place_index<0>); EXPECT_FALSE(v.valueless_by_exception()); ToValuelessByException(v); EXPECT_TRUE(v.valueless_by_exception()); @@ -966,7 +1034,7 @@ using V = variant<MoveCanThrow, std::string, int>; int i = 33; std::string s = "abc"; - V valueless(in_place_index_t<0>{}); + V valueless(in_place_index<0>); ToValuelessByException(valueless); { // lhs and rhs holds different alternative @@ -1127,7 +1195,7 @@ using Var = variant<int, std::string, double, int>; { - Var v(absl::in_place_index_t<0>{}, 0); + Var v(absl::in_place_index<0>, 0); using LValueGetType = decltype(absl::get<0>(v)); using RValueGetType = decltype(absl::get<0>(absl::move(v))); @@ -1187,7 +1255,7 @@ } { - Var v(absl::in_place_index_t<0>{}, 0); + Var v(absl::in_place_index<0>, 0); v.emplace<3>(1); using LValueGetType = decltype(absl::get<3>(v)); @@ -1334,7 +1402,7 @@ using Var = variant<int, std::string, double, int>; { - Var v(absl::in_place_index_t<0>{}, 0); + Var v(absl::in_place_index<0>, 0); EXPECT_TRUE(noexcept(absl::get_if<0>(&v))); { @@ -1492,7 +1560,7 @@ } { - Var v(absl::in_place_index_t<0>{}, 0); + Var v(absl::in_place_index<0>, 0); v.emplace<3>(1); EXPECT_TRUE(noexcept(absl::get_if<3>(&v))); @@ -1638,8 +1706,8 @@ TEST(VariantTest, ValuelessOperatorEquals) { variant<MoveCanThrow, std::string> int_v(1), string_v("Hello"), - valueless(absl::in_place_index_t<0>{}), - other_valueless(absl::in_place_index_t<0>{}); + valueless(absl::in_place_index<0>), + other_valueless(absl::in_place_index<0>); ToValuelessByException(valueless); ToValuelessByException(other_valueless); @@ -1660,8 +1728,8 @@ TEST(VariantTest, ValuelessOperatorRelational) { variant<MoveCanThrow, std::string> int_v(1), string_v("Hello"), - valueless(absl::in_place_index_t<0>{}), - other_valueless(absl::in_place_index_t<0>{}); + valueless(absl::in_place_index<0>), + other_valueless(absl::in_place_index<0>); ToValuelessByException(valueless); ToValuelessByException(other_valueless); @@ -2008,8 +2076,8 @@ #if !(defined(_MSC_VER) && defined(ABSL_HAVE_STD_VARIANT)) { // same value as different alternative - variant<int, int> v0(in_place_index_t<0>{}, 42); - variant<int, int> v1(in_place_index_t<1>{}, 42); + variant<int, int> v0(in_place_index<0>, 42); + variant<int, int> v1(in_place_index<1>, 42); std::hash<variant<int, int>> hash; EXPECT_NE(hash(v0), hash(v1)); } @@ -2605,7 +2673,7 @@ }; { using V = absl::variant<TrivialCopyNontrivialMove, int>; - V v1(absl::in_place_index_t<0>{}); + V v1(absl::in_place_index<0>); // this should invoke the move ctor, rather than the trivial copy ctor. V v2(std::move(v1)); EXPECT_TRUE(absl::get<0>(v2).called); @@ -2613,7 +2681,7 @@ { // this case failed to compile before our fix due to a GCC bug. using V = absl::variant<int, TrivialCopyNontrivialMove>; - V v1(absl::in_place_index_t<1>{}); + V v1(absl::in_place_index<1>); // this should invoke the move ctor, rather than the trivial copy ctor. V v2(std::move(v1)); EXPECT_TRUE(absl::get<1>(v2).called);
diff --git a/absl/utility/BUILD.bazel b/absl/utility/BUILD.bazel index 5185ccd..d41317e 100644 --- a/absl/utility/BUILD.bazel +++ b/absl/utility/BUILD.bazel
@@ -1,6 +1,7 @@ load( "//absl:copts/configure_copts.bzl", "ABSL_DEFAULT_COPTS", + "ABSL_DEFAULT_LINKOPTS", "ABSL_TEST_COPTS", ) @@ -12,6 +13,7 @@ name = "utility", hdrs = ["utility.h"], copts = ABSL_DEFAULT_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, deps = [ "//absl/base:base_internal", "//absl/base:config", @@ -23,6 +25,7 @@ name = "utility_test", srcs = ["utility_test.cc"], copts = ABSL_TEST_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, deps = [ ":utility", "//absl/base:core_headers",
diff --git a/absl/utility/utility.h b/absl/utility/utility.h index 853c1fb..7686db1 100644 --- a/absl/utility/utility.h +++ b/absl/utility/utility.h
@@ -113,6 +113,20 @@ using type = integer_sequence<T>; }; +template <typename T> +struct InPlaceTypeTag { + explicit InPlaceTypeTag() = delete; + InPlaceTypeTag(const InPlaceTypeTag&) = delete; + InPlaceTypeTag& operator=(const InPlaceTypeTag&) = delete; +}; + +template <size_t I> +struct InPlaceIndexTag { + explicit InPlaceIndexTag() = delete; + InPlaceIndexTag(const InPlaceIndexTag&) = delete; + InPlaceIndexTag& operator=(const InPlaceIndexTag&) = delete; +}; + } // namespace utility_internal // Compile-time sequences of integers @@ -162,6 +176,7 @@ #endif // ABSL_HAVE_STD_OPTIONAL #if defined(ABSL_HAVE_STD_ANY) || defined(ABSL_HAVE_STD_VARIANT) +using std::in_place_type; using std::in_place_type_t; #else @@ -171,10 +186,14 @@ // be specified, such as with `absl::any`, designed to be a drop-in replacement // for C++17's `std::in_place_type_t`. template <typename T> -struct in_place_type_t {}; +using in_place_type_t = void (*)(utility_internal::InPlaceTypeTag<T>); + +template <typename T> +void in_place_type(utility_internal::InPlaceTypeTag<T>) {} #endif // ABSL_HAVE_STD_ANY || ABSL_HAVE_STD_VARIANT #ifdef ABSL_HAVE_STD_VARIANT +using std::in_place_index; using std::in_place_index_t; #else @@ -184,7 +203,10 @@ // be specified, such as with `absl::any`, designed to be a drop-in replacement // for C++17's `std::in_place_index_t`. template <size_t I> -struct in_place_index_t {}; +using in_place_index_t = void (*)(utility_internal::InPlaceIndexTag<I>); + +template <size_t I> +void in_place_index(utility_internal::InPlaceIndexTag<I>) {} #endif // ABSL_HAVE_STD_VARIANT // Constexpr move and forward
diff --git a/ci/cmake_install_test.sh b/ci/cmake_install_test.sh index e54b783..7195d18 100755 --- a/ci/cmake_install_test.sh +++ b/ci/cmake_install_test.sh
@@ -29,5 +29,5 @@ -e CFLAGS="-Werror" \ -e CXXFLAGS="-Werror" \ gcr.io/google.com/absl-177019/linux_gcc-4.8:20190316 \ - /bin/bash CMake/install_test_project/test.sh + /bin/bash CMake/install_test_project/test.sh $@
diff --git a/ci/linux_clang-latest_libcxx_bazel.sh b/ci/linux_clang-latest_libcxx_bazel.sh index 741e48c..fe9d6aa 100755 --- a/ci/linux_clang-latest_libcxx_bazel.sh +++ b/ci/linux_clang-latest_libcxx_bazel.sh
@@ -32,6 +32,20 @@ COMPILATION_MODE="fastbuild opt" fi +readonly DOCKER_CONTAINER="gcr.io/google.com/absl-177019/linux_clang-latest:20190329" + +# USE_BAZEL_CACHE=1 only works on Kokoro. +# Without access to the credentials this won't work. +if [ ${USE_BAZEL_CACHE:-0} -ne 0 ]; then + DOCKER_EXTRA_ARGS="--volume=${KOKORO_KEYSTORE_DIR}:/keystore:ro ${DOCKER_EXTRA_ARGS:-}" + # Bazel doesn't track changes to tools outside of the workspace + # (e.g. /usr/bin/gcc), so by appending the docker container to the + # remote_http_cache url, we make changes to the container part of + # the cache key. Hashing the key is to make it shorter and url-safe. + container_key=$(echo ${DOCKER_CONTAINER} | sha256sum | head -c 16) + BAZEL_EXTRA_ARGS="--remote_http_cache=https://storage.googleapis.com/absl-bazel-remote-cache/${container_key} --google_credentials=/keystore/73103_absl-bazel-remote-cache ${BAZEL_EXTRA_ARGS:-}" +fi + for std in ${STD}; do for compilation_mode in ${COMPILATION_MODE}; do echo "--------------------------------------------------------------------" @@ -47,7 +61,8 @@ -e BAZEL_CXXOPTS="-std=${std}:-nostdinc++" \ -e BAZEL_LINKOPTS="-L/opt/llvm/libcxx/lib:-lc++:-lc++abi:-lm:-Wl,-rpath=/opt/llvm/libcxx/lib" \ -e CPLUS_INCLUDE_PATH="/opt/llvm/libcxx/include/c++/v1" \ - gcr.io/google.com/absl-177019/linux_clang-latest:20190313 \ + ${DOCKER_EXTRA_ARGS:-} \ + ${DOCKER_CONTAINER} \ /usr/local/bin/bazel test ... \ --compilation_mode=${compilation_mode} \ --copt=-Werror \ @@ -57,6 +72,7 @@ --test_env="GTEST_INSTALL_FAILURE_SIGNAL_HANDLER=1" \ --test_env="TZDIR=/abseil-cpp/absl/time/internal/cctz/testdata/zoneinfo" \ --test_output=errors \ - --test_tag_filters=-benchmark + --test_tag_filters=-benchmark \ + ${BAZEL_EXTRA_ARGS:-} done done
diff --git a/ci/linux_clang-latest_libstdcxx_bazel.sh b/ci/linux_clang-latest_libstdcxx_bazel.sh index d703a77..611b7f2 100755 --- a/ci/linux_clang-latest_libstdcxx_bazel.sh +++ b/ci/linux_clang-latest_libstdcxx_bazel.sh
@@ -32,6 +32,20 @@ COMPILATION_MODE="fastbuild opt" fi +readonly DOCKER_CONTAINER="gcr.io/google.com/absl-177019/linux_clang-latest:20190329" + +# USE_BAZEL_CACHE=1 only works on Kokoro. +# Without access to the credentials this won't work. +if [ ${USE_BAZEL_CACHE:-0} -ne 0 ]; then + DOCKER_EXTRA_ARGS="--volume=${KOKORO_KEYSTORE_DIR}:/keystore:ro ${DOCKER_EXTRA_ARGS:-}" + # Bazel doesn't track changes to tools outside of the workspace + # (e.g. /usr/bin/gcc), so by appending the docker container to the + # remote_http_cache url, we make changes to the container part of + # the cache key. Hashing the key is to make it shorter and url-safe. + container_key=$(echo ${DOCKER_CONTAINER} | sha256sum | head -c 16) + BAZEL_EXTRA_ARGS="--remote_http_cache=https://storage.googleapis.com/absl-bazel-remote-cache/${container_key} --google_credentials=/keystore/73103_absl-bazel-remote-cache ${BAZEL_EXTRA_ARGS:-}" +fi + for std in ${STD}; do for compilation_mode in ${COMPILATION_MODE}; do echo "--------------------------------------------------------------------" @@ -46,7 +60,8 @@ -e BAZEL_COMPILER="llvm" \ -e BAZEL_CXXOPTS="-std=${std}" \ -e CPLUS_INCLUDE_PATH="/usr/include/c++/6" \ - gcr.io/google.com/absl-177019/linux_clang-latest:20190313 \ + ${DOCKER_EXTRA_ARGS:-} \ + ${DOCKER_CONTAINER} \ /usr/local/bin/bazel test ... \ --compilation_mode=${compilation_mode} \ --copt=-Werror \ @@ -56,6 +71,7 @@ --test_env="GTEST_INSTALL_FAILURE_SIGNAL_HANDLER=1" \ --test_env="TZDIR=/abseil-cpp/absl/time/internal/cctz/testdata/zoneinfo" \ --test_output=errors \ - --test_tag_filters=-benchmark + --test_tag_filters=-benchmark \ + ${BAZEL_EXTRA_ARGS:-} done done
diff --git a/ci/linux_gcc-latest_libstdcxx_bazel.sh b/ci/linux_gcc-latest_libstdcxx_bazel.sh index e14a019..2446962 100755 --- a/ci/linux_gcc-latest_libstdcxx_bazel.sh +++ b/ci/linux_gcc-latest_libstdcxx_bazel.sh
@@ -32,6 +32,20 @@ COMPILATION_MODE="fastbuild opt" fi +readonly DOCKER_CONTAINER="gcr.io/google.com/absl-177019/linux_gcc-latest:20190318" + +# USE_BAZEL_CACHE=1 only works on Kokoro. +# Without access to the credentials this won't work. +if [ ${USE_BAZEL_CACHE:-0} -ne 0 ]; then + DOCKER_EXTRA_ARGS="--volume=${KOKORO_KEYSTORE_DIR}:/keystore:ro ${DOCKER_EXTRA_ARGS:-}" + # Bazel doesn't track changes to tools outside of the workspace + # (e.g. /usr/bin/gcc), so by appending the docker container to the + # remote_http_cache url, we make changes to the container part of + # the cache key. Hashing the key is to make it shorter and url-safe. + container_key=$(echo ${DOCKER_CONTAINER} | sha256sum | head -c 16) + BAZEL_EXTRA_ARGS="--remote_http_cache=https://storage.googleapis.com/absl-bazel-remote-cache/${container_key} --google_credentials=/keystore/73103_absl-bazel-remote-cache ${BAZEL_EXTRA_ARGS:-}" +fi + for std in ${STD}; do for compilation_mode in ${COMPILATION_MODE}; do echo "--------------------------------------------------------------------" @@ -44,7 +58,8 @@ --rm \ -e CC="/usr/local/bin/gcc" \ -e BAZEL_CXXOPTS="-std=${std}" \ - gcr.io/google.com/absl-177019/linux_gcc-latest:20190318 \ + ${DOCKER_EXTRA_ARGS:-} \ + ${DOCKER_CONTAINER} \ /usr/local/bin/bazel test ... \ --compilation_mode=${compilation_mode} \ --copt=-Werror \ @@ -54,6 +69,7 @@ --test_env="GTEST_INSTALL_FAILURE_SIGNAL_HANDLER=1" \ --test_env="TZDIR=/abseil-cpp/absl/time/internal/cctz/testdata/zoneinfo" \ --test_output=errors \ - --test_tag_filters=-benchmark + --test_tag_filters=-benchmark \ + ${BAZEL_EXTRA_ARGS:-} done done
diff --git a/ci/macos_xcode_bazel.sh b/ci/macos_xcode_bazel.sh new file mode 100644 index 0000000..e840e9d --- /dev/null +++ b/ci/macos_xcode_bazel.sh
@@ -0,0 +1,41 @@ +#!/bin/bash +# +# Copyright 2019 The Abseil Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# This script is invoked on Kokoro to test Abseil on MacOS. +# It is not hermetic and may break when Kokoro is updated. + +set -euox pipefail + +if [ -z ${ABSEIL_ROOT:-} ]; then + ABSEIL_ROOT="$(realpath $(dirname ${0})/..)" +fi + +# Print the default compiler and Bazel versions. +echo "---------------" +gcc -v +echo "---------------" +bazel version +echo "---------------" + +cd ${ABSEIL_ROOT} + +bazel test ... \ + --copt=-Werror \ + --keep_going \ + --show_timestamps \ + --test_env="TZDIR=${ABSEIL_ROOT}/absl/time/internal/cctz/testdata/zoneinfo" \ + --test_output=errors \ + --test_tag_filters=-benchmark
diff --git a/ci/macos_xcode_cmake.sh b/ci/macos_xcode_cmake.sh new file mode 100644 index 0000000..4892e26 --- /dev/null +++ b/ci/macos_xcode_cmake.sh
@@ -0,0 +1,43 @@ +#!/bin/bash +# +# Copyright 2019 The Abseil Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# This script is invoked on Kokoro to test Abseil on MacOS. +# It is not hermetic and may break when Kokoro is updated. + +set -euox pipefail + +if [ -z ${ABSEIL_ROOT:-} ]; then + ABSEIL_ROOT="$(dirname ${0})/.." +fi +ABSEIL_ROOT=$(realpath ${ABSEIL_ROOT}) + +if [ -z ${ABSL_CMAKE_BUILD_TYPES:-} ]; then + ABSL_CMAKE_BUILD_TYPES="Debug" +fi + +for compilation_mode in ${ABSL_CMAKE_BUILD_TYPES}; do + BUILD_DIR=$(mktemp -d ${compilation_mode}.XXXXXXXX) + cd ${BUILD_DIR} + + # TODO(absl-team): Enable -Werror once all warnings are fixed. + time cmake ${ABSEIL_ROOT} \ + -GXcode \ + -DCMAKE_BUILD_TYPE=${compilation_mode} \ + -DABSL_USE_GOOGLETEST_HEAD=ON \ + -DABSL_RUN_TESTS=ON + time cmake --build . + time ctest -C ${compilation_mode} --output-on-failure +done