diff options
author | Étienne Mollier <emollier@debian.org> | 2022-07-03 13:51:25 +0200 |
---|---|---|
committer | Étienne Mollier <emollier@debian.org> | 2022-07-03 13:51:25 +0200 |
commit | ac1745a2d7dd6e2010b6ea804dd89a0d6918111f (patch) | |
tree | baa360e08891b38e5ec5e6e0fd71459a585733eb | |
parent | 9a5186edead2633a422df47926164e69cd4d3fcd (diff) |
New upstream version 1.0.2
25 files changed, 10859 insertions, 4076 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 5f01ecd..b9421f8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -17,6 +17,7 @@ project(hdf_plugins ) set(CMAKE_POSITION_INDEPENDENT_CODE ON) +set(CMAKE_CXX_STANDARD 14) include(ExternalProject) include(GenerateExportHeader) @@ -75,6 +76,8 @@ if (NOT VBZ_BUILD_ARCHIVE) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) endif() +option(BUILD_SHARED_LIBS "Build shared library for VBZ plugin" ON) + if (ENABLE_CONAN) # # Dependencies: Conan @@ -87,7 +90,7 @@ if (ENABLE_CONAN) include(conan) set(_requirements - "zstd/1.3.4@nanopore/stable") + "zstd/1.4.8@nanopore/stable") set(_generators cmake json) @@ -111,10 +114,14 @@ if (ENABLE_CONAN) list(APPEND _extra_args BUILD_TYPE "${_build_type_${_build_type}}") endif() endif() + if (CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") + list(APPEND CONAN_EXTRA_SETTINGS "compiler.cppstd=${CMAKE_CXX_STANDARD}") + endif() if (CONAN_EXTRA_SETTINGS) list(APPEND _extra_args SETTINGS ${CONAN_EXTRA_SETTINGS} + BUILD missing ) endif() diff --git a/cmake/Findzstd.cmake b/cmake/Findzstd.cmake index 7fd4b4a..493a53b 100644 --- a/cmake/Findzstd.cmake +++ b/cmake/Findzstd.cmake @@ -1,6 +1,8 @@ find_path(ZSTD_INCLUDE_DIR NAMES zstd.h - PATHS ${CONAN_INCLUDE_DIRS_RELEASE} + PATHS + ${CONAN_INCLUDE_DIRS_RELEASE} + ${CONAN_INCLUDE_DIRS_DEBUG} ) set(ZSTD_NAMES zstd zstd_static) @@ -11,7 +13,9 @@ find_library(ZSTD_LIBRARY_RELEASE PATHS ${CONAN_LIB_DIRS_RELEASE} ) find_library(ZSTD_LIBRARY_DEBUG - NAMES ${ZSTD_NAMES_DEBUG} + NAMES + ${ZSTD_NAMES_DEBUG} + ${ZSTD_NAMES} PATHS ${CONAN_LIB_DIRS_DEBUG} ) @@ -68,4 +72,4 @@ if (ZSTD_FOUND) IMPORTED_LOCATION "${ZSTD_LIBRARY}") endif() endif() -endif()
\ No newline at end of file +endif() diff --git a/cmake/ONTFindModuleHelpers.cmake b/cmake/ONTFindModuleHelpers.cmake index d795912..bcc987c 100644 --- a/cmake/ONTFindModuleHelpers.cmake +++ b/cmake/ONTFindModuleHelpers.cmake @@ -172,6 +172,9 @@ macro(ont_find_package_handle_library_components module_name) if(NOT _ONT_FPWC_SKIP_PKG_CONFIG)
find_package(PkgConfig QUIET)
endif()
+ # CMake 3.17+ warns when find_package_handle_standard_args() is called with a name that doesn't
+ # match the find module name; this tells it that we really did mean to do that
+ set(FPHSA_NAME_MISMATCHED TRUE)
foreach(_comp ${_ONT_FPWC_COMPONENTS})
set(_dep_vars)
set(_dep_targets)
@@ -290,6 +293,8 @@ macro(ont_find_package_handle_library_components module_name) "${module_name}::${_comp}")
endif()
endforeach()
+ # we need to unset it again because this is a macro, not a function
+ unset(FPHSA_NAME_MISMATCHED)
if(${module_name}_DEBUG_LIBRARIES)
list(REMOVE_DUPLICATES ${module_name}_DEBUG_LIBRARIES)
endif()
diff --git a/cmake/SignFile.cmake b/cmake/SignFile.cmake index cfa320d..286bacc 100644 --- a/cmake/SignFile.cmake +++ b/cmake/SignFile.cmake @@ -24,7 +24,8 @@ elseif(WIN32) message("Signing file... ${file_to_sign}${comment}") set(SIGN_COMMAND ${SIGNTOOL_EXE} sign "/v" "/sha1" "${MINKNOW_CODE_SIGN_IDENTITY}" - "/t" "http://timestamp.globalsign.com/scripts/" + "/tr" "http://rfc3161timestamp.globalsign.com/advanced" + "/td" "SHA256" ${file_to_sign} ) @@ -32,13 +33,26 @@ else() message(FATAL_ERROR "Cannot sign code on this platform.") endif() -message("Running sign command: ${SIGN_COMMAND}") -execute_process( - COMMAND ${SIGN_COMMAND} - RESULT_VARIABLE result - OUTPUT_VARIABLE output - ERROR_VARIABLE output -) +set(retry_count 10) +foreach(retry_index RANGE ${retry_count}) + message("Running sign command: ${SIGN_COMMAND}") + execute_process( + COMMAND ${SIGN_COMMAND} + RESULT_VARIABLE result + OUTPUT_VARIABLE output + ERROR_VARIABLE output + ) + + if (result EQUAL 0) + break() + endif() + + message(WARN "Signing failed, waiting and retrying (${retry_index}/${retry_count})") + execute_process( + COMMAND ${CMAKE_COMMAND} -E sleep 5 + ) + +endforeach() if (NOT result EQUAL 0) message(FATAL_ERROR "Could not sign file: ${result}: ${output}") diff --git a/cmake/conan.cmake b/cmake/conan.cmake index db9a18a..1bd1289 100644 --- a/cmake/conan.cmake +++ b/cmake/conan.cmake @@ -52,40 +52,49 @@ function(_get_msvc_ide_version result) set(${result} 14 PARENT_SCOPE) elseif(NOT MSVC_VERSION VERSION_LESS 1910 AND MSVC_VERSION VERSION_LESS 1920) set(${result} 15 PARENT_SCOPE) + elseif(NOT MSVC_VERSION VERSION_LESS 1920 AND MSVC_VERSION VERSION_LESS 1930) + set(${result} 16 PARENT_SCOPE) else() message(FATAL_ERROR "Conan: Unknown MSVC compiler version [${MSVC_VERSION}]") endif() endfunction() function(conan_cmake_settings result) - message(STATUS "COMPILER " ${CMAKE_CXX_COMPILER}) - message(STATUS "COMPILER " ${CMAKE_CXX_COMPILER_ID}) - message(STATUS "VERSION " ${CMAKE_CXX_COMPILER_VERSION}) - message(STATUS "FLAGS " ${CMAKE_LANG_FLAGS}) - message(STATUS "LIB ARCH " ${CMAKE_CXX_LIBRARY_ARCHITECTURE}) - message(STATUS "BUILD TYPE " ${CMAKE_BUILD_TYPE}) - message(STATUS "GENERATOR " ${CMAKE_GENERATOR}) - message(STATUS "GENERATOR WIN64 " ${CMAKE_CL_64}) - - message(STATUS "Conan ** WARNING** : This detection of settings from cmake is experimental and incomplete. " - "Please check 'conan.cmake' and contribute") + #message(STATUS "COMPILER " ${CMAKE_CXX_COMPILER}) + #message(STATUS "COMPILER " ${CMAKE_CXX_COMPILER_ID}) + #message(STATUS "VERSION " ${CMAKE_CXX_COMPILER_VERSION}) + #message(STATUS "FLAGS " ${CMAKE_LANG_FLAGS}) + #message(STATUS "LIB ARCH " ${CMAKE_CXX_LIBRARY_ARCHITECTURE}) + #message(STATUS "BUILD TYPE " ${CMAKE_BUILD_TYPE}) + #message(STATUS "GENERATOR " ${CMAKE_GENERATOR}) + #message(STATUS "GENERATOR WIN64 " ${CMAKE_CL_64}) + + message(STATUS "Conan: Automatic detection of conan settings from cmake") parse_arguments(${ARGV}) - set(arch ${ARGUMENTS_ARCH}) - if(CONAN_CMAKE_MULTI) - set(_SETTINGS -g cmake_multi) - else() - set(_SETTINGS -g cmake) - endif() if(ARGUMENTS_BUILD_TYPE) - set(_SETTINGS ${_SETTINGS} -s build_type=${ARGUMENTS_BUILD_TYPE}) + set(_CONAN_SETTING_BUILD_TYPE ${ARGUMENTS_BUILD_TYPE}) elseif(CMAKE_BUILD_TYPE) - set(_SETTINGS ${_SETTINGS} -s build_type=${CMAKE_BUILD_TYPE}) + set(_CONAN_SETTING_BUILD_TYPE ${CMAKE_BUILD_TYPE}) else() message(FATAL_ERROR "Please specify in command line CMAKE_BUILD_TYPE (-DCMAKE_BUILD_TYPE=Release)") endif() + string(TOUPPER ${_CONAN_SETTING_BUILD_TYPE} _CONAN_SETTING_BUILD_TYPE_UPPER) + if (_CONAN_SETTING_BUILD_TYPE_UPPER STREQUAL "DEBUG") + set(_CONAN_SETTING_BUILD_TYPE "Debug") + elseif(_CONAN_SETTING_BUILD_TYPE_UPPER STREQUAL "RELEASE") + set(_CONAN_SETTING_BUILD_TYPE "Release") + elseif(_CONAN_SETTING_BUILD_TYPE_UPPER STREQUAL "RELWITHDEBINFO") + set(_CONAN_SETTING_BUILD_TYPE "RelWithDebInfo") + elseif(_CONAN_SETTING_BUILD_TYPE_UPPER STREQUAL "MINSIZEREL") + set(_CONAN_SETTING_BUILD_TYPE "MinSizeRel") + endif() + + if(ARGUMENTS_ARCH) + set(_CONAN_SETTING_ARCH ${ARGUMENTS_ARCH}) + endif() #handle -s os setting if(CMAKE_SYSTEM_NAME) #use default conan os setting if CMAKE_SYSTEM_NAME is not defined @@ -93,11 +102,11 @@ function(conan_cmake_settings result) if(${CMAKE_SYSTEM_NAME} STREQUAL "Darwin") set(CONAN_SYSTEM_NAME Macos) endif() - set(CONAN_SUPPORTED_PLATFORMS Windows Linux Macos Android iOS FreeBSD) + set(CONAN_SUPPORTED_PLATFORMS Windows Linux Macos Android iOS FreeBSD WindowsStore) list (FIND CONAN_SUPPORTED_PLATFORMS "${CONAN_SYSTEM_NAME}" _index) if (${_index} GREATER -1) #check if the cmake system is a conan supported one - set(_SETTINGS ${_SETTINGS} -s os=${CONAN_SYSTEM_NAME}) + set(_CONAN_SETTING_OS ${CONAN_SYSTEM_NAME}) else() message(FATAL_ERROR "cmake system ${CONAN_SYSTEM_NAME} is not supported by conan. Use one of ${CONAN_SUPPORTED_PLATFORMS}") endif() @@ -114,10 +123,6 @@ function(conan_cmake_settings result) message(FATAL_ERROR "Conan: Neither C or C++ was detected as a language for the project. Unabled to detect compiler version.") endif() - if(arch) - set(_SETTINGS ${_SETTINGS} -s arch=${arch}) - endif() - if (${CMAKE_${LANGUAGE}_COMPILER_ID} STREQUAL GNU) # using GCC # TODO: Handle other params @@ -128,72 +133,74 @@ function(conan_cmake_settings result) if(${MAJOR} GREATER 4) set(COMPILER_VERSION ${MAJOR}) endif() - set(_SETTINGS ${_SETTINGS} -s compiler=gcc -s compiler.version=${COMPILER_VERSION}) + set(_CONAN_SETTING_COMPILER gcc) + set(_CONAN_SETTING_COMPILER_VERSION ${COMPILER_VERSION}) if (USING_CXX) - conan_cmake_detect_gnu_libcxx(_LIBCXX) - set(_SETTINGS ${_SETTINGS} -s compiler.libcxx=${_LIBCXX}) + conan_cmake_detect_unix_libcxx(_LIBCXX) + set(_CONAN_SETTING_COMPILER_LIBCXX ${_LIBCXX}) endif () elseif (${CMAKE_${LANGUAGE}_COMPILER_ID} STREQUAL AppleClang) # using AppleClang string(REPLACE "." ";" VERSION_LIST ${CMAKE_${LANGUAGE}_COMPILER_VERSION}) list(GET VERSION_LIST 0 MAJOR) list(GET VERSION_LIST 1 MINOR) - set(_SETTINGS ${_SETTINGS} -s compiler=apple-clang -s compiler.version=${MAJOR}.${MINOR}) + set(_CONAN_SETTING_COMPILER apple-clang) + set(_CONAN_SETTING_COMPILER_VERSION ${MAJOR}.${MINOR}) if (USING_CXX) - set(_SETTINGS ${_SETTINGS} -s compiler.libcxx=libc++) + conan_cmake_detect_unix_libcxx(_LIBCXX) + set(_CONAN_SETTING_COMPILER_LIBCXX ${_LIBCXX}) endif () elseif (${CMAKE_${LANGUAGE}_COMPILER_ID} STREQUAL Clang) string(REPLACE "." ";" VERSION_LIST ${CMAKE_${LANGUAGE}_COMPILER_VERSION}) list(GET VERSION_LIST 0 MAJOR) list(GET VERSION_LIST 1 MINOR) + set(_CONAN_SETTING_COMPILER clang) + set(_CONAN_SETTING_COMPILER_VERSION ${MAJOR}.${MINOR}) if(APPLE) cmake_policy(GET CMP0025 APPLE_CLANG_POLICY_ENABLED) if(NOT APPLE_CLANG_POLICY_ENABLED) message(STATUS "Conan: APPLE and Clang detected. Assuming apple-clang compiler. Set CMP0025 to avoid it") - set(_SETTINGS ${_SETTINGS} -s compiler=apple-clang -s compiler.version=${MAJOR}.${MINOR}) - else() - set(_SETTINGS ${_SETTINGS} -s compiler=clang -s compiler.version=${MAJOR}.${MINOR}) + set(_CONAN_SETTING_COMPILER apple-clang) endif() - if (USING_CXX) - set(_SETTINGS ${_SETTINGS} -s compiler.libcxx=libc++) - endif () - else() - set(_SETTINGS ${_SETTINGS} -s compiler=clang -s compiler.version=${MAJOR}.${MINOR}) - if (USING_CXX) - conan_cmake_detect_gnu_libcxx(_LIBCXX) - set(_SETTINGS ${_SETTINGS} -s compiler.libcxx=${_LIBCXX}) - endif () endif() + if(${_CONAN_SETTING_COMPILER} STREQUAL clang AND ${MAJOR} GREATER 7) + set(_CONAN_SETTING_COMPILER_VERSION ${MAJOR}) + endif() + if (USING_CXX) + conan_cmake_detect_unix_libcxx(_LIBCXX) + set(_CONAN_SETTING_COMPILER_LIBCXX ${_LIBCXX}) + endif () elseif(${CMAKE_${LANGUAGE}_COMPILER_ID} STREQUAL MSVC) set(_VISUAL "Visual Studio") _get_msvc_ide_version(_VISUAL_VERSION) if("${_VISUAL_VERSION}" STREQUAL "") message(FATAL_ERROR "Conan: Visual Studio not recognized") else() - set(_SETTINGS ${_SETTINGS} -s compiler=${_VISUAL} -s compiler.version=${_VISUAL_VERSION}) + set(_CONAN_SETTING_COMPILER ${_VISUAL}) + set(_CONAN_SETTING_COMPILER_VERSION ${_VISUAL_VERSION}) endif() - if(NOT arch) + if(NOT _CONAN_SETTING_ARCH) if (MSVC_${LANGUAGE}_ARCHITECTURE_ID MATCHES "64") - set(_SETTINGS ${_SETTINGS} -s arch=x86_64) + set(_CONAN_SETTING_ARCH x86_64) elseif (MSVC_${LANGUAGE}_ARCHITECTURE_ID MATCHES "^ARM") message(STATUS "Conan: Using default ARM architecture from MSVC") - set(_SETTINGS ${_SETTINGS} -s arch=armv6) + set(_CONAN_SETTING_ARCH armv6) elseif (MSVC_${LANGUAGE}_ARCHITECTURE_ID MATCHES "86") - set(_SETTINGS ${_SETTINGS} -s arch=x86) + set(_CONAN_SETTING_ARCH x86) else () message(FATAL_ERROR "Conan: Unknown MSVC architecture [${MSVC_${LANGUAGE}_ARCHITECTURE_ID}]") endif() endif() conan_cmake_detect_vs_runtime(_vs_runtime) - message(STATUS "Detected VS runtime: ${_vs_runtime}") - set(_SETTINGS ${_SETTINGS} -s compiler.runtime=${_vs_runtime}) - + message(STATUS "Conan: Detected VS runtime: ${_vs_runtime}") + set(_CONAN_SETTING_COMPILER_RUNTIME ${_vs_runtime}) + if (CMAKE_GENERATOR_TOOLSET) - set(_SETTINGS ${_SETTINGS} -s compiler.toolset=${CMAKE_VS_PLATFORM_TOOLSET}) + set(_CONAN_SETTING_COMPILER_TOOLSET ${CMAKE_VS_PLATFORM_TOOLSET}) elseif(CMAKE_VS_PLATFORM_TOOLSET AND (CMAKE_GENERATOR STREQUAL "Ninja")) - set(_SETTINGS ${_SETTINGS} -s compiler.toolset=${CMAKE_VS_PLATFORM_TOOLSET}) + set(_CONAN_SETTING_COMPILER_TOOLSET ${CMAKE_VS_PLATFORM_TOOLSET}) endif() # Temp fix due to https://github.com/conan-io/cmake-conan/issues/166 elseif (${CMAKE_${LANGUAGE}_COMPILER_ID} STREQUAL Intel) @@ -205,56 +212,113 @@ function(conan_cmake_settings result) set(_CONAN_SETTING_COMPILER_VERSION ${COMPILER_VERSION}) set(_SETTINGS ${_SETTINGS} -s compiler=icc -s compiler.version=${COMPILER_VERSION}) if (USING_CXX) - conan_cmake_detect_gnu_libcxx(_LIBCXX) + conan_cmake_detect_unix_libcxx(_LIBCXX) set(_CONAN_SETTING_COMPILER_LIBCXX ${_LIBCXX}) endif () else() message(FATAL_ERROR "Conan: compiler setup not recognized") endif() + # If profile is defined it is used + if(CMAKE_BUILD_TYPE STREQUAL "Debug" AND ARGUMENTS_DEBUG_PROFILE) + set(_APPLIED_PROFILES ${ARGUMENTS_DEBUG_PROFILE}) + elseif(CMAKE_BUILD_TYPE STREQUAL "Release" AND ARGUMENTS_RELEASE_PROFILE) + set(_APPLIED_PROFILES ${ARGUMENTS_RELEASE_PROFILE}) + elseif(CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo" AND ARGUMENTS_RELWITHDEBINFO_PROFILE) + set(_APPLIED_PROFILES ${ARGUMENTS_RELWITHDEBINFO_PROFILE}) + elseif(CMAKE_BUILD_TYPE STREQUAL "MinSizeRel" AND ARGUMENTS_MINSIZEREL_PROFILE) + set(_APPLIED_PROFILES ${ARGUMENTS_MINSIZEREL_PROFILE}) + elseif(ARGUMENTS_PROFILE) + set(_APPLIED_PROFILES ${ARGUMENTS_PROFILE}) + endif() + + foreach(ARG ${_APPLIED_PROFILES}) + set(_SETTINGS ${_SETTINGS} -pr ${ARG}) + endforeach() + + if(NOT _SETTINGS OR ARGUMENTS_PROFILE_AUTO STREQUAL "ALL") + set(ARGUMENTS_PROFILE_AUTO arch build_type compiler compiler.version + compiler.runtime compiler.libcxx compiler.toolset) + endif() + + # Automatic from CMake + foreach(ARG ${ARGUMENTS_PROFILE_AUTO}) + string(TOUPPER ${ARG} _arg_name) + string(REPLACE "." "_" _arg_name ${_arg_name}) + if(_CONAN_SETTING_${_arg_name}) + set(_SETTINGS ${_SETTINGS} -s ${ARG}=${_CONAN_SETTING_${_arg_name}}) + endif() + endforeach() + foreach(ARG ${ARGUMENTS_SETTINGS}) set(_SETTINGS ${_SETTINGS} -s ${ARG}) endforeach() + message(STATUS "Conan: Settings= ${_SETTINGS}") + set(${result} ${_SETTINGS} PARENT_SCOPE) endfunction() -function(conan_cmake_detect_gnu_libcxx result) - # Allow -D_GLIBCXX_USE_CXX11_ABI=ON/OFF as argument to cmake - if(DEFINED _GLIBCXX_USE_CXX11_ABI) - if(_GLIBCXX_USE_CXX11_ABI) - set(${result} libstdc++11 PARENT_SCOPE) - return() - else() - set(${result} libstdc++ PARENT_SCOPE) - return() +function(conan_cmake_detect_unix_libcxx result) + set(compile_options) + + # Take into account any -stdlib in compile options + get_directory_property(options DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} COMPILE_OPTIONS) + foreach(option ${options}) + if(option MATCHES "^-std") + set(compile_options ${compile_options} "${option}") endif() - endif() + endforeach() - # Check if there's any add_definitions(-D_GLIBCXX_USE_CXX11_ABI=0) + # Take into account any _GLIBCXX_USE_CXX11_ABI in compile definitions get_directory_property(defines DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} COMPILE_DEFINITIONS) foreach(define ${defines}) - if(define STREQUAL "_GLIBCXX_USE_CXX11_ABI=0") - set(${result} libstdc++ PARENT_SCOPE) - return() + if(define MATCHES "_GLIBCXX_USE_CXX11_ABI") + if(define MATCHES "^-D") + set(compile_options ${compile_options} "${define}") + else() + set(compile_options ${compile_options} "-D${define}") + endif() endif() endforeach() - # Use C++11 stdlib as default if gcc is 5.1+ - if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS "5.1") - set(${result} libstdc++ PARENT_SCOPE) + execute_process( + COMMAND ${CMAKE_COMMAND} -E echo "#include <string>" + COMMAND ${CMAKE_CXX_COMPILER} -x c++ ${compile_options} -E -dM - + OUTPUT_VARIABLE string_defines + ) + + if(string_defines MATCHES "#define __GLIBCXX__") + # Allow -D_GLIBCXX_USE_CXX11_ABI=ON/OFF as argument to cmake + if(DEFINED _GLIBCXX_USE_CXX11_ABI) + if(_GLIBCXX_USE_CXX11_ABI) + set(${result} libstdc++11 PARENT_SCOPE) + return() + else() + set(${result} libstdc++ PARENT_SCOPE) + return() + endif() + endif() + + if(string_defines MATCHES "#define _GLIBCXX_USE_CXX11_ABI 1\n") + set(${result} libstdc++11 PARENT_SCOPE) + else() + # Either the compiler is missing the define because it is old, and so + # it can't use the new abi, or the compiler was configured to use the + # old abi by the user or distro (e.g. devtoolset on RHEL/CentOS) + set(${result} libstdc++ PARENT_SCOPE) + endif() else() - set(${result} libstdc++11 PARENT_SCOPE) + set(${result} libc++ PARENT_SCOPE) endif() endfunction() - function(conan_cmake_detect_vs_runtime result) string(TOUPPER ${CMAKE_BUILD_TYPE} build_type) set(variables CMAKE_CXX_FLAGS_${build_type} CMAKE_C_FLAGS_${build_type} CMAKE_CXX_FLAGS CMAKE_C_FLAGS) foreach(variable ${variables}) - string(REPLACE " " ";" flags ${${variable}}) + string(REPLACE " " ";" flags "${${variable}}") foreach (flag ${flags}) if(${flag} STREQUAL "/MD" OR ${flag} STREQUAL "/MDd" OR ${flag} STREQUAL "/MT" OR ${flag} STREQUAL "/MTd") string(SUBSTRING ${flag} 1 -1 runtime) @@ -272,10 +336,12 @@ endfunction() macro(parse_arguments) - set(options BASIC_SETUP CMAKE_TARGETS UPDATE KEEP_RPATHS NO_OUTPUT_DIRS) - set(oneValueArgs CONANFILE DEBUG_PROFILE RELEASE_PROFILE RELWITHDEBINFO_PROFILE MINSIZEREL_PROFILE PROFILE ARCH BUILD_TYPE) - set(multiValueArgs REQUIRES OPTIONS IMPORTS SETTINGS BUILD CONAN_COMMAND) - cmake_parse_arguments(ARGUMENTS "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN} ) + set(options BASIC_SETUP CMAKE_TARGETS UPDATE KEEP_RPATHS NO_LOAD NO_OUTPUT_DIRS OUTPUT_QUIET NO_IMPORTS) + set(oneValueArgs CONANFILE ARCH BUILD_TYPE INSTALL_FOLDER CONAN_COMMAND) + set(multiValueArgs DEBUG_PROFILE RELEASE_PROFILE RELWITHDEBINFO_PROFILE MINSIZEREL_PROFILE + PROFILE REQUIRES OPTIONS IMPORTS SETTINGS BUILD ENV GENERATORS PROFILE_AUTO + INSTALL_ARGS) + cmake_parse_arguments(ARGUMENTS "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) endmacro() function(conan_cmake_install) @@ -286,6 +352,12 @@ function(conan_cmake_install) # cmake does not identify conan as command, even if it is +x and it is in the path parse_arguments(${ARGV}) + if(CONAN_CMAKE_MULTI) + set(ARGUMENTS_GENERATORS ${ARGUMENTS_GENERATORS} cmake_multi) + else() + set(ARGUMENTS_GENERATORS ${ARGUMENTS_GENERATORS} cmake) + endif() + set(CONAN_BUILD_POLICY "") foreach(ARG ${ARGUMENTS_BUILD}) if(${ARG} STREQUAL "all") @@ -305,37 +377,43 @@ function(conan_cmake_install) set(CONANFILE ${CMAKE_CURRENT_SOURCE_DIR}/${ARGUMENTS_CONANFILE}) # A conan file has been specified - apply specified options as well if provided foreach(ARG ${ARGUMENTS_OPTIONS}) - set(CONAN_OPTIONS ${CONAN_OPTIONS} -o ${ARG}) + set(CONAN_OPTIONS ${CONAN_OPTIONS} -o=${ARG}) endforeach() else() set(CONANFILE ".") endif() - if(CMAKE_BUILD_TYPE STREQUAL "Debug" AND ARGUMENTS_DEBUG_PROFILE) - set(settings -pr ${ARGUMENTS_DEBUG_PROFILE}) - endif() - if(CMAKE_BUILD_TYPE STREQUAL "Release" AND ARGUMENTS_RELEASE_PROFILE) - set(settings -pr ${ARGUMENTS_RELEASE_PROFILE}) - endif() - if(CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo" AND ARGUMENTS_RELWITHDEBINFO_PROFILE) - set(settings -pr ${ARGUMENTS_RELWITHDEBINFO_PROFILE}) - endif() - if(CMAKE_BUILD_TYPE STREQUAL "MinSizeRel" AND ARGUMENTS_MINSIZEREL_PROFILE) - set(settings -pr ${ARGUMENTS_MINSIZEREL_PROFILE}) - endif() - if(ARGUMENTS_PROFILE) - set(settings -pr ${ARGUMENTS_PROFILE}) - endif() if(ARGUMENTS_UPDATE) set(CONAN_INSTALL_UPDATE --update) endif() - set(conan_args install ${CONANFILE} ${settings} ${CONAN_BUILD_POLICY} ${CONAN_INSTALL_UPDATE} ${CONAN_OPTIONS}) + if(ARGUMENTS_NO_IMPORTS) + set(CONAN_INSTALL_NO_IMPORTS --no-imports) + endif() + set(CONAN_INSTALL_FOLDER "") + if(ARGUMENTS_INSTALL_FOLDER) + set(CONAN_INSTALL_FOLDER -if=${ARGUMENTS_INSTALL_FOLDER}) + endif() + foreach(ARG ${ARGUMENTS_GENERATORS}) + set(CONAN_GENERATORS ${CONAN_GENERATORS} -g=${ARG}) + endforeach() + foreach(ARG ${ARGUMENTS_ENV}) + set(CONAN_ENV_VARS ${CONAN_ENV_VARS} -e=${ARG}) + endforeach() + set(conan_args install ${CONANFILE} ${settings} ${CONAN_ENV_VARS} ${CONAN_GENERATORS} ${CONAN_BUILD_POLICY} ${CONAN_INSTALL_UPDATE} ${CONAN_INSTALL_NO_IMPORTS} ${CONAN_OPTIONS} ${CONAN_INSTALL_FOLDER} ${ARGUMENTS_INSTALL_ARGS}) string (REPLACE ";" " " _conan_args "${conan_args}") message(STATUS "Conan executing: ${conan_command} ${_conan_args}") - execute_process(COMMAND ${conan_command} ${conan_args} - RESULT_VARIABLE return_code - WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) + if(ARGUMENTS_OUTPUT_QUIET) + execute_process(COMMAND ${conan_command} ${conan_args} + RESULT_VARIABLE return_code + OUTPUT_VARIABLE conan_output + ERROR_VARIABLE conan_output + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) + else() + execute_process(COMMAND ${conan_command} ${conan_args} + RESULT_VARIABLE return_code + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) + endif() if(NOT "${return_code}" STREQUAL "0") message(FATAL_ERROR "Conan install failed='${return_code}'") @@ -347,9 +425,10 @@ endfunction() function(conan_cmake_setup_conanfile) parse_arguments(${ARGV}) if(ARGUMENTS_CONANFILE) + get_filename_component(_CONANFILE_NAME ${ARGUMENTS_CONANFILE} NAME) # configure_file will make sure cmake re-runs when conanfile is updated - configure_file(${ARGUMENTS_CONANFILE} ${ARGUMENTS_CONANFILE}.junk) - file(REMOVE ${CMAKE_CURRENT_BINARY_DIR}/${ARGUMENTS_CONANFILE}.junk) + configure_file(${ARGUMENTS_CONANFILE} ${CMAKE_CURRENT_BINARY_DIR}/${_CONANFILE_NAME}.junk) + file(REMOVE ${CMAKE_CURRENT_BINARY_DIR}/${_CONANFILE_NAME}.junk) else() conan_cmake_generate_conanfile(${ARGV}) endif() @@ -385,11 +464,16 @@ macro(conan_load_buildinfo) else() set(_CONANBUILDINFO conanbuildinfo.cmake) endif() + if(ARGUMENTS_INSTALL_FOLDER) + set(_CONANBUILDINFOFOLDER ${ARGUMENTS_INSTALL_FOLDER}) + else() + set(_CONANBUILDINFOFOLDER ${CMAKE_CURRENT_BINARY_DIR}) + endif() # Checks for the existence of conanbuildinfo.cmake, and loads it # important that it is macro, so variables defined at parent scope - if(EXISTS "${CMAKE_CURRENT_BINARY_DIR}/${_CONANBUILDINFO}") + if(EXISTS "${_CONANBUILDINFOFOLDER}/${_CONANBUILDINFO}") message(STATUS "Conan: Loading ${_CONANBUILDINFO}") - include(${CMAKE_CURRENT_BINARY_DIR}/${_CONANBUILDINFO}) + include(${_CONANBUILDINFOFOLDER}/${_CONANBUILDINFO}) else() message(FATAL_ERROR "${_CONANBUILDINFO} doesn't exist in ${CMAKE_CURRENT_BINARY_DIR}") endif() @@ -399,16 +483,19 @@ endmacro() macro(conan_cmake_run) parse_arguments(${ARGV}) - if(CMAKE_CONFIGURATION_TYPES AND NOT CMAKE_BUILD_TYPE AND NOT CONAN_EXPORTED) + if(CMAKE_CONFIGURATION_TYPES AND NOT CMAKE_BUILD_TYPE AND NOT CONAN_EXPORTED + AND NOT ARGUMENTS_BUILD_TYPE) set(CONAN_CMAKE_MULTI ON) message(STATUS "Conan: Using cmake-multi generator") else() set(CONAN_CMAKE_MULTI OFF) endif() + if(NOT CONAN_EXPORTED) conan_cmake_setup_conanfile(${ARGV}) if(CONAN_CMAKE_MULTI) foreach(CMAKE_BUILD_TYPE "Release" "Debug") + set(ENV{CONAN_IMPORT_PATH} ${CMAKE_BUILD_TYPE}) conan_cmake_settings(settings ${ARGV}) conan_cmake_install(SETTINGS ${settings} ${ARGV}) endforeach() @@ -419,7 +506,9 @@ macro(conan_cmake_run) endif() endif() - conan_load_buildinfo() + if (NOT ARGUMENTS_NO_LOAD) + conan_load_buildinfo() + endif() if(ARGUMENTS_BASIC_SETUP) foreach(_option CMAKE_TARGETS KEEP_RPATHS NO_OUTPUT_DIRS) @@ -434,3 +523,52 @@ macro(conan_cmake_run) conan_basic_setup(${_setup_options}) endif() endmacro() + +macro(conan_check) + # Checks conan availability in PATH + # Arguments REQUIRED and VERSION are optional + # Example usage: + # conan_check(VERSION 1.0.0 REQUIRED) + message(STATUS "Conan: checking conan executable in path") + set(options REQUIRED) + set(oneValueArgs VERSION) + cmake_parse_arguments(CONAN "${options}" "${oneValueArgs}" "" ${ARGN}) + + find_program(CONAN_CMD conan) + if(NOT CONAN_CMD AND CONAN_REQUIRED) + message(FATAL_ERROR "Conan executable not found!") + endif() + message(STATUS "Conan: Found program ${CONAN_CMD}") + execute_process(COMMAND ${CONAN_CMD} --version + OUTPUT_VARIABLE CONAN_VERSION_OUTPUT + ERROR_VARIABLE CONAN_VERSION_OUTPUT) + message(STATUS "Conan: Version found ${CONAN_VERSION_OUTPUT}") + + if(DEFINED CONAN_VERSION) + string(REGEX MATCH ".*Conan version ([0-9]+\.[0-9]+\.[0-9]+)" FOO + "${CONAN_VERSION_OUTPUT}") + if(${CMAKE_MATCH_1} VERSION_LESS ${CONAN_VERSION}) + message(FATAL_ERROR "Conan outdated. Installed: ${CMAKE_MATCH_1}, \ + required: ${CONAN_VERSION}. Consider updating via 'pip \ + install conan==${CONAN_VERSION}'.") + endif() + endif() +endmacro() + +macro(conan_add_remote) + # Adds a remote + # Arguments URL and NAME are required, INDEX is optional + # Example usage: + # conan_add_remote(NAME bincrafters INDEX 1 + # URL https://api.bintray.com/conan/bincrafters/public-conan) + set(oneValueArgs URL NAME INDEX) + cmake_parse_arguments(CONAN "" "${oneValueArgs}" "" ${ARGN}) + + if(DEFINED CONAN_INDEX) + set(CONAN_INDEX_ARG "-i ${CONAN_INDEX}") + endif() + + message(STATUS "Conan: Adding ${CONAN_NAME} remote repository (${CONAN_URL})") + execute_process(COMMAND ${CONAN_CMD} remote add ${CONAN_NAME} ${CONAN_URL} + ${CONAN_INDEX_ARG} -f) +endmacro() diff --git a/python/test/requirements_1.10.txt b/python/test/requirements_1.10.txt index 0146f57..e1195fe 100644 --- a/python/test/requirements_1.10.txt +++ b/python/test/requirements_1.10.txt @@ -1 +1,4 @@ -h5py==2.9.0
\ No newline at end of file +# h5py 2 support was dropped in Python 3.9 +h5py==2.10.0 +# numpy 1.18.5 is the last version that supports Python 3.5 +numpy==1.18.5 diff --git a/python/test/requirements_1.12.txt b/python/test/requirements_1.12.txt new file mode 100644 index 0000000..b46db0d --- /dev/null +++ b/python/test/requirements_1.12.txt @@ -0,0 +1,2 @@ +# Originally built against Python 3.9 +h5py==3.6.0 diff --git a/third_party/catch2/catch.hpp b/third_party/catch2/catch.hpp index b1b2411..db1fed3 100644 --- a/third_party/catch2/catch.hpp +++ b/third_party/catch2/catch.hpp @@ -1,9 +1,9 @@ /* - * Catch v2.5.0 - * Generated: 2018-11-26 20:46:12.165372 + * Catch v2.13.8 + * Generated: 2022-01-03 21:20:09.589503 * ---------------------------------------------------------- * This file has been merged from multiple headers. Please don't edit it directly - * Copyright (c) 2018 Two Blue Cubes Ltd. All rights reserved. + * Copyright (c) 2022 Two Blue Cubes Ltd. All rights reserved. * * Distributed under the Boost Software License, Version 1.0. (See accompanying * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -14,8 +14,8 @@ #define CATCH_VERSION_MAJOR 2 -#define CATCH_VERSION_MINOR 5 -#define CATCH_VERSION_PATCH 0 +#define CATCH_VERSION_MINOR 13 +#define CATCH_VERSION_PATCH 8 #ifdef __clang__ # pragma clang system_header @@ -36,10 +36,11 @@ # pragma clang diagnostic ignored "-Wcovered-switch-default" # endif #elif defined __GNUC__ - // GCC likes to warn on REQUIREs, and we cannot suppress them - // locally because g++'s support for _Pragma is lacking in older, - // still supported, versions -# pragma GCC diagnostic ignored "-Wparentheses" + // Because REQUIREs trigger GCC's -Wparentheses, and because still + // supported version of g++ have only buggy support for _Pragmas, + // Wparentheses have to be suppressed globally. +# pragma GCC diagnostic ignored "-Wparentheses" // See #674 for details + # pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Wunused-variable" # pragma GCC diagnostic ignored "-Wpadded" @@ -65,13 +66,16 @@ #if !defined(CATCH_CONFIG_IMPL_ONLY) // start catch_platform.h +// See e.g.: +// https://opensource.apple.com/source/CarbonHeaders/CarbonHeaders-18.1/TargetConditionals.h.auto.html #ifdef __APPLE__ -# include <TargetConditionals.h> -# if TARGET_OS_OSX == 1 -# define CATCH_PLATFORM_MAC -# elif TARGET_OS_IPHONE == 1 -# define CATCH_PLATFORM_IPHONE -# endif +# include <TargetConditionals.h> +# if (defined(TARGET_OS_OSX) && TARGET_OS_OSX == 1) || \ + (defined(TARGET_OS_MAC) && TARGET_OS_MAC == 1) +# define CATCH_PLATFORM_MAC +# elif (defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE == 1) +# define CATCH_PLATFORM_IPHONE +# endif #elif defined(linux) || defined(__linux) || defined(__linux__) # define CATCH_PLATFORM_LINUX @@ -131,30 +135,51 @@ namespace Catch { #endif -#if defined(CATCH_CPP17_OR_GREATER) -# define CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS +// Only GCC compiler should be used in this block, so other compilers trying to +// mask themselves as GCC should be ignored. +#if defined(__GNUC__) && !defined(__clang__) && !defined(__ICC) && !defined(__CUDACC__) && !defined(__LCC__) +# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION _Pragma( "GCC diagnostic push" ) +# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION _Pragma( "GCC diagnostic pop" ) + +# define CATCH_INTERNAL_IGNORE_BUT_WARN(...) (void)__builtin_constant_p(__VA_ARGS__) + #endif -#ifdef __clang__ +#if defined(__clang__) -# define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ - _Pragma( "clang diagnostic push" ) \ - _Pragma( "clang diagnostic ignored \"-Wexit-time-destructors\"" ) \ - _Pragma( "clang diagnostic ignored \"-Wglobal-constructors\"") -# define CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS \ - _Pragma( "clang diagnostic pop" ) - -# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \ - _Pragma( "clang diagnostic push" ) \ - _Pragma( "clang diagnostic ignored \"-Wparentheses\"" ) -# define CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS \ - _Pragma( "clang diagnostic pop" ) - -# define CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS \ - _Pragma( "clang diagnostic push" ) \ - _Pragma( "clang diagnostic ignored \"-Wunused-variable\"" ) -# define CATCH_INTERNAL_UNSUPPRESS_UNUSED_WARNINGS \ - _Pragma( "clang diagnostic pop" ) +# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION _Pragma( "clang diagnostic push" ) +# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION _Pragma( "clang diagnostic pop" ) + +// As of this writing, IBM XL's implementation of __builtin_constant_p has a bug +// which results in calls to destructors being emitted for each temporary, +// without a matching initialization. In practice, this can result in something +// like `std::string::~string` being called on an uninitialized value. +// +// For example, this code will likely segfault under IBM XL: +// ``` +// REQUIRE(std::string("12") + "34" == "1234") +// ``` +// +// Therefore, `CATCH_INTERNAL_IGNORE_BUT_WARN` is not implemented. +# if !defined(__ibmxl__) && !defined(__CUDACC__) +# define CATCH_INTERNAL_IGNORE_BUT_WARN(...) (void)__builtin_constant_p(__VA_ARGS__) /* NOLINT(cppcoreguidelines-pro-type-vararg, hicpp-vararg) */ +# endif + +# define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ + _Pragma( "clang diagnostic ignored \"-Wexit-time-destructors\"" ) \ + _Pragma( "clang diagnostic ignored \"-Wglobal-constructors\"") + +# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \ + _Pragma( "clang diagnostic ignored \"-Wparentheses\"" ) + +# define CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS \ + _Pragma( "clang diagnostic ignored \"-Wunused-variable\"" ) + +# define CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS \ + _Pragma( "clang diagnostic ignored \"-Wgnu-zero-variadic-macro-arguments\"" ) + +# define CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \ + _Pragma( "clang diagnostic ignored \"-Wunused-template\"" ) #endif // __clang__ @@ -179,6 +204,7 @@ namespace Catch { // Android somehow still does not support std::to_string #if defined(__ANDROID__) # define CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING +# define CATCH_INTERNAL_CONFIG_ANDROID_LOGWRITE #endif //////////////////////////////////////////////////////////////////////////////// @@ -203,20 +229,16 @@ namespace Catch { // some versions of cygwin (most) do not support std::to_string. Use the libstd check. // https://gcc.gnu.org/onlinedocs/gcc-4.8.2/libstdc++/api/a01053_source.html line 2812-2813 # if !((__cplusplus >= 201103L) && defined(_GLIBCXX_USE_C99) \ - && !defined(_GLIBCXX_HAVE_BROKEN_VSWPRINTF)) + && !defined(_GLIBCXX_HAVE_BROKEN_VSWPRINTF)) -# define CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING +# define CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING # endif #endif // __CYGWIN__ //////////////////////////////////////////////////////////////////////////////// // Visual C++ -#ifdef _MSC_VER - -# if _MSC_VER >= 1900 // Visual Studio 2015 or newer -# define CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS -# endif +#if defined(_MSC_VER) // Universal Windows platform does not support SEH // Or console colours (or console at all...) @@ -226,13 +248,25 @@ namespace Catch { # define CATCH_INTERNAL_CONFIG_WINDOWS_SEH # endif +# if !defined(__clang__) // Handle Clang masquerading for msvc + // MSVC traditional preprocessor needs some workaround for __VA_ARGS__ // _MSVC_TRADITIONAL == 0 means new conformant preprocessor // _MSVC_TRADITIONAL == 1 means old traditional non-conformant preprocessor -# if !defined(_MSVC_TRADITIONAL) || (defined(_MSVC_TRADITIONAL) && _MSVC_TRADITIONAL) -# define CATCH_INTERNAL_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR -# endif +# if !defined(_MSVC_TRADITIONAL) || (defined(_MSVC_TRADITIONAL) && _MSVC_TRADITIONAL) +# define CATCH_INTERNAL_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR +# endif // MSVC_TRADITIONAL + +// Only do this if we're not using clang on Windows, which uses `diagnostic push` & `diagnostic pop` +# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION __pragma( warning(push) ) +# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION __pragma( warning(pop) ) +# endif // __clang__ + +#endif // _MSC_VER +#if defined(_REENTRANT) || defined(_MSC_VER) +// Enable async processing, as -pthread is specified or no additional linking is required +# define CATCH_INTERNAL_CONFIG_USE_ASYNC #endif // _MSC_VER //////////////////////////////////////////////////////////////////////////////// @@ -265,30 +299,56 @@ namespace Catch { #endif //////////////////////////////////////////////////////////////////////////////// -// Check if string_view is available and usable -// The check is split apart to work around v140 (VS2015) preprocessor issue... -#if defined(__has_include) -#if __has_include(<string_view>) && defined(CATCH_CPP17_OR_GREATER) -# define CATCH_INTERNAL_CONFIG_CPP17_STRING_VIEW + +// RTX is a special version of Windows that is real time. +// This means that it is detected as Windows, but does not provide +// the same set of capabilities as real Windows does. +#if defined(UNDER_RTSS) || defined(RTX64_BUILD) + #define CATCH_INTERNAL_CONFIG_NO_WINDOWS_SEH + #define CATCH_INTERNAL_CONFIG_NO_ASYNC + #define CATCH_CONFIG_COLOUR_NONE #endif + +#if !defined(_GLIBCXX_USE_C99_MATH_TR1) +#define CATCH_INTERNAL_CONFIG_GLOBAL_NEXTAFTER #endif -//////////////////////////////////////////////////////////////////////////////// -// Check if variant is available and usable +// Various stdlib support checks that require __has_include #if defined(__has_include) -# if __has_include(<variant>) && defined(CATCH_CPP17_OR_GREATER) -# if defined(__clang__) && (__clang_major__ < 8) - // work around clang bug with libstdc++ https://bugs.llvm.org/show_bug.cgi?id=31852 - // fix should be in clang 8, workaround in libstdc++ 8.2 -# include <ciso646> -# if defined(__GLIBCXX__) && defined(_GLIBCXX_RELEASE) && (_GLIBCXX_RELEASE < 9) -# define CATCH_CONFIG_NO_CPP17_VARIANT -# else -# define CATCH_INTERNAL_CONFIG_CPP17_VARIANT -# endif // defined(__GLIBCXX__) && defined(_GLIBCXX_RELEASE) && (_GLIBCXX_RELEASE < 9) -# endif // defined(__clang__) && (__clang_major__ < 8) -# endif // __has_include(<variant>) && defined(CATCH_CPP17_OR_GREATER) -#endif // __has_include + // Check if string_view is available and usable + #if __has_include(<string_view>) && defined(CATCH_CPP17_OR_GREATER) + # define CATCH_INTERNAL_CONFIG_CPP17_STRING_VIEW + #endif + + // Check if optional is available and usable + # if __has_include(<optional>) && defined(CATCH_CPP17_OR_GREATER) + # define CATCH_INTERNAL_CONFIG_CPP17_OPTIONAL + # endif // __has_include(<optional>) && defined(CATCH_CPP17_OR_GREATER) + + // Check if byte is available and usable + # if __has_include(<cstddef>) && defined(CATCH_CPP17_OR_GREATER) + # include <cstddef> + # if defined(__cpp_lib_byte) && (__cpp_lib_byte > 0) + # define CATCH_INTERNAL_CONFIG_CPP17_BYTE + # endif + # endif // __has_include(<cstddef>) && defined(CATCH_CPP17_OR_GREATER) + + // Check if variant is available and usable + # if __has_include(<variant>) && defined(CATCH_CPP17_OR_GREATER) + # if defined(__clang__) && (__clang_major__ < 8) + // work around clang bug with libstdc++ https://bugs.llvm.org/show_bug.cgi?id=31852 + // fix should be in clang 8, workaround in libstdc++ 8.2 + # include <ciso646> + # if defined(__GLIBCXX__) && defined(_GLIBCXX_RELEASE) && (_GLIBCXX_RELEASE < 9) + # define CATCH_CONFIG_NO_CPP17_VARIANT + # else + # define CATCH_INTERNAL_CONFIG_CPP17_VARIANT + # endif // defined(__GLIBCXX__) && defined(_GLIBCXX_RELEASE) && (_GLIBCXX_RELEASE < 9) + # else + # define CATCH_INTERNAL_CONFIG_CPP17_VARIANT + # endif // defined(__clang__) && (__clang_major__ < 8) + # endif // __has_include(<variant>) && defined(CATCH_CPP17_OR_GREATER) +#endif // defined(__has_include) #if defined(CATCH_INTERNAL_CONFIG_COUNTER) && !defined(CATCH_CONFIG_NO_COUNTER) && !defined(CATCH_CONFIG_COUNTER) # define CATCH_CONFIG_COUNTER @@ -309,8 +369,8 @@ namespace Catch { # define CATCH_CONFIG_CPP11_TO_STRING #endif -#if defined(CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS) && !defined(CATCH_CONFIG_NO_CPP17_UNCAUGHT_EXCEPTIONS) && !defined(CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS) -# define CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS +#if defined(CATCH_INTERNAL_CONFIG_CPP17_OPTIONAL) && !defined(CATCH_CONFIG_NO_CPP17_OPTIONAL) && !defined(CATCH_CONFIG_CPP17_OPTIONAL) +# define CATCH_CONFIG_CPP17_OPTIONAL #endif #if defined(CATCH_INTERNAL_CONFIG_CPP17_STRING_VIEW) && !defined(CATCH_CONFIG_NO_CPP17_STRING_VIEW) && !defined(CATCH_CONFIG_CPP17_STRING_VIEW) @@ -321,6 +381,10 @@ namespace Catch { # define CATCH_CONFIG_CPP17_VARIANT #endif +#if defined(CATCH_INTERNAL_CONFIG_CPP17_BYTE) && !defined(CATCH_CONFIG_NO_CPP17_BYTE) && !defined(CATCH_CONFIG_CPP17_BYTE) +# define CATCH_CONFIG_CPP17_BYTE +#endif + #if defined(CATCH_CONFIG_EXPERIMENTAL_REDIRECT) # define CATCH_INTERNAL_CONFIG_NEW_CAPTURE #endif @@ -337,17 +401,53 @@ namespace Catch { # define CATCH_CONFIG_POLYFILL_ISNAN #endif +#if defined(CATCH_INTERNAL_CONFIG_USE_ASYNC) && !defined(CATCH_INTERNAL_CONFIG_NO_ASYNC) && !defined(CATCH_CONFIG_NO_USE_ASYNC) && !defined(CATCH_CONFIG_USE_ASYNC) +# define CATCH_CONFIG_USE_ASYNC +#endif + +#if defined(CATCH_INTERNAL_CONFIG_ANDROID_LOGWRITE) && !defined(CATCH_CONFIG_NO_ANDROID_LOGWRITE) && !defined(CATCH_CONFIG_ANDROID_LOGWRITE) +# define CATCH_CONFIG_ANDROID_LOGWRITE +#endif + +#if defined(CATCH_INTERNAL_CONFIG_GLOBAL_NEXTAFTER) && !defined(CATCH_CONFIG_NO_GLOBAL_NEXTAFTER) && !defined(CATCH_CONFIG_GLOBAL_NEXTAFTER) +# define CATCH_CONFIG_GLOBAL_NEXTAFTER +#endif + +// Even if we do not think the compiler has that warning, we still have +// to provide a macro that can be used by the code. +#if !defined(CATCH_INTERNAL_START_WARNINGS_SUPPRESSION) +# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION +#endif +#if !defined(CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION) +# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION +#endif #if !defined(CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS) # define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS -# define CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS #endif #if !defined(CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS) # define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS -# define CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS #endif #if !defined(CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS) # define CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS -# define CATCH_INTERNAL_UNSUPPRESS_UNUSED_WARNINGS +#endif +#if !defined(CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS) +# define CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS +#endif + +// The goal of this macro is to avoid evaluation of the arguments, but +// still have the compiler warn on problems inside... +#if !defined(CATCH_INTERNAL_IGNORE_BUT_WARN) +# define CATCH_INTERNAL_IGNORE_BUT_WARN(...) +#endif + +#if defined(__APPLE__) && defined(__apple_build_version__) && (__clang_major__ < 10) +# undef CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS +#elif defined(__clang__) && (__clang_major__ < 5) +# undef CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS +#endif + +#if !defined(CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS) +# define CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS #endif #if defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) @@ -407,12 +507,12 @@ namespace Catch { line( _line ) {} - SourceLineInfo( SourceLineInfo const& other ) = default; - SourceLineInfo( SourceLineInfo && ) = default; - SourceLineInfo& operator = ( SourceLineInfo const& ) = default; - SourceLineInfo& operator = ( SourceLineInfo && ) = default; + SourceLineInfo( SourceLineInfo const& other ) = default; + SourceLineInfo& operator = ( SourceLineInfo const& ) = default; + SourceLineInfo( SourceLineInfo&& ) noexcept = default; + SourceLineInfo& operator = ( SourceLineInfo&& ) noexcept = default; - bool empty() const noexcept; + bool empty() const noexcept { return file[0] == '\0'; } bool operator == ( SourceLineInfo const& other ) const noexcept; bool operator < ( SourceLineInfo const& other ) const noexcept; @@ -453,9 +553,10 @@ namespace Catch { } // end namespace Catch #define CATCH_REGISTER_TAG_ALIAS( alias, spec ) \ + CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ namespace{ Catch::RegistrarForTagAliases INTERNAL_CATCH_UNIQUE_NAME( AutoRegisterTagAlias )( alias, spec, CATCH_INTERNAL_LINEINFO ); } \ - CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS + CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION // end catch_tag_alias_autoregistrar.h // start catch_test_registry.h @@ -463,7 +564,6 @@ namespace Catch { // start catch_interfaces_testcase.h #include <vector> -#include <memory> namespace Catch { @@ -474,8 +574,6 @@ namespace Catch { virtual ~ITestInvoker(); }; - using ITestCasePtr = std::shared_ptr<ITestInvoker>; - class TestCase; struct IConfig; @@ -485,6 +583,7 @@ namespace Catch { virtual std::vector<TestCase> const& getAllTestsSorted( IConfig const& config ) const = 0; }; + bool isThrowSafe( TestCase const& testCase, IConfig const& config ); bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config ); std::vector<TestCase> filterTests( std::vector<TestCase> const& testCases, TestSpec const& testSpec, IConfig const& config ); std::vector<TestCase> const& getAllTestCasesSorted( IConfig const& config ); @@ -497,55 +596,30 @@ namespace Catch { #include <cstddef> #include <string> #include <iosfwd> +#include <cassert> namespace Catch { - class StringData; - /// A non-owning string class (similar to the forthcoming std::string_view) /// Note that, because a StringRef may be a substring of another string, - /// it may not be null terminated. c_str() must return a null terminated - /// string, however, and so the StringRef will internally take ownership - /// (taking a copy), if necessary. In theory this ownership is not externally - /// visible - but it does mean (substring) StringRefs should not be shared between - /// threads. + /// it may not be null terminated. class StringRef { public: using size_type = std::size_t; + using const_iterator = const char*; private: - friend struct StringRefTestAccess; - - char const* m_start; - size_type m_size; - - char* m_data = nullptr; - - void takeOwnership(); - static constexpr char const* const s_empty = ""; - public: // construction/ assignment - StringRef() noexcept - : StringRef( s_empty, 0 ) - {} + char const* m_start = s_empty; + size_type m_size = 0; - StringRef( StringRef const& other ) noexcept - : m_start( other.m_start ), - m_size( other.m_size ) - {} - - StringRef( StringRef&& other ) noexcept - : m_start( other.m_start ), - m_size( other.m_size ), - m_data( other.m_data ) - { - other.m_data = nullptr; - } + public: // construction + constexpr StringRef() noexcept = default; StringRef( char const* rawChars ) noexcept; - StringRef( char const* rawChars, size_type size ) noexcept + constexpr StringRef( char const* rawChars, size_type size ) noexcept : m_start( rawChars ), m_size( size ) {} @@ -555,99 +629,64 @@ namespace Catch { m_size( stdString.size() ) {} - ~StringRef() noexcept { - delete[] m_data; + explicit operator std::string() const { + return std::string(m_start, m_size); } - auto operator = ( StringRef const &other ) noexcept -> StringRef& { - delete[] m_data; - m_data = nullptr; - m_start = other.m_start; - m_size = other.m_size; - return *this; - } - - operator std::string() const; - - void swap( StringRef& other ) noexcept; - public: // operators auto operator == ( StringRef const& other ) const noexcept -> bool; - auto operator != ( StringRef const& other ) const noexcept -> bool; + auto operator != (StringRef const& other) const noexcept -> bool { + return !(*this == other); + } - auto operator[] ( size_type index ) const noexcept -> char; + auto operator[] ( size_type index ) const noexcept -> char { + assert(index < m_size); + return m_start[index]; + } public: // named queries - auto empty() const noexcept -> bool { + constexpr auto empty() const noexcept -> bool { return m_size == 0; } - auto size() const noexcept -> size_type { + constexpr auto size() const noexcept -> size_type { return m_size; } - auto numberOfCharacters() const noexcept -> size_type; + // Returns the current start pointer. If the StringRef is not + // null-terminated, throws std::domain_exception auto c_str() const -> char const*; public: // substrings and searches - auto substr( size_type start, size_type size ) const noexcept -> StringRef; + // Returns a substring of [start, start + length). + // If start + length > size(), then the substring is [start, size()). + // If start > size(), then the substring is empty. + auto substr( size_type start, size_type length ) const noexcept -> StringRef; - // Returns the current start pointer. - // Note that the pointer can change when if the StringRef is a substring - auto currentData() const noexcept -> char const*; + // Returns the current start pointer. May not be null-terminated. + auto data() const noexcept -> char const*; - private: // ownership queries - may not be consistent between calls - auto isOwned() const noexcept -> bool; - auto isSubstring() const noexcept -> bool; - }; + constexpr auto isNullTerminated() const noexcept -> bool { + return m_start[m_size] == '\0'; + } - auto operator + ( StringRef const& lhs, StringRef const& rhs ) -> std::string; - auto operator + ( StringRef const& lhs, char const* rhs ) -> std::string; - auto operator + ( char const* lhs, StringRef const& rhs ) -> std::string; + public: // iterators + constexpr const_iterator begin() const { return m_start; } + constexpr const_iterator end() const { return m_start + m_size; } + }; auto operator += ( std::string& lhs, StringRef const& sr ) -> std::string&; auto operator << ( std::ostream& os, StringRef const& sr ) -> std::ostream&; - inline auto operator "" _sr( char const* rawChars, std::size_t size ) noexcept -> StringRef { + constexpr auto operator "" _sr( char const* rawChars, std::size_t size ) noexcept -> StringRef { return StringRef( rawChars, size ); } - } // namespace Catch -inline auto operator "" _catch_sr( char const* rawChars, std::size_t size ) noexcept -> Catch::StringRef { +constexpr auto operator "" _catch_sr( char const* rawChars, std::size_t size ) noexcept -> Catch::StringRef { return Catch::StringRef( rawChars, size ); } // end catch_stringref.h -// start catch_type_traits.hpp - - -namespace Catch{ - -#ifdef CATCH_CPP17_OR_GREATER - template <typename...> - inline constexpr auto is_unique = std::true_type{}; - - template <typename T, typename... Rest> - inline constexpr auto is_unique<T, Rest...> = std::bool_constant< - (!std::is_same_v<T, Rest> && ...) && is_unique<Rest...> - >{}; -#else - -template <typename...> -struct is_unique : std::true_type{}; - -template <typename T0, typename T1, typename... Rest> -struct is_unique<T0, T1, Rest...> : std::integral_constant -<bool, - !std::is_same<T0, T1>::value - && is_unique<T0, Rest...>::value - && is_unique<T1, Rest...>::value ->{}; - -#endif -} - -// end catch_type_traits.hpp // start catch_preprocessor.hpp @@ -699,21 +738,224 @@ struct is_unique<T0, T1, Rest...> : std::integral_constant #define INTERNAL_CATCH_EXPAND2(...) INTERNAL_CATCH_NO## __VA_ARGS__ #define INTERNAL_CATCH_DEF(...) INTERNAL_CATCH_DEF __VA_ARGS__ #define INTERNAL_CATCH_NOINTERNAL_CATCH_DEF +#define INTERNAL_CATCH_STRINGIZE(...) INTERNAL_CATCH_STRINGIZE2(__VA_ARGS__) +#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR +#define INTERNAL_CATCH_STRINGIZE2(...) #__VA_ARGS__ +#define INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS(param) INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_REMOVE_PARENS(param)) +#else +// MSVC is adding extra space and needs another indirection to expand INTERNAL_CATCH_NOINTERNAL_CATCH_DEF +#define INTERNAL_CATCH_STRINGIZE2(...) INTERNAL_CATCH_STRINGIZE3(__VA_ARGS__) +#define INTERNAL_CATCH_STRINGIZE3(...) #__VA_ARGS__ +#define INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS(param) (INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_REMOVE_PARENS(param)) + 1) +#endif + +#define INTERNAL_CATCH_MAKE_NAMESPACE2(...) ns_##__VA_ARGS__ +#define INTERNAL_CATCH_MAKE_NAMESPACE(name) INTERNAL_CATCH_MAKE_NAMESPACE2(name) #define INTERNAL_CATCH_REMOVE_PARENS(...) INTERNAL_CATCH_EXPAND1(INTERNAL_CATCH_DEF __VA_ARGS__) -#define INTERNAL_CATCH_TEMPLATE_UNIQUE_NAME2(Name, ...) INTERNAL_CATCH_TEMPLATE_UNIQUE_NAME3(Name, __VA_ARGS__) #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR -#define INTERNAL_CATCH_TEMPLATE_UNIQUE_NAME3(Name,...) Name " - " #__VA_ARGS__ -#define INTERNAL_CATCH_TEMPLATE_UNIQUE_NAME(Name,...) INTERNAL_CATCH_TEMPLATE_UNIQUE_NAME2(Name, INTERNAL_CATCH_REMOVE_PARENS(__VA_ARGS__)) +#define INTERNAL_CATCH_MAKE_TYPE_LIST2(...) decltype(get_wrapper<INTERNAL_CATCH_REMOVE_PARENS_GEN(__VA_ARGS__)>()) +#define INTERNAL_CATCH_MAKE_TYPE_LIST(...) INTERNAL_CATCH_MAKE_TYPE_LIST2(INTERNAL_CATCH_REMOVE_PARENS(__VA_ARGS__)) #else -// MSVC is adding extra space and needs more calls to properly remove () -#define INTERNAL_CATCH_TEMPLATE_UNIQUE_NAME3(Name,...) Name " -" #__VA_ARGS__ -#define INTERNAL_CATCH_TEMPLATE_UNIQUE_NAME1(Name, ...) INTERNAL_CATCH_TEMPLATE_UNIQUE_NAME2(Name, __VA_ARGS__) -#define INTERNAL_CATCH_TEMPLATE_UNIQUE_NAME(Name, ...) INTERNAL_CATCH_TEMPLATE_UNIQUE_NAME1(Name, INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_REMOVE_PARENS(__VA_ARGS__))) +#define INTERNAL_CATCH_MAKE_TYPE_LIST2(...) INTERNAL_CATCH_EXPAND_VARGS(decltype(get_wrapper<INTERNAL_CATCH_REMOVE_PARENS_GEN(__VA_ARGS__)>())) +#define INTERNAL_CATCH_MAKE_TYPE_LIST(...) INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_MAKE_TYPE_LIST2(INTERNAL_CATCH_REMOVE_PARENS(__VA_ARGS__))) +#endif + +#define INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES(...)\ + CATCH_REC_LIST(INTERNAL_CATCH_MAKE_TYPE_LIST,__VA_ARGS__) + +#define INTERNAL_CATCH_REMOVE_PARENS_1_ARG(_0) INTERNAL_CATCH_REMOVE_PARENS(_0) +#define INTERNAL_CATCH_REMOVE_PARENS_2_ARG(_0, _1) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_1_ARG(_1) +#define INTERNAL_CATCH_REMOVE_PARENS_3_ARG(_0, _1, _2) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_2_ARG(_1, _2) +#define INTERNAL_CATCH_REMOVE_PARENS_4_ARG(_0, _1, _2, _3) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_3_ARG(_1, _2, _3) +#define INTERNAL_CATCH_REMOVE_PARENS_5_ARG(_0, _1, _2, _3, _4) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_4_ARG(_1, _2, _3, _4) +#define INTERNAL_CATCH_REMOVE_PARENS_6_ARG(_0, _1, _2, _3, _4, _5) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_5_ARG(_1, _2, _3, _4, _5) +#define INTERNAL_CATCH_REMOVE_PARENS_7_ARG(_0, _1, _2, _3, _4, _5, _6) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_6_ARG(_1, _2, _3, _4, _5, _6) +#define INTERNAL_CATCH_REMOVE_PARENS_8_ARG(_0, _1, _2, _3, _4, _5, _6, _7) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_7_ARG(_1, _2, _3, _4, _5, _6, _7) +#define INTERNAL_CATCH_REMOVE_PARENS_9_ARG(_0, _1, _2, _3, _4, _5, _6, _7, _8) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_8_ARG(_1, _2, _3, _4, _5, _6, _7, _8) +#define INTERNAL_CATCH_REMOVE_PARENS_10_ARG(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_9_ARG(_1, _2, _3, _4, _5, _6, _7, _8, _9) +#define INTERNAL_CATCH_REMOVE_PARENS_11_ARG(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_10_ARG(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10) + +#define INTERNAL_CATCH_VA_NARGS_IMPL(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, N, ...) N + +#define INTERNAL_CATCH_TYPE_GEN\ + template<typename...> struct TypeList {};\ + template<typename...Ts>\ + constexpr auto get_wrapper() noexcept -> TypeList<Ts...> { return {}; }\ + template<template<typename...> class...> struct TemplateTypeList{};\ + template<template<typename...> class...Cs>\ + constexpr auto get_wrapper() noexcept -> TemplateTypeList<Cs...> { return {}; }\ + template<typename...>\ + struct append;\ + template<typename...>\ + struct rewrap;\ + template<template<typename...> class, typename...>\ + struct create;\ + template<template<typename...> class, typename>\ + struct convert;\ + \ + template<typename T> \ + struct append<T> { using type = T; };\ + template< template<typename...> class L1, typename...E1, template<typename...> class L2, typename...E2, typename...Rest>\ + struct append<L1<E1...>, L2<E2...>, Rest...> { using type = typename append<L1<E1...,E2...>, Rest...>::type; };\ + template< template<typename...> class L1, typename...E1, typename...Rest>\ + struct append<L1<E1...>, TypeList<mpl_::na>, Rest...> { using type = L1<E1...>; };\ + \ + template< template<typename...> class Container, template<typename...> class List, typename...elems>\ + struct rewrap<TemplateTypeList<Container>, List<elems...>> { using type = TypeList<Container<elems...>>; };\ + template< template<typename...> class Container, template<typename...> class List, class...Elems, typename...Elements>\ + struct rewrap<TemplateTypeList<Container>, List<Elems...>, Elements...> { using type = typename append<TypeList<Container<Elems...>>, typename rewrap<TemplateTypeList<Container>, Elements...>::type>::type; };\ + \ + template<template <typename...> class Final, template< typename...> class...Containers, typename...Types>\ + struct create<Final, TemplateTypeList<Containers...>, TypeList<Types...>> { using type = typename append<Final<>, typename rewrap<TemplateTypeList<Containers>, Types...>::type...>::type; };\ + template<template <typename...> class Final, template <typename...> class List, typename...Ts>\ + struct convert<Final, List<Ts...>> { using type = typename append<Final<>,TypeList<Ts>...>::type; }; + +#define INTERNAL_CATCH_NTTP_1(signature, ...)\ + template<INTERNAL_CATCH_REMOVE_PARENS(signature)> struct Nttp{};\ + template<INTERNAL_CATCH_REMOVE_PARENS(signature)>\ + constexpr auto get_wrapper() noexcept -> Nttp<__VA_ARGS__> { return {}; } \ + template<template<INTERNAL_CATCH_REMOVE_PARENS(signature)> class...> struct NttpTemplateTypeList{};\ + template<template<INTERNAL_CATCH_REMOVE_PARENS(signature)> class...Cs>\ + constexpr auto get_wrapper() noexcept -> NttpTemplateTypeList<Cs...> { return {}; } \ + \ + template< template<INTERNAL_CATCH_REMOVE_PARENS(signature)> class Container, template<INTERNAL_CATCH_REMOVE_PARENS(signature)> class List, INTERNAL_CATCH_REMOVE_PARENS(signature)>\ + struct rewrap<NttpTemplateTypeList<Container>, List<__VA_ARGS__>> { using type = TypeList<Container<__VA_ARGS__>>; };\ + template< template<INTERNAL_CATCH_REMOVE_PARENS(signature)> class Container, template<INTERNAL_CATCH_REMOVE_PARENS(signature)> class List, INTERNAL_CATCH_REMOVE_PARENS(signature), typename...Elements>\ + struct rewrap<NttpTemplateTypeList<Container>, List<__VA_ARGS__>, Elements...> { using type = typename append<TypeList<Container<__VA_ARGS__>>, typename rewrap<NttpTemplateTypeList<Container>, Elements...>::type>::type; };\ + template<template <typename...> class Final, template<INTERNAL_CATCH_REMOVE_PARENS(signature)> class...Containers, typename...Types>\ + struct create<Final, NttpTemplateTypeList<Containers...>, TypeList<Types...>> { using type = typename append<Final<>, typename rewrap<NttpTemplateTypeList<Containers>, Types...>::type...>::type; }; + +#define INTERNAL_CATCH_DECLARE_SIG_TEST0(TestName) +#define INTERNAL_CATCH_DECLARE_SIG_TEST1(TestName, signature)\ + template<INTERNAL_CATCH_REMOVE_PARENS(signature)>\ + static void TestName() +#define INTERNAL_CATCH_DECLARE_SIG_TEST_X(TestName, signature, ...)\ + template<INTERNAL_CATCH_REMOVE_PARENS(signature)>\ + static void TestName() + +#define INTERNAL_CATCH_DEFINE_SIG_TEST0(TestName) +#define INTERNAL_CATCH_DEFINE_SIG_TEST1(TestName, signature)\ + template<INTERNAL_CATCH_REMOVE_PARENS(signature)>\ + static void TestName() +#define INTERNAL_CATCH_DEFINE_SIG_TEST_X(TestName, signature,...)\ + template<INTERNAL_CATCH_REMOVE_PARENS(signature)>\ + static void TestName() + +#define INTERNAL_CATCH_NTTP_REGISTER0(TestFunc, signature)\ + template<typename Type>\ + void reg_test(TypeList<Type>, Catch::NameAndTags nameAndTags)\ + {\ + Catch::AutoReg( Catch::makeTestInvoker(&TestFunc<Type>), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), nameAndTags);\ + } + +#define INTERNAL_CATCH_NTTP_REGISTER(TestFunc, signature, ...)\ + template<INTERNAL_CATCH_REMOVE_PARENS(signature)>\ + void reg_test(Nttp<__VA_ARGS__>, Catch::NameAndTags nameAndTags)\ + {\ + Catch::AutoReg( Catch::makeTestInvoker(&TestFunc<__VA_ARGS__>), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), nameAndTags);\ + } + +#define INTERNAL_CATCH_NTTP_REGISTER_METHOD0(TestName, signature, ...)\ + template<typename Type>\ + void reg_test(TypeList<Type>, Catch::StringRef className, Catch::NameAndTags nameAndTags)\ + {\ + Catch::AutoReg( Catch::makeTestInvoker(&TestName<Type>::test), CATCH_INTERNAL_LINEINFO, className, nameAndTags);\ + } + +#define INTERNAL_CATCH_NTTP_REGISTER_METHOD(TestName, signature, ...)\ + template<INTERNAL_CATCH_REMOVE_PARENS(signature)>\ + void reg_test(Nttp<__VA_ARGS__>, Catch::StringRef className, Catch::NameAndTags nameAndTags)\ + {\ + Catch::AutoReg( Catch::makeTestInvoker(&TestName<__VA_ARGS__>::test), CATCH_INTERNAL_LINEINFO, className, nameAndTags);\ + } + +#define INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD0(TestName, ClassName) +#define INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD1(TestName, ClassName, signature)\ + template<typename TestType> \ + struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName)<TestType> { \ + void test();\ + } + +#define INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X(TestName, ClassName, signature, ...)\ + template<INTERNAL_CATCH_REMOVE_PARENS(signature)> \ + struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName)<__VA_ARGS__> { \ + void test();\ + } + +#define INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD0(TestName) +#define INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD1(TestName, signature)\ + template<typename TestType> \ + void INTERNAL_CATCH_MAKE_NAMESPACE(TestName)::TestName<TestType>::test() +#define INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X(TestName, signature, ...)\ + template<INTERNAL_CATCH_REMOVE_PARENS(signature)> \ + void INTERNAL_CATCH_MAKE_NAMESPACE(TestName)::TestName<__VA_ARGS__>::test() + +#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR +#define INTERNAL_CATCH_NTTP_0 +#define INTERNAL_CATCH_NTTP_GEN(...) INTERNAL_CATCH_VA_NARGS_IMPL(__VA_ARGS__, INTERNAL_CATCH_NTTP_1(__VA_ARGS__), INTERNAL_CATCH_NTTP_1(__VA_ARGS__), INTERNAL_CATCH_NTTP_1(__VA_ARGS__), INTERNAL_CATCH_NTTP_1(__VA_ARGS__), INTERNAL_CATCH_NTTP_1(__VA_ARGS__), INTERNAL_CATCH_NTTP_1( __VA_ARGS__), INTERNAL_CATCH_NTTP_1( __VA_ARGS__), INTERNAL_CATCH_NTTP_1( __VA_ARGS__), INTERNAL_CATCH_NTTP_1( __VA_ARGS__),INTERNAL_CATCH_NTTP_1( __VA_ARGS__), INTERNAL_CATCH_NTTP_0) +#define INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD(TestName, ...) INTERNAL_CATCH_VA_NARGS_IMPL( "dummy", __VA_ARGS__, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD1, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD0)(TestName, __VA_ARGS__) +#define INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD(TestName, ClassName, ...) INTERNAL_CATCH_VA_NARGS_IMPL( "dummy", __VA_ARGS__, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD1, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD0)(TestName, ClassName, __VA_ARGS__) +#define INTERNAL_CATCH_NTTP_REG_METHOD_GEN(TestName, ...) INTERNAL_CATCH_VA_NARGS_IMPL( "dummy", __VA_ARGS__, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD0, INTERNAL_CATCH_NTTP_REGISTER_METHOD0)(TestName, __VA_ARGS__) +#define INTERNAL_CATCH_NTTP_REG_GEN(TestFunc, ...) INTERNAL_CATCH_VA_NARGS_IMPL( "dummy", __VA_ARGS__, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER0, INTERNAL_CATCH_NTTP_REGISTER0)(TestFunc, __VA_ARGS__) +#define INTERNAL_CATCH_DEFINE_SIG_TEST(TestName, ...) INTERNAL_CATCH_VA_NARGS_IMPL( "dummy", __VA_ARGS__, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X,INTERNAL_CATCH_DEFINE_SIG_TEST_X,INTERNAL_CATCH_DEFINE_SIG_TEST1, INTERNAL_CATCH_DEFINE_SIG_TEST0)(TestName, __VA_ARGS__) +#define INTERNAL_CATCH_DECLARE_SIG_TEST(TestName, ...) INTERNAL_CATCH_VA_NARGS_IMPL( "dummy", __VA_ARGS__, INTERNAL_CATCH_DECLARE_SIG_TEST_X,INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X,INTERNAL_CATCH_DECLARE_SIG_TEST_X,INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DECLARE_SIG_TEST1, INTERNAL_CATCH_DECLARE_SIG_TEST0)(TestName, __VA_ARGS__) +#define INTERNAL_CATCH_REMOVE_PARENS_GEN(...) INTERNAL_CATCH_VA_NARGS_IMPL(__VA_ARGS__, INTERNAL_CATCH_REMOVE_PARENS_11_ARG,INTERNAL_CATCH_REMOVE_PARENS_10_ARG,INTERNAL_CATCH_REMOVE_PARENS_9_ARG,INTERNAL_CATCH_REMOVE_PARENS_8_ARG,INTERNAL_CATCH_REMOVE_PARENS_7_ARG,INTERNAL_CATCH_REMOVE_PARENS_6_ARG,INTERNAL_CATCH_REMOVE_PARENS_5_ARG,INTERNAL_CATCH_REMOVE_PARENS_4_ARG,INTERNAL_CATCH_REMOVE_PARENS_3_ARG,INTERNAL_CATCH_REMOVE_PARENS_2_ARG,INTERNAL_CATCH_REMOVE_PARENS_1_ARG)(__VA_ARGS__) +#else +#define INTERNAL_CATCH_NTTP_0(signature) +#define INTERNAL_CATCH_NTTP_GEN(...) INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_VA_NARGS_IMPL(__VA_ARGS__, INTERNAL_CATCH_NTTP_1, INTERNAL_CATCH_NTTP_1, INTERNAL_CATCH_NTTP_1, INTERNAL_CATCH_NTTP_1, INTERNAL_CATCH_NTTP_1, INTERNAL_CATCH_NTTP_1, INTERNAL_CATCH_NTTP_1, INTERNAL_CATCH_NTTP_1, INTERNAL_CATCH_NTTP_1,INTERNAL_CATCH_NTTP_1, INTERNAL_CATCH_NTTP_0)( __VA_ARGS__)) +#define INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD(TestName, ...) INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_VA_NARGS_IMPL( "dummy", __VA_ARGS__, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD1, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD0)(TestName, __VA_ARGS__)) +#define INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD(TestName, ClassName, ...) INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_VA_NARGS_IMPL( "dummy", __VA_ARGS__, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD1, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD0)(TestName, ClassName, __VA_ARGS__)) +#define INTERNAL_CATCH_NTTP_REG_METHOD_GEN(TestName, ...) INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_VA_NARGS_IMPL( "dummy", __VA_ARGS__, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD0, INTERNAL_CATCH_NTTP_REGISTER_METHOD0)(TestName, __VA_ARGS__)) +#define INTERNAL_CATCH_NTTP_REG_GEN(TestFunc, ...) INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_VA_NARGS_IMPL( "dummy", __VA_ARGS__, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER0, INTERNAL_CATCH_NTTP_REGISTER0)(TestFunc, __VA_ARGS__)) +#define INTERNAL_CATCH_DEFINE_SIG_TEST(TestName, ...) INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_VA_NARGS_IMPL( "dummy", __VA_ARGS__, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X,INTERNAL_CATCH_DEFINE_SIG_TEST_X,INTERNAL_CATCH_DEFINE_SIG_TEST1, INTERNAL_CATCH_DEFINE_SIG_TEST0)(TestName, __VA_ARGS__)) +#define INTERNAL_CATCH_DECLARE_SIG_TEST(TestName, ...) INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_VA_NARGS_IMPL( "dummy", __VA_ARGS__, INTERNAL_CATCH_DECLARE_SIG_TEST_X,INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X,INTERNAL_CATCH_DECLARE_SIG_TEST_X,INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DECLARE_SIG_TEST1, INTERNAL_CATCH_DECLARE_SIG_TEST0)(TestName, __VA_ARGS__)) +#define INTERNAL_CATCH_REMOVE_PARENS_GEN(...) INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_VA_NARGS_IMPL(__VA_ARGS__, INTERNAL_CATCH_REMOVE_PARENS_11_ARG,INTERNAL_CATCH_REMOVE_PARENS_10_ARG,INTERNAL_CATCH_REMOVE_PARENS_9_ARG,INTERNAL_CATCH_REMOVE_PARENS_8_ARG,INTERNAL_CATCH_REMOVE_PARENS_7_ARG,INTERNAL_CATCH_REMOVE_PARENS_6_ARG,INTERNAL_CATCH_REMOVE_PARENS_5_ARG,INTERNAL_CATCH_REMOVE_PARENS_4_ARG,INTERNAL_CATCH_REMOVE_PARENS_3_ARG,INTERNAL_CATCH_REMOVE_PARENS_2_ARG,INTERNAL_CATCH_REMOVE_PARENS_1_ARG)(__VA_ARGS__)) #endif // end catch_preprocessor.hpp +// start catch_meta.hpp + + +#include <type_traits> + +namespace Catch { + template<typename T> + struct always_false : std::false_type {}; + + template <typename> struct true_given : std::true_type {}; + struct is_callable_tester { + template <typename Fun, typename... Args> + true_given<decltype(std::declval<Fun>()(std::declval<Args>()...))> static test(int); + template <typename...> + std::false_type static test(...); + }; + + template <typename T> + struct is_callable; + + template <typename Fun, typename... Args> + struct is_callable<Fun(Args...)> : decltype(is_callable_tester::test<Fun, Args...>(0)) {}; + +#if defined(__cpp_lib_is_invocable) && __cpp_lib_is_invocable >= 201703 + // std::result_of is deprecated in C++17 and removed in C++20. Hence, it is + // replaced with std::invoke_result here. + template <typename Func, typename... U> + using FunctionReturnType = std::remove_reference_t<std::remove_cv_t<std::invoke_result_t<Func, U...>>>; +#else + // Keep ::type here because we still support C++11 + template <typename Func, typename... U> + using FunctionReturnType = typename std::remove_reference<typename std::remove_cv<typename std::result_of<Func(U...)>::type>::type>::type; +#endif + +} // namespace Catch + +namespace mpl_{ + struct na; +} + +// end catch_meta.hpp namespace Catch { template<typename C> @@ -758,38 +1000,70 @@ struct AutoReg : NonCopyable { }; \ } \ void TestName::test() - #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION( TestName, ... ) \ - template<typename TestType> \ - static void TestName() - #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION( TestName, ClassName, ... ) \ + #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION_2( TestName, TestFunc, Name, Tags, Signature, ... ) \ + INTERNAL_CATCH_DEFINE_SIG_TEST(TestFunc, INTERNAL_CATCH_REMOVE_PARENS(Signature)) + #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION_2( TestNameClass, TestName, ClassName, Name, Tags, Signature, ... ) \ namespace{ \ - template<typename TestType> \ - struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName <TestType>) { \ - void test(); \ - }; \ + namespace INTERNAL_CATCH_MAKE_NAMESPACE(TestName) { \ + INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD(TestName, ClassName, INTERNAL_CATCH_REMOVE_PARENS(Signature));\ } \ - template<typename TestType> \ - void TestName::test() + } \ + INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD(TestName, INTERNAL_CATCH_REMOVE_PARENS(Signature)) + + #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR + #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(Name, Tags, ...) \ + INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), Name, Tags, typename TestType, __VA_ARGS__ ) + #else + #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(Name, Tags, ...) \ + INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), Name, Tags, typename TestType, __VA_ARGS__ ) ) + #endif + + #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR + #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG_NO_REGISTRATION(Name, Tags, Signature, ...) \ + INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), Name, Tags, Signature, __VA_ARGS__ ) + #else + #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG_NO_REGISTRATION(Name, Tags, Signature, ...) \ + INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), Name, Tags, Signature, __VA_ARGS__ ) ) + #endif + + #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR + #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION( ClassName, Name, Tags,... ) \ + INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_C_L_A_S_S_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ) , ClassName, Name, Tags, typename T, __VA_ARGS__ ) + #else + #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION( ClassName, Name, Tags,... ) \ + INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_C_L_A_S_S_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ) , ClassName, Name, Tags, typename T, __VA_ARGS__ ) ) + #endif + + #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR + #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG_NO_REGISTRATION( ClassName, Name, Tags, Signature, ... ) \ + INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_C_L_A_S_S_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ) , ClassName, Name, Tags, Signature, __VA_ARGS__ ) + #else + #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG_NO_REGISTRATION( ClassName, Name, Tags, Signature, ... ) \ + INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_C_L_A_S_S_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ) , ClassName, Name, Tags, Signature, __VA_ARGS__ ) ) + #endif #endif /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_TESTCASE2( TestName, ... ) \ static void TestName(); \ + CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( Catch::makeTestInvoker( &TestName ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ __VA_ARGS__ } ); } /* NOLINT */ \ - CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS \ + CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \ static void TestName() #define INTERNAL_CATCH_TESTCASE( ... ) \ - INTERNAL_CATCH_TESTCASE2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), __VA_ARGS__ ) + INTERNAL_CATCH_TESTCASE2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_S_T_ ), __VA_ARGS__ ) /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, ... ) \ + CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( Catch::makeTestInvoker( &QualifiedMethod ), CATCH_INTERNAL_LINEINFO, "&" #QualifiedMethod, Catch::NameAndTags{ __VA_ARGS__ } ); } /* NOLINT */ \ - CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS + CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_TEST_CASE_METHOD2( TestName, ClassName, ... )\ + CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ namespace{ \ struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName) { \ @@ -797,88 +1071,273 @@ struct AutoReg : NonCopyable { }; \ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( Catch::makeTestInvoker( &TestName::test ), CATCH_INTERNAL_LINEINFO, #ClassName, Catch::NameAndTags{ __VA_ARGS__ } ); /* NOLINT */ \ } \ - CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS \ + CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \ void TestName::test() #define INTERNAL_CATCH_TEST_CASE_METHOD( ClassName, ... ) \ - INTERNAL_CATCH_TEST_CASE_METHOD2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), ClassName, __VA_ARGS__ ) + INTERNAL_CATCH_TEST_CASE_METHOD2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_S_T_ ), ClassName, __VA_ARGS__ ) /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_REGISTER_TESTCASE( Function, ... ) \ + CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( Catch::makeTestInvoker( Function ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ __VA_ARGS__ } ); /* NOLINT */ \ - CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS + CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION /////////////////////////////////////////////////////////////////////////////// - #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_2(TestName, TestFunc, Name, Tags, ... )\ + #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_2(TestName, TestFunc, Name, Tags, Signature, ... )\ + CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ - template<typename TestType> \ - static void TestFunc();\ + CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS \ + CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \ + INTERNAL_CATCH_DECLARE_SIG_TEST(TestFunc, INTERNAL_CATCH_REMOVE_PARENS(Signature));\ namespace {\ + namespace INTERNAL_CATCH_MAKE_NAMESPACE(TestName){\ + INTERNAL_CATCH_TYPE_GEN\ + INTERNAL_CATCH_NTTP_GEN(INTERNAL_CATCH_REMOVE_PARENS(Signature))\ + INTERNAL_CATCH_NTTP_REG_GEN(TestFunc,INTERNAL_CATCH_REMOVE_PARENS(Signature))\ template<typename...Types> \ struct TestName{\ - template<typename...Ts> \ - TestName(Ts...names){\ - CATCH_INTERNAL_CHECK_UNIQUE_TYPES(CATCH_REC_LIST(INTERNAL_CATCH_REMOVE_PARENS, __VA_ARGS__)) \ + TestName(){\ + int index = 0; \ + constexpr char const* tmpl_types[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, __VA_ARGS__)};\ using expander = int[];\ - (void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestFunc<Types> ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ names, Tags } ), 0)... };/* NOLINT */ \ + (void)expander{(reg_test(Types{}, Catch::NameAndTags{ Name " - " + std::string(tmpl_types[index]), Tags } ), index++)... };/* NOLINT */ \ }\ };\ - INTERNAL_CATCH_TEMPLATE_REGISTRY_INITIATE(TestName, Name, __VA_ARGS__) \ + static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){\ + TestName<INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES(__VA_ARGS__)>();\ + return 0;\ + }();\ }\ - CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS \ - template<typename TestType> \ - static void TestFunc() + }\ + CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \ + INTERNAL_CATCH_DEFINE_SIG_TEST(TestFunc,INTERNAL_CATCH_REMOVE_PARENS(Signature)) -#if defined(CATCH_CPP17_OR_GREATER) -#define CATCH_INTERNAL_CHECK_UNIQUE_TYPES(...) static_assert(Catch::is_unique<__VA_ARGS__>,"Duplicate type detected in declaration of template test case"); +#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR + #define INTERNAL_CATCH_TEMPLATE_TEST_CASE(Name, Tags, ...) \ + INTERNAL_CATCH_TEMPLATE_TEST_CASE_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), Name, Tags, typename TestType, __VA_ARGS__ ) #else -#define CATCH_INTERNAL_CHECK_UNIQUE_TYPES(...) static_assert(Catch::is_unique<__VA_ARGS__>::value,"Duplicate type detected in declaration of template test case"); + #define INTERNAL_CATCH_TEMPLATE_TEST_CASE(Name, Tags, ...) \ + INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), Name, Tags, typename TestType, __VA_ARGS__ ) ) #endif #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR - #define INTERNAL_CATCH_TEMPLATE_TEST_CASE(Name, Tags, ...) \ - INTERNAL_CATCH_TEMPLATE_TEST_CASE_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, __VA_ARGS__ ) + #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG(Name, Tags, Signature, ...) \ + INTERNAL_CATCH_TEMPLATE_TEST_CASE_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), Name, Tags, Signature, __VA_ARGS__ ) #else - #define INTERNAL_CATCH_TEMPLATE_TEST_CASE(Name, Tags, ...) \ - INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, __VA_ARGS__ ) ) + #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG(Name, Tags, Signature, ...) \ + INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), Name, Tags, Signature, __VA_ARGS__ ) ) #endif - #define INTERNAL_CATCH_TEMPLATE_REGISTRY_INITIATE(TestName, Name, ...)\ - static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){\ - TestName<CATCH_REC_LIST(INTERNAL_CATCH_REMOVE_PARENS, __VA_ARGS__)>(CATCH_REC_LIST_UD(INTERNAL_CATCH_TEMPLATE_UNIQUE_NAME,Name, __VA_ARGS__));\ - return 0;\ - }(); + #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE2(TestName, TestFuncName, Name, Tags, Signature, TmplTypes, TypesList) \ + CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ + CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ + CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS \ + CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \ + template<typename TestType> static void TestFuncName(); \ + namespace {\ + namespace INTERNAL_CATCH_MAKE_NAMESPACE(TestName) { \ + INTERNAL_CATCH_TYPE_GEN \ + INTERNAL_CATCH_NTTP_GEN(INTERNAL_CATCH_REMOVE_PARENS(Signature)) \ + template<typename... Types> \ + struct TestName { \ + void reg_tests() { \ + int index = 0; \ + using expander = int[]; \ + constexpr char const* tmpl_types[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, INTERNAL_CATCH_REMOVE_PARENS(TmplTypes))};\ + constexpr char const* types_list[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, INTERNAL_CATCH_REMOVE_PARENS(TypesList))};\ + constexpr auto num_types = sizeof(types_list) / sizeof(types_list[0]);\ + (void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestFuncName<Types> ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ Name " - " + std::string(tmpl_types[index / num_types]) + "<" + std::string(types_list[index % num_types]) + ">", Tags } ), index++)... };/* NOLINT */\ + } \ + }; \ + static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){ \ + using TestInit = typename create<TestName, decltype(get_wrapper<INTERNAL_CATCH_REMOVE_PARENS(TmplTypes)>()), TypeList<INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES(INTERNAL_CATCH_REMOVE_PARENS(TypesList))>>::type; \ + TestInit t; \ + t.reg_tests(); \ + return 0; \ + }(); \ + } \ + } \ + CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \ + template<typename TestType> \ + static void TestFuncName() + +#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR + #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE(Name, Tags, ...)\ + INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE2(INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), Name, Tags, typename T,__VA_ARGS__) +#else + #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE(Name, Tags, ...)\ + INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), Name, Tags, typename T, __VA_ARGS__ ) ) +#endif + +#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR + #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG(Name, Tags, Signature, ...)\ + INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE2(INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), Name, Tags, Signature, __VA_ARGS__) +#else + #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG(Name, Tags, Signature, ...)\ + INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), Name, Tags, Signature, __VA_ARGS__ ) ) +#endif - #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_2( TestNameClass, TestName, ClassName, Name, Tags, ... ) \ + #define INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_2(TestName, TestFunc, Name, Tags, TmplList)\ + CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ - namespace{ \ - template<typename TestType> \ + CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \ + template<typename TestType> static void TestFunc(); \ + namespace {\ + namespace INTERNAL_CATCH_MAKE_NAMESPACE(TestName){\ + INTERNAL_CATCH_TYPE_GEN\ + template<typename... Types> \ + struct TestName { \ + void reg_tests() { \ + int index = 0; \ + using expander = int[]; \ + (void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestFunc<Types> ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ Name " - " + std::string(INTERNAL_CATCH_STRINGIZE(TmplList)) + " - " + std::to_string(index), Tags } ), index++)... };/* NOLINT */\ + } \ + };\ + static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){ \ + using TestInit = typename convert<TestName, TmplList>::type; \ + TestInit t; \ + t.reg_tests(); \ + return 0; \ + }(); \ + }}\ + CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \ + template<typename TestType> \ + static void TestFunc() + + #define INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE(Name, Tags, TmplList) \ + INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), Name, Tags, TmplList ) + + #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_2( TestNameClass, TestName, ClassName, Name, Tags, Signature, ... ) \ + CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ + CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ + CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS \ + CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \ + namespace {\ + namespace INTERNAL_CATCH_MAKE_NAMESPACE(TestName){ \ + INTERNAL_CATCH_TYPE_GEN\ + INTERNAL_CATCH_NTTP_GEN(INTERNAL_CATCH_REMOVE_PARENS(Signature))\ + INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD(TestName, ClassName, INTERNAL_CATCH_REMOVE_PARENS(Signature));\ + INTERNAL_CATCH_NTTP_REG_METHOD_GEN(TestName, INTERNAL_CATCH_REMOVE_PARENS(Signature))\ + template<typename...Types> \ + struct TestNameClass{\ + TestNameClass(){\ + int index = 0; \ + constexpr char const* tmpl_types[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, __VA_ARGS__)};\ + using expander = int[];\ + (void)expander{(reg_test(Types{}, #ClassName, Catch::NameAndTags{ Name " - " + std::string(tmpl_types[index]), Tags } ), index++)... };/* NOLINT */ \ + }\ + };\ + static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){\ + TestNameClass<INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES(__VA_ARGS__)>();\ + return 0;\ + }();\ + }\ + }\ + CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \ + INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD(TestName, INTERNAL_CATCH_REMOVE_PARENS(Signature)) + +#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR + #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( ClassName, Name, Tags,... ) \ + INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_C_L_A_S_S_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ) , ClassName, Name, Tags, typename T, __VA_ARGS__ ) +#else + #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( ClassName, Name, Tags,... ) \ + INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_C_L_A_S_S_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ) , ClassName, Name, Tags, typename T, __VA_ARGS__ ) ) +#endif + +#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR + #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( ClassName, Name, Tags, Signature, ... ) \ + INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_C_L_A_S_S_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ) , ClassName, Name, Tags, Signature, __VA_ARGS__ ) +#else + #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( ClassName, Name, Tags, Signature, ... ) \ + INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_C_L_A_S_S_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ) , ClassName, Name, Tags, Signature, __VA_ARGS__ ) ) +#endif + + #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_2(TestNameClass, TestName, ClassName, Name, Tags, Signature, TmplTypes, TypesList)\ + CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ + CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ + CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS \ + CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \ + template<typename TestType> \ struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName <TestType>) { \ void test();\ };\ - template<typename...Types> \ + namespace {\ + namespace INTERNAL_CATCH_MAKE_NAMESPACE(TestNameClass) {\ + INTERNAL_CATCH_TYPE_GEN \ + INTERNAL_CATCH_NTTP_GEN(INTERNAL_CATCH_REMOVE_PARENS(Signature))\ + template<typename...Types>\ struct TestNameClass{\ - template<typename...Ts> \ - TestNameClass(Ts...names){\ - CATCH_INTERNAL_CHECK_UNIQUE_TYPES(CATCH_REC_LIST(INTERNAL_CATCH_REMOVE_PARENS, __VA_ARGS__)) \ + void reg_tests(){\ + int index = 0;\ using expander = int[];\ - (void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestName<Types>::test ), CATCH_INTERNAL_LINEINFO, #ClassName, Catch::NameAndTags{ names, Tags } ), 0)... };/* NOLINT */ \ + constexpr char const* tmpl_types[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, INTERNAL_CATCH_REMOVE_PARENS(TmplTypes))};\ + constexpr char const* types_list[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, INTERNAL_CATCH_REMOVE_PARENS(TypesList))};\ + constexpr auto num_types = sizeof(types_list) / sizeof(types_list[0]);\ + (void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestName<Types>::test ), CATCH_INTERNAL_LINEINFO, #ClassName, Catch::NameAndTags{ Name " - " + std::string(tmpl_types[index / num_types]) + "<" + std::string(types_list[index % num_types]) + ">", Tags } ), index++)... };/* NOLINT */ \ }\ };\ - INTERNAL_CATCH_TEMPLATE_REGISTRY_INITIATE(TestNameClass, Name, __VA_ARGS__)\ + static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){\ + using TestInit = typename create<TestNameClass, decltype(get_wrapper<INTERNAL_CATCH_REMOVE_PARENS(TmplTypes)>()), TypeList<INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES(INTERNAL_CATCH_REMOVE_PARENS(TypesList))>>::type;\ + TestInit t;\ + t.reg_tests();\ + return 0;\ + }(); \ }\ - CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS\ + }\ + CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \ template<typename TestType> \ void TestName<TestType>::test() #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR - #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( ClassName, Name, Tags,... ) \ - INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____C_L_A_S_S____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ) , ClassName, Name, Tags, __VA_ARGS__ ) + #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( ClassName, Name, Tags, ... )\ + INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), ClassName, Name, Tags, typename T, __VA_ARGS__ ) #else - #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( ClassName, Name, Tags,... ) \ - INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____C_L_A_S_S____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ) , ClassName, Name, Tags, __VA_ARGS__ ) ) + #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( ClassName, Name, Tags, ... )\ + INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), ClassName, Name, Tags, typename T,__VA_ARGS__ ) ) #endif +#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR + #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( ClassName, Name, Tags, Signature, ... )\ + INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), ClassName, Name, Tags, Signature, __VA_ARGS__ ) +#else + #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( ClassName, Name, Tags, Signature, ... )\ + INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), ClassName, Name, Tags, Signature,__VA_ARGS__ ) ) +#endif + + #define INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_METHOD_2( TestNameClass, TestName, ClassName, Name, Tags, TmplList) \ + CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ + CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ + CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \ + template<typename TestType> \ + struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName <TestType>) { \ + void test();\ + };\ + namespace {\ + namespace INTERNAL_CATCH_MAKE_NAMESPACE(TestName){ \ + INTERNAL_CATCH_TYPE_GEN\ + template<typename...Types>\ + struct TestNameClass{\ + void reg_tests(){\ + int index = 0;\ + using expander = int[];\ + (void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestName<Types>::test ), CATCH_INTERNAL_LINEINFO, #ClassName, Catch::NameAndTags{ Name " - " + std::string(INTERNAL_CATCH_STRINGIZE(TmplList)) + " - " + std::to_string(index), Tags } ), index++)... };/* NOLINT */ \ + }\ + };\ + static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){\ + using TestInit = typename convert<TestNameClass, TmplList>::type;\ + TestInit t;\ + t.reg_tests();\ + return 0;\ + }(); \ + }}\ + CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \ + template<typename TestType> \ + void TestName<TestType>::test() + +#define INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_METHOD(ClassName, Name, Tags, TmplList) \ + INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), ClassName, Name, Tags, TmplList ) + // end catch_test_registry.h // start catch_capture.hpp @@ -978,7 +1437,7 @@ namespace Catch { auto makeStream( StringRef const &filename ) -> IStream const*; - class ReusableStringStream { + class ReusableStringStream : NonCopyable { std::size_t m_index; std::ostream* m_oss; public: @@ -997,6 +1456,42 @@ namespace Catch { } // end catch_stream.h +// start catch_interfaces_enum_values_registry.h + +#include <vector> + +namespace Catch { + + namespace Detail { + struct EnumInfo { + StringRef m_name; + std::vector<std::pair<int, StringRef>> m_values; + + ~EnumInfo(); + + StringRef lookup( int value ) const; + }; + } // namespace Detail + + struct IMutableEnumValuesRegistry { + virtual ~IMutableEnumValuesRegistry(); + + virtual Detail::EnumInfo const& registerEnum( StringRef enumName, StringRef allEnums, std::vector<int> const& values ) = 0; + + template<typename E> + Detail::EnumInfo const& registerEnum( StringRef enumName, StringRef allEnums, std::initializer_list<E> values ) { + static_assert(sizeof(int) >= sizeof(E), "Cannot serialize enum to int"); + std::vector<int> intValues; + intValues.reserve( values.size() ); + for( auto enumValue : values ) + intValues.push_back( static_cast<int>( enumValue ) ); + return registerEnum( enumName, allEnums, intValues ); + } + }; + +} // Catch + +// end catch_interfaces_enum_values_registry.h #ifdef CATCH_CONFIG_CPP17_STRING_VIEW #include <string_view> @@ -1067,9 +1562,9 @@ namespace Catch { template<typename T> class IsStreamInsertable { - template<typename SS, typename TT> + template<typename Stream, typename U> static auto test(int) - -> decltype(std::declval<SS&>() << std::declval<TT>(), std::true_type()); + -> decltype(std::declval<Stream&>() << std::declval<U>(), std::true_type()); template<typename, typename> static auto test(...)->std::false_type; @@ -1231,6 +1726,12 @@ namespace Catch { } }; +#if defined(CATCH_CONFIG_CPP17_BYTE) + template<> + struct StringMaker<std::byte> { + static std::string convert(std::byte value); + }; +#endif // defined(CATCH_CONFIG_CPP17_BYTE) template<> struct StringMaker<int> { static std::string convert(int value); @@ -1282,10 +1783,13 @@ namespace Catch { template<> struct StringMaker<float> { static std::string convert(float value); + static int precision; }; + template<> struct StringMaker<double> { static std::string convert(double value); + static int precision; }; template <typename T> @@ -1321,8 +1825,8 @@ namespace Catch { #endif namespace Detail { - template<typename InputIterator> - std::string rangeToString(InputIterator first, InputIterator last) { + template<typename InputIterator, typename Sentinel = InputIterator> + std::string rangeToString(InputIterator first, Sentinel last) { ReusableStringStream rss; rss << "{ "; if (first != last) { @@ -1370,6 +1874,7 @@ namespace Catch { # define CATCH_CONFIG_ENABLE_TUPLE_STRINGMAKER # define CATCH_CONFIG_ENABLE_VARIANT_STRINGMAKER # define CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER +# define CATCH_CONFIG_ENABLE_OPTIONAL_STRINGMAKER #endif // Separate std::pair specialization @@ -1391,6 +1896,24 @@ namespace Catch { } #endif // CATCH_CONFIG_ENABLE_PAIR_STRINGMAKER +#if defined(CATCH_CONFIG_ENABLE_OPTIONAL_STRINGMAKER) && defined(CATCH_CONFIG_CPP17_OPTIONAL) +#include <optional> +namespace Catch { + template<typename T> + struct StringMaker<std::optional<T> > { + static std::string convert(const std::optional<T>& optional) { + ReusableStringStream rss; + if (optional.has_value()) { + rss << ::Catch::Detail::stringify(*optional); + } else { + rss << "{ }"; + } + return rss.str(); + } + }; +} +#endif // CATCH_CONFIG_ENABLE_OPTIONAL_STRINGMAKER + // Separate std::tuple specialization #if defined(CATCH_CONFIG_ENABLE_TUPLE_STRINGMAKER) #include <tuple> @@ -1461,20 +1984,27 @@ namespace Catch { #endif // CATCH_CONFIG_ENABLE_VARIANT_STRINGMAKER namespace Catch { - struct not_this_one {}; // Tag type for detecting which begin/ end are being selected - - // Import begin/ end from std here so they are considered alongside the fallback (...) overloads in this namespace + // Import begin/ end from std here using std::begin; using std::end; - not_this_one begin( ... ); - not_this_one end( ... ); + namespace detail { + template <typename...> + struct void_type { + using type = void; + }; + + template <typename T, typename = void> + struct is_range_impl : std::false_type { + }; + + template <typename T> + struct is_range_impl<T, typename void_type<decltype(begin(std::declval<T>()))>::type> : std::true_type { + }; + } // namespace detail template <typename T> - struct is_range { - static const bool value = - !std::is_same<decltype(begin(std::declval<T>())), not_this_one>::value && - !std::is_same<decltype(end(std::declval<T>())), not_this_one>::value; + struct is_range : detail::is_range_impl<T> { }; #if defined(_MANAGED) // Managed types are never ranges @@ -1639,6 +2169,18 @@ struct ratio_string<std::milli> { } #endif // CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER +#define INTERNAL_CATCH_REGISTER_ENUM( enumName, ... ) \ +namespace Catch { \ + template<> struct StringMaker<enumName> { \ + static std::string convert( enumName value ) { \ + static const auto& enumInfo = ::Catch::getMutableRegistryHub().getMutableEnumValuesRegistry().registerEnum( #enumName, #__VA_ARGS__, { __VA_ARGS__ } ); \ + return static_cast<std::string>(enumInfo.lookup( static_cast<int>( value ) )); \ + } \ + }; \ +} + +#define CATCH_REGISTER_ENUM( enumName, ... ) INTERNAL_CATCH_REGISTER_ENUM( enumName, __VA_ARGS__ ) + #ifdef _MSC_VER #pragma warning(pop) #endif @@ -1652,6 +2194,7 @@ struct ratio_string<std::milli> { #pragma warning(disable:4018) // more "signed/unsigned mismatch" #pragma warning(disable:4312) // Converting int to T* using reinterpret_cast (issue on x64 platform) #pragma warning(disable:4180) // qualifier applied to function type has no meaning +#pragma warning(disable:4800) // Forcing result to true or false #endif namespace Catch { @@ -1695,6 +2238,62 @@ namespace Catch { m_op( op ), m_rhs( rhs ) {} + + template<typename T> + auto operator && ( T ) const -> BinaryExpr<LhsT, RhsT const&> const { + static_assert(always_false<T>::value, + "chained comparisons are not supported inside assertions, " + "wrap the expression inside parentheses, or decompose it"); + } + + template<typename T> + auto operator || ( T ) const -> BinaryExpr<LhsT, RhsT const&> const { + static_assert(always_false<T>::value, + "chained comparisons are not supported inside assertions, " + "wrap the expression inside parentheses, or decompose it"); + } + + template<typename T> + auto operator == ( T ) const -> BinaryExpr<LhsT, RhsT const&> const { + static_assert(always_false<T>::value, + "chained comparisons are not supported inside assertions, " + "wrap the expression inside parentheses, or decompose it"); + } + + template<typename T> + auto operator != ( T ) const -> BinaryExpr<LhsT, RhsT const&> const { + static_assert(always_false<T>::value, + "chained comparisons are not supported inside assertions, " + "wrap the expression inside parentheses, or decompose it"); + } + + template<typename T> + auto operator > ( T ) const -> BinaryExpr<LhsT, RhsT const&> const { + static_assert(always_false<T>::value, + "chained comparisons are not supported inside assertions, " + "wrap the expression inside parentheses, or decompose it"); + } + + template<typename T> + auto operator < ( T ) const -> BinaryExpr<LhsT, RhsT const&> const { + static_assert(always_false<T>::value, + "chained comparisons are not supported inside assertions, " + "wrap the expression inside parentheses, or decompose it"); + } + + template<typename T> + auto operator >= ( T ) const -> BinaryExpr<LhsT, RhsT const&> const { + static_assert(always_false<T>::value, + "chained comparisons are not supported inside assertions, " + "wrap the expression inside parentheses, or decompose it"); + } + + template<typename T> + auto operator <= ( T ) const -> BinaryExpr<LhsT, RhsT const&> const { + static_assert(always_false<T>::value, + "chained comparisons are not supported inside assertions, " + "wrap the expression inside parentheses, or decompose it"); + } }; template<typename LhsT> @@ -1707,7 +2306,7 @@ namespace Catch { public: explicit UnaryExpr( LhsT lhs ) - : ITransientExpression{ false, lhs ? true : false }, + : ITransientExpression{ false, static_cast<bool>(lhs) }, m_lhs( lhs ) {} }; @@ -1773,6 +2372,32 @@ namespace Catch { auto operator <= ( RhsT const& rhs ) -> BinaryExpr<LhsT, RhsT const&> const { return { static_cast<bool>(m_lhs <= rhs), m_lhs, "<=", rhs }; } + template <typename RhsT> + auto operator | (RhsT const& rhs) -> BinaryExpr<LhsT, RhsT const&> const { + return { static_cast<bool>(m_lhs | rhs), m_lhs, "|", rhs }; + } + template <typename RhsT> + auto operator & (RhsT const& rhs) -> BinaryExpr<LhsT, RhsT const&> const { + return { static_cast<bool>(m_lhs & rhs), m_lhs, "&", rhs }; + } + template <typename RhsT> + auto operator ^ (RhsT const& rhs) -> BinaryExpr<LhsT, RhsT const&> const { + return { static_cast<bool>(m_lhs ^ rhs), m_lhs, "^", rhs }; + } + + template<typename RhsT> + auto operator && ( RhsT const& ) -> BinaryExpr<LhsT, RhsT const&> const { + static_assert(always_false<RhsT>::value, + "operator&& is not supported inside assertions, " + "wrap the expression inside parentheses, or decompose it"); + } + + template<typename RhsT> + auto operator || ( RhsT const& ) -> BinaryExpr<LhsT, RhsT const&> const { + static_assert(always_false<RhsT>::value, + "operator|| is not supported inside assertions, " + "wrap the expression inside parentheses, or decompose it"); + } auto makeUnaryExpr() const -> UnaryExpr<LhsT> { return UnaryExpr<LhsT>{ m_lhs }; @@ -1807,6 +2432,7 @@ namespace Catch { // start catch_interfaces_capture.h #include <string> +#include <chrono> namespace Catch { @@ -1815,15 +2441,20 @@ namespace Catch { struct SectionInfo; struct SectionEndInfo; struct MessageInfo; + struct MessageBuilder; struct Counts; - struct BenchmarkInfo; - struct BenchmarkStats; struct AssertionReaction; struct SourceLineInfo; struct ITransientExpression; struct IGeneratorTracker; +#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING) + struct BenchmarkInfo; + template <typename Duration = std::chrono::duration<double, std::nano>> + struct BenchmarkStats; +#endif // CATCH_CONFIG_ENABLE_BENCHMARKING + struct IResultCapture { virtual ~IResultCapture(); @@ -1833,14 +2464,20 @@ namespace Catch { virtual void sectionEnded( SectionEndInfo const& endInfo ) = 0; virtual void sectionEndedEarly( SectionEndInfo const& endInfo ) = 0; - virtual auto acquireGeneratorTracker( SourceLineInfo const& lineInfo ) -> IGeneratorTracker& = 0; + virtual auto acquireGeneratorTracker( StringRef generatorName, SourceLineInfo const& lineInfo ) -> IGeneratorTracker& = 0; +#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING) + virtual void benchmarkPreparing( std::string const& name ) = 0; virtual void benchmarkStarting( BenchmarkInfo const& info ) = 0; - virtual void benchmarkEnded( BenchmarkStats const& stats ) = 0; + virtual void benchmarkEnded( BenchmarkStats<> const& stats ) = 0; + virtual void benchmarkFailed( std::string const& error ) = 0; +#endif // CATCH_CONFIG_ENABLE_BENCHMARKING virtual void pushScopedMessage( MessageInfo const& message ) = 0; virtual void popScopedMessage( MessageInfo const& message ) = 0; + virtual void emplaceUnscopedMessage( MessageBuilder const& builder ) = 0; + virtual void handleFatalErrorCondition( StringRef message ) = 0; virtual void handleExpr @@ -2004,9 +2641,12 @@ namespace Catch { class ScopedMessage { public: explicit ScopedMessage( MessageBuilder const& builder ); + ScopedMessage( ScopedMessage& duplicate ) = delete; + ScopedMessage( ScopedMessage&& old ); ~ScopedMessage(); MessageInfo m_info; + bool m_moved; }; class Capturer { @@ -2062,15 +2702,16 @@ namespace Catch { /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_TEST( macroName, resultDisposition, ... ) \ do { \ + CATCH_INTERNAL_IGNORE_BUT_WARN(__VA_ARGS__); \ Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__), resultDisposition ); \ INTERNAL_CATCH_TRY { \ + CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \ catchAssertionHandler.handleExpr( Catch::Decomposer() <= __VA_ARGS__ ); \ - CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS \ + CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \ } INTERNAL_CATCH_CATCH( catchAssertionHandler ) \ INTERNAL_CATCH_REACT( catchAssertionHandler ) \ - } while( (void)0, false && static_cast<bool>( !!(__VA_ARGS__) ) ) // the expression here is never evaluated at runtime but it forces the compiler to give it a look - // The double negation silences MSVC's C4800 warning, the static_cast forces short-circuit evaluation if the type has overloaded &&. + } while( (void)0, (false) && static_cast<bool>( !!(__VA_ARGS__) ) ) /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_IF( macroName, resultDisposition, ... ) \ @@ -2151,6 +2792,10 @@ namespace Catch { Catch::ScopedMessage INTERNAL_CATCH_UNIQUE_NAME( scopedMessage )( Catch::MessageBuilder( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info ) << log ); /////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_UNSCOPED_INFO( macroName, log ) \ + Catch::getResultCapture().emplaceUnscopedMessage( Catch::MessageBuilder( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info ) << log ) + +/////////////////////////////////////////////////////////////////////////////// // Although this is matcher-based, it can be used with just a string #define INTERNAL_CATCH_THROWS_STR_MATCHES( macroName, resultDisposition, matcher, ... ) \ do { \ @@ -2283,62 +2928,18 @@ namespace Catch { } // end namespace Catch #define INTERNAL_CATCH_SECTION( ... ) \ + CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS \ if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::SectionInfo( CATCH_INTERNAL_LINEINFO, __VA_ARGS__ ) ) \ - CATCH_INTERNAL_UNSUPPRESS_UNUSED_WARNINGS + CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION #define INTERNAL_CATCH_DYNAMIC_SECTION( ... ) \ + CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS \ if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::SectionInfo( CATCH_INTERNAL_LINEINFO, (Catch::ReusableStringStream() << __VA_ARGS__).str() ) ) \ - CATCH_INTERNAL_UNSUPPRESS_UNUSED_WARNINGS + CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION // end catch_section.h -// start catch_benchmark.h - -#include <cstdint> -#include <string> - -namespace Catch { - - class BenchmarkLooper { - - std::string m_name; - std::size_t m_count = 0; - std::size_t m_iterationsToRun = 1; - uint64_t m_resolution; - Timer m_timer; - - static auto getResolution() -> uint64_t; - public: - // Keep most of this inline as it's on the code path that is being timed - BenchmarkLooper( StringRef name ) - : m_name( name ), - m_resolution( getResolution() ) - { - reportStart(); - m_timer.start(); - } - - explicit operator bool() { - if( m_count < m_iterationsToRun ) - return true; - return needsMoreIterations(); - } - - void increment() { - ++m_count; - } - - void reportStart(); - auto needsMoreIterations() -> bool; - }; - -} // end namespace Catch - -#define BENCHMARK( name ) \ - for( Catch::BenchmarkLooper looper( name ); looper; looper.increment() ) - -// end catch_benchmark.h // start catch_interfaces_exception.h // start catch_interfaces_registry_hub.h @@ -2355,6 +2956,8 @@ namespace Catch { struct IReporterRegistry; struct IReporterFactory; struct ITagAliasRegistry; + struct IMutableEnumValuesRegistry; + class StartupExceptionRegistry; using IReporterFactoryPtr = std::shared_ptr<IReporterFactory>; @@ -2365,7 +2968,6 @@ namespace Catch { virtual IReporterRegistry const& getReporterRegistry() const = 0; virtual ITestCaseRegistry const& getTestCaseRegistry() const = 0; virtual ITagAliasRegistry const& getTagAliasRegistry() const = 0; - virtual IExceptionTranslatorRegistry const& getExceptionTranslatorRegistry() const = 0; virtual StartupExceptionRegistry const& getStartupExceptionRegistry() const = 0; @@ -2379,6 +2981,7 @@ namespace Catch { virtual void registerTranslator( const IExceptionTranslator* translator ) = 0; virtual void registerTagAlias( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ) = 0; virtual void registerStartupException() noexcept = 0; + virtual IMutableEnumValuesRegistry& getMutableEnumValuesRegistry() = 0; }; IRegistryHub const& getRegistryHub(); @@ -2425,6 +3028,9 @@ namespace Catch { {} std::string translate( ExceptionTranslators::const_iterator it, ExceptionTranslators::const_iterator itEnd ) const override { +#if defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) + return ""; +#else try { if( it == itEnd ) std::rethrow_exception(std::current_exception()); @@ -2434,6 +3040,7 @@ namespace Catch { catch( T& ex ) { return m_translateFunction( ex ); } +#endif } protected: @@ -2452,9 +3059,10 @@ namespace Catch { /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_TRANSLATE_EXCEPTION2( translatorName, signature ) \ static std::string translatorName( signature ); \ + CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ namespace{ Catch::ExceptionTranslatorRegistrar INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionRegistrar )( &translatorName ); } \ - CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS \ + CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \ static std::string translatorName( signature ) #define INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION2( INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator ), signature ) @@ -2485,7 +3093,7 @@ namespace Detail { Approx operator-() const; template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type> - Approx operator()( T const& value ) { + Approx operator()( T const& value ) const { Approx approx( static_cast<double>(value) ); approx.m_epsilon = m_epsilon; approx.m_margin = m_margin; @@ -2585,6 +3193,7 @@ struct StringMaker<Catch::Detail::Approx> { #include <string> #include <iosfwd> +#include <vector> namespace Catch { @@ -2595,7 +3204,13 @@ namespace Catch { bool contains( std::string const& s, std::string const& infix ); void toLowerInPlace( std::string& s ); std::string toLower( std::string const& s ); + //! Returns a new string without whitespace at the start/end std::string trim( std::string const& str ); + //! Returns a substring of the original ref without whitespace. Beware lifetimes! + StringRef trim(StringRef ref); + + // !!! Be aware, returns refs into original string - make sure original string outlives them + std::vector<StringRef> splitStringRef( StringRef str, char delimiter ); bool replaceInPlace( std::string& str, std::string const& replaceThis, std::string const& withThis ); struct pluralise { @@ -2648,6 +3263,15 @@ namespace Matchers { virtual bool match( ObjectT const& arg ) const = 0; }; +#if defined(__OBJC__) + // Hack to fix Catch GH issue #1661. Could use id for generic Object support. + // use of const for Object pointers is very uncommon and under ARC it causes some kind of signature mismatch that breaks compilation + template<> + struct MatcherMethod<NSString*> { + virtual bool match( NSString* arg ) const = 0; + }; +#endif + #ifdef __clang__ # pragma clang diagnostic pop #endif @@ -2685,9 +3309,10 @@ namespace Matchers { return description; } - MatchAllOf<ArgT>& operator && ( MatcherBase<ArgT> const& other ) { - m_matchers.push_back( &other ); - return *this; + MatchAllOf<ArgT> operator && ( MatcherBase<ArgT> const& other ) { + auto copy(*this); + copy.m_matchers.push_back( &other ); + return copy; } std::vector<MatcherBase<ArgT> const*> m_matchers; @@ -2718,9 +3343,10 @@ namespace Matchers { return description; } - MatchAnyOf<ArgT>& operator || ( MatcherBase<ArgT> const& other ) { - m_matchers.push_back( &other ); - return *this; + MatchAnyOf<ArgT> operator || ( MatcherBase<ArgT> const& other ) { + auto copy(*this); + copy.m_matchers.push_back( &other ); + return copy; } std::vector<MatcherBase<ArgT> const*> m_matchers; @@ -2764,10 +3390,34 @@ using Matchers::Impl::MatcherBase; } // namespace Catch // end catch_matchers.h -// start catch_matchers_floating.h +// start catch_matchers_exception.hpp -#include <type_traits> -#include <cmath> +namespace Catch { +namespace Matchers { +namespace Exception { + +class ExceptionMessageMatcher : public MatcherBase<std::exception> { + std::string m_message; +public: + + ExceptionMessageMatcher(std::string const& message): + m_message(message) + {} + + bool match(std::exception const& ex) const override; + + std::string describe() const override; +}; + +} // namespace Exception + +Exception::ExceptionMessageMatcher Message(std::string const& message); + +} // namespace Matchers +} // namespace Catch + +// end catch_matchers_exception.hpp +// start catch_matchers_floating.h namespace Catch { namespace Matchers { @@ -2786,22 +3436,43 @@ namespace Matchers { }; struct WithinUlpsMatcher : MatcherBase<double> { - WithinUlpsMatcher(double target, int ulps, FloatingPointKind baseType); + WithinUlpsMatcher(double target, uint64_t ulps, FloatingPointKind baseType); bool match(double const& matchee) const override; std::string describe() const override; private: double m_target; - int m_ulps; + uint64_t m_ulps; FloatingPointKind m_type; }; + // Given IEEE-754 format for floats and doubles, we can assume + // that float -> double promotion is lossless. Given this, we can + // assume that if we do the standard relative comparison of + // |lhs - rhs| <= epsilon * max(fabs(lhs), fabs(rhs)), then we get + // the same result if we do this for floats, as if we do this for + // doubles that were promoted from floats. + struct WithinRelMatcher : MatcherBase<double> { + WithinRelMatcher(double target, double epsilon); + bool match(double const& matchee) const override; + std::string describe() const override; + private: + double m_target; + double m_epsilon; + }; + } // namespace Floating // The following functions create the actual matcher objects. // This allows the types to be inferred - Floating::WithinUlpsMatcher WithinULP(double target, int maxUlpDiff); - Floating::WithinUlpsMatcher WithinULP(float target, int maxUlpDiff); + Floating::WithinUlpsMatcher WithinULP(double target, uint64_t maxUlpDiff); + Floating::WithinUlpsMatcher WithinULP(float target, uint64_t maxUlpDiff); Floating::WithinAbsMatcher WithinAbs(double target, double margin); + Floating::WithinRelMatcher WithinRel(double target, double eps); + // defaults epsilon to 100*numeric_limits<double>::epsilon() + Floating::WithinRelMatcher WithinRel(double target); + Floating::WithinRelMatcher WithinRel(float target, float eps); + // defaults epsilon to 100*numeric_limits<float>::epsilon() + Floating::WithinRelMatcher WithinRel(float target); } // namespace Matchers } // namespace Catch @@ -2844,7 +3515,7 @@ public: // The following functions create the actual matcher objects. // The user has to explicitly specify type to the function, because - // infering std::function<bool(T const&)> is hard (but possible) and + // inferring std::function<bool(T const&)> is hard (but possible) and // requires a lot of TMP. template<typename T> Generic::PredicateMatcher<T> Predicate(std::function<bool(T const&)> const& predicate, std::string const& description = "") { @@ -2932,34 +3603,12 @@ namespace Catch { namespace Matchers { namespace Vector { - namespace Detail { - template <typename InputIterator, typename T> - size_t count(InputIterator first, InputIterator last, T const& item) { - size_t cnt = 0; - for (; first != last; ++first) { - if (*first == item) { - ++cnt; - } - } - return cnt; - } - template <typename InputIterator, typename T> - bool contains(InputIterator first, InputIterator last, T const& item) { - for (; first != last; ++first) { - if (*first == item) { - return true; - } - } - return false; - } - } - - template<typename T> - struct ContainsElementMatcher : MatcherBase<std::vector<T>> { + template<typename T, typename Alloc> + struct ContainsElementMatcher : MatcherBase<std::vector<T, Alloc>> { ContainsElementMatcher(T const &comparator) : m_comparator( comparator) {} - bool match(std::vector<T> const &v) const override { + bool match(std::vector<T, Alloc> const &v) const override { for (auto const& el : v) { if (el == m_comparator) { return true; @@ -2975,12 +3624,12 @@ namespace Matchers { T const& m_comparator; }; - template<typename T> - struct ContainsMatcher : MatcherBase<std::vector<T>> { + template<typename T, typename AllocComp, typename AllocMatch> + struct ContainsMatcher : MatcherBase<std::vector<T, AllocMatch>> { - ContainsMatcher(std::vector<T> const &comparator) : m_comparator( comparator ) {} + ContainsMatcher(std::vector<T, AllocComp> const &comparator) : m_comparator( comparator ) {} - bool match(std::vector<T> const &v) const override { + bool match(std::vector<T, AllocMatch> const &v) const override { // !TBD: see note in EqualsMatcher if (m_comparator.size() > v.size()) return false; @@ -3002,18 +3651,18 @@ namespace Matchers { return "Contains: " + ::Catch::Detail::stringify( m_comparator ); } - std::vector<T> const& m_comparator; + std::vector<T, AllocComp> const& m_comparator; }; - template<typename T> - struct EqualsMatcher : MatcherBase<std::vector<T>> { + template<typename T, typename AllocComp, typename AllocMatch> + struct EqualsMatcher : MatcherBase<std::vector<T, AllocMatch>> { - EqualsMatcher(std::vector<T> const &comparator) : m_comparator( comparator ) {} + EqualsMatcher(std::vector<T, AllocComp> const &comparator) : m_comparator( comparator ) {} - bool match(std::vector<T> const &v) const override { + bool match(std::vector<T, AllocMatch> const &v) const override { // !TBD: This currently works if all elements can be compared using != // - a more general approach would be via a compare template that defaults - // to using !=. but could be specialised for, e.g. std::vector<T> etc + // to using !=. but could be specialised for, e.g. std::vector<T, Alloc> etc // - then just call that directly if (m_comparator.size() != v.size()) return false; @@ -3025,47 +3674,60 @@ namespace Matchers { std::string describe() const override { return "Equals: " + ::Catch::Detail::stringify( m_comparator ); } - std::vector<T> const& m_comparator; + std::vector<T, AllocComp> const& m_comparator; }; - template<typename T> - struct UnorderedEqualsMatcher : MatcherBase<std::vector<T>> { - UnorderedEqualsMatcher(std::vector<T> const& target) : m_target(target) {} - bool match(std::vector<T> const& vec) const override { - // Note: This is a reimplementation of std::is_permutation, - // because I don't want to include <algorithm> inside the common path - if (m_target.size() != vec.size()) { - return false; - } - auto lfirst = m_target.begin(), llast = m_target.end(); - auto rfirst = vec.begin(), rlast = vec.end(); - // Cut common prefix to optimize checking of permuted parts - while (lfirst != llast && *lfirst == *rfirst) { - ++lfirst; ++rfirst; - } - if (lfirst == llast) { - return true; - } + template<typename T, typename AllocComp, typename AllocMatch> + struct ApproxMatcher : MatcherBase<std::vector<T, AllocMatch>> { - for (auto mid = lfirst; mid != llast; ++mid) { - // Skip already counted items - if (Detail::contains(lfirst, mid, *mid)) { - continue; - } - size_t num_vec = Detail::count(rfirst, rlast, *mid); - if (num_vec == 0 || Detail::count(lfirst, llast, *mid) != num_vec) { - return false; - } - } + ApproxMatcher(std::vector<T, AllocComp> const& comparator) : m_comparator( comparator ) {} + bool match(std::vector<T, AllocMatch> const &v) const override { + if (m_comparator.size() != v.size()) + return false; + for (std::size_t i = 0; i < v.size(); ++i) + if (m_comparator[i] != approx(v[i])) + return false; return true; } + std::string describe() const override { + return "is approx: " + ::Catch::Detail::stringify( m_comparator ); + } + template <typename = typename std::enable_if<std::is_constructible<double, T>::value>::type> + ApproxMatcher& epsilon( T const& newEpsilon ) { + approx.epsilon(newEpsilon); + return *this; + } + template <typename = typename std::enable_if<std::is_constructible<double, T>::value>::type> + ApproxMatcher& margin( T const& newMargin ) { + approx.margin(newMargin); + return *this; + } + template <typename = typename std::enable_if<std::is_constructible<double, T>::value>::type> + ApproxMatcher& scale( T const& newScale ) { + approx.scale(newScale); + return *this; + } + + std::vector<T, AllocComp> const& m_comparator; + mutable Catch::Detail::Approx approx = Catch::Detail::Approx::custom(); + }; + + template<typename T, typename AllocComp, typename AllocMatch> + struct UnorderedEqualsMatcher : MatcherBase<std::vector<T, AllocMatch>> { + UnorderedEqualsMatcher(std::vector<T, AllocComp> const& target) : m_target(target) {} + bool match(std::vector<T, AllocMatch> const& vec) const override { + if (m_target.size() != vec.size()) { + return false; + } + return std::is_permutation(m_target.begin(), m_target.end(), vec.begin()); + } std::string describe() const override { return "UnorderedEquals: " + ::Catch::Detail::stringify(m_target); } private: - std::vector<T> const& m_target; + std::vector<T, AllocComp> const& m_target; }; } // namespace Vector @@ -3073,24 +3735,29 @@ namespace Matchers { // The following functions create the actual matcher objects. // This allows the types to be inferred - template<typename T> - Vector::ContainsMatcher<T> Contains( std::vector<T> const& comparator ) { - return Vector::ContainsMatcher<T>( comparator ); + template<typename T, typename AllocComp = std::allocator<T>, typename AllocMatch = AllocComp> + Vector::ContainsMatcher<T, AllocComp, AllocMatch> Contains( std::vector<T, AllocComp> const& comparator ) { + return Vector::ContainsMatcher<T, AllocComp, AllocMatch>( comparator ); } - template<typename T> - Vector::ContainsElementMatcher<T> VectorContains( T const& comparator ) { - return Vector::ContainsElementMatcher<T>( comparator ); + template<typename T, typename Alloc = std::allocator<T>> + Vector::ContainsElementMatcher<T, Alloc> VectorContains( T const& comparator ) { + return Vector::ContainsElementMatcher<T, Alloc>( comparator ); } - template<typename T> - Vector::EqualsMatcher<T> Equals( std::vector<T> const& comparator ) { - return Vector::EqualsMatcher<T>( comparator ); + template<typename T, typename AllocComp = std::allocator<T>, typename AllocMatch = AllocComp> + Vector::EqualsMatcher<T, AllocComp, AllocMatch> Equals( std::vector<T, AllocComp> const& comparator ) { + return Vector::EqualsMatcher<T, AllocComp, AllocMatch>( comparator ); } - template<typename T> - Vector::UnorderedEqualsMatcher<T> UnorderedEquals(std::vector<T> const& target) { - return Vector::UnorderedEqualsMatcher<T>(target); + template<typename T, typename AllocComp = std::allocator<T>, typename AllocMatch = AllocComp> + Vector::ApproxMatcher<T, AllocComp, AllocMatch> Approx( std::vector<T, AllocComp> const& comparator ) { + return Vector::ApproxMatcher<T, AllocComp, AllocMatch>( comparator ); + } + + template<typename T, typename AllocComp = std::allocator<T>, typename AllocMatch = AllocComp> + Vector::UnorderedEqualsMatcher<T, AllocComp, AllocMatch> UnorderedEquals(std::vector<T, AllocComp> const& target) { + return Vector::UnorderedEqualsMatcher<T, AllocComp, AllocMatch>( target ); } } // namespace Matchers @@ -3175,16 +3842,17 @@ namespace Catch { namespace Catch { namespace Generators { - class GeneratorBase { - protected: - size_t m_size = 0; - + class GeneratorUntypedBase { public: - GeneratorBase( size_t size ) : m_size( size ) {} - virtual ~GeneratorBase(); - auto size() const -> size_t { return m_size; } + GeneratorUntypedBase() = default; + virtual ~GeneratorUntypedBase(); + // Attempts to move the generator to the next element + // + // Returns true iff the move succeeded (and a valid element + // can be retrieved). + virtual bool next() = 0; }; - using GeneratorBasePtr = std::unique_ptr<GeneratorBase>; + using GeneratorBasePtr = std::unique_ptr<GeneratorUntypedBase>; } // namespace Generators @@ -3193,7 +3861,6 @@ namespace Catch { virtual auto hasGenerator() const -> bool = 0; virtual auto getGenerator() const -> Generators::GeneratorBasePtr const& = 0; virtual void setGenerator( Generators::GeneratorBasePtr&& generator ) = 0; - virtual auto getIndex() const -> std::size_t = 0; }; } // namespace Catch @@ -3201,7 +3868,7 @@ namespace Catch { // end catch_interfaces_generatortracker.h // start catch_enforce.h -#include <stdexcept> +#include <exception> namespace Catch { #if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) @@ -3214,18 +3881,30 @@ namespace Catch { [[noreturn]] void throw_exception(std::exception const& e); #endif + + [[noreturn]] + void throw_logic_error(std::string const& msg); + [[noreturn]] + void throw_domain_error(std::string const& msg); + [[noreturn]] + void throw_runtime_error(std::string const& msg); + } // namespace Catch; -#define CATCH_PREPARE_EXCEPTION( type, msg ) \ - type( ( Catch::ReusableStringStream() << msg ).str() ) -#define CATCH_INTERNAL_ERROR( msg ) \ - Catch::throw_exception(CATCH_PREPARE_EXCEPTION( std::logic_error, CATCH_INTERNAL_LINEINFO << ": Internal Catch error: " << msg)) -#define CATCH_ERROR( msg ) \ - Catch::throw_exception(CATCH_PREPARE_EXCEPTION( std::domain_error, msg )) -#define CATCH_RUNTIME_ERROR( msg ) \ - Catch::throw_exception(CATCH_PREPARE_EXCEPTION( std::runtime_error, msg )) -#define CATCH_ENFORCE( condition, msg ) \ - do{ if( !(condition) ) CATCH_ERROR( msg ); } while(false) +#define CATCH_MAKE_MSG(...) \ + (Catch::ReusableStringStream() << __VA_ARGS__).str() + +#define CATCH_INTERNAL_ERROR(...) \ + Catch::throw_logic_error(CATCH_MAKE_MSG( CATCH_INTERNAL_LINEINFO << ": Internal Catch2 error: " << __VA_ARGS__)) + +#define CATCH_ERROR(...) \ + Catch::throw_domain_error(CATCH_MAKE_MSG( __VA_ARGS__ )) + +#define CATCH_RUNTIME_ERROR(...) \ + Catch::throw_runtime_error(CATCH_MAKE_MSG( __VA_ARGS__ )) + +#define CATCH_ENFORCE( condition, ... ) \ + do{ if( !(condition) ) CATCH_ERROR( __VA_ARGS__ ); } while(false) // end catch_enforce.h #include <memory> @@ -3233,8 +3912,21 @@ namespace Catch { #include <cassert> #include <utility> +#include <exception> namespace Catch { + +class GeneratorException : public std::exception { + const char* const m_msg = ""; + +public: + GeneratorException(const char* msg): + m_msg(msg) + {} + + const char* what() const noexcept override final; +}; + namespace Generators { // !TBD move this into its own location? @@ -3246,223 +3938,819 @@ namespace Generators { } template<typename T> - struct IGenerator { - virtual ~IGenerator() {} - virtual auto get( size_t index ) const -> T = 0; + struct IGenerator : GeneratorUntypedBase { + virtual ~IGenerator() = default; + + // Returns the current element of the generator + // + // \Precondition The generator is either freshly constructed, + // or the last call to `next()` returned true + virtual T const& get() const = 0; + using type = T; }; template<typename T> - class SingleValueGenerator : public IGenerator<T> { + class SingleValueGenerator final : public IGenerator<T> { T m_value; public: - SingleValueGenerator( T const& value ) : m_value( value ) {} + SingleValueGenerator(T&& value) : m_value(std::move(value)) {} - auto get( size_t ) const -> T override { + T const& get() const override { return m_value; } + bool next() override { + return false; + } }; template<typename T> - class FixedValuesGenerator : public IGenerator<T> { + class FixedValuesGenerator final : public IGenerator<T> { + static_assert(!std::is_same<T, bool>::value, + "FixedValuesGenerator does not support bools because of std::vector<bool>" + "specialization, use SingleValue Generator instead."); std::vector<T> m_values; - + size_t m_idx = 0; public: FixedValuesGenerator( std::initializer_list<T> values ) : m_values( values ) {} - auto get( size_t index ) const -> T override { - return m_values[index]; + T const& get() const override { + return m_values[m_idx]; + } + bool next() override { + ++m_idx; + return m_idx < m_values.size(); + } + }; + + template <typename T> + class GeneratorWrapper final { + std::unique_ptr<IGenerator<T>> m_generator; + public: + GeneratorWrapper(std::unique_ptr<IGenerator<T>> generator): + m_generator(std::move(generator)) + {} + T const& get() const { + return m_generator->get(); + } + bool next() { + return m_generator->next(); } }; + template <typename T> + GeneratorWrapper<T> value(T&& value) { + return GeneratorWrapper<T>(pf::make_unique<SingleValueGenerator<T>>(std::forward<T>(value))); + } + template <typename T> + GeneratorWrapper<T> values(std::initializer_list<T> values) { + return GeneratorWrapper<T>(pf::make_unique<FixedValuesGenerator<T>>(values)); + } + template<typename T> - class RangeGenerator : public IGenerator<T> { - T const m_first; - T const m_last; + class Generators : public IGenerator<T> { + std::vector<GeneratorWrapper<T>> m_generators; + size_t m_current = 0; + + void populate(GeneratorWrapper<T>&& generator) { + m_generators.emplace_back(std::move(generator)); + } + void populate(T&& val) { + m_generators.emplace_back(value(std::forward<T>(val))); + } + template<typename U> + void populate(U&& val) { + populate(T(std::forward<U>(val))); + } + template<typename U, typename... Gs> + void populate(U&& valueOrGenerator, Gs &&... moreGenerators) { + populate(std::forward<U>(valueOrGenerator)); + populate(std::forward<Gs>(moreGenerators)...); + } public: - RangeGenerator( T const& first, T const& last ) : m_first( first ), m_last( last ) { - assert( m_last > m_first ); + template <typename... Gs> + Generators(Gs &&... moreGenerators) { + m_generators.reserve(sizeof...(Gs)); + populate(std::forward<Gs>(moreGenerators)...); } - auto get( size_t index ) const -> T override { - // ToDo:: introduce a safe cast to catch potential overflows - return static_cast<T>(m_first+index); + T const& get() const override { + return m_generators[m_current].get(); } - }; - template<typename T> - struct NullGenerator : IGenerator<T> { - auto get( size_t ) const -> T override { - CATCH_INTERNAL_ERROR("A Null Generator is always empty"); + bool next() override { + if (m_current >= m_generators.size()) { + return false; + } + const bool current_status = m_generators[m_current].next(); + if (!current_status) { + ++m_current; + } + return m_current < m_generators.size(); } }; + template<typename... Ts> + GeneratorWrapper<std::tuple<Ts...>> table( std::initializer_list<std::tuple<typename std::decay<Ts>::type...>> tuples ) { + return values<std::tuple<Ts...>>( tuples ); + } + + // Tag type to signal that a generator sequence should convert arguments to a specific type + template <typename T> + struct as {}; + + template<typename T, typename... Gs> + auto makeGenerators( GeneratorWrapper<T>&& generator, Gs &&... moreGenerators ) -> Generators<T> { + return Generators<T>(std::move(generator), std::forward<Gs>(moreGenerators)...); + } template<typename T> - class Generator { - std::unique_ptr<IGenerator<T>> m_generator; - size_t m_size; + auto makeGenerators( GeneratorWrapper<T>&& generator ) -> Generators<T> { + return Generators<T>(std::move(generator)); + } + template<typename T, typename... Gs> + auto makeGenerators( T&& val, Gs &&... moreGenerators ) -> Generators<T> { + return makeGenerators( value( std::forward<T>( val ) ), std::forward<Gs>( moreGenerators )... ); + } + template<typename T, typename U, typename... Gs> + auto makeGenerators( as<T>, U&& val, Gs &&... moreGenerators ) -> Generators<T> { + return makeGenerators( value( T( std::forward<U>( val ) ) ), std::forward<Gs>( moreGenerators )... ); + } - public: - Generator( size_t size, std::unique_ptr<IGenerator<T>> generator ) - : m_generator( std::move( generator ) ), - m_size( size ) - {} + auto acquireGeneratorTracker( StringRef generatorName, SourceLineInfo const& lineInfo ) -> IGeneratorTracker&; + + template<typename L> + // Note: The type after -> is weird, because VS2015 cannot parse + // the expression used in the typedef inside, when it is in + // return type. Yeah. + auto generate( StringRef generatorName, SourceLineInfo const& lineInfo, L const& generatorExpression ) -> decltype(std::declval<decltype(generatorExpression())>().get()) { + using UnderlyingType = typename decltype(generatorExpression())::type; - auto size() const -> size_t { return m_size; } - auto operator[]( size_t index ) const -> T { - assert( index < m_size ); - return m_generator->get( index ); + IGeneratorTracker& tracker = acquireGeneratorTracker( generatorName, lineInfo ); + if (!tracker.hasGenerator()) { + tracker.setGenerator(pf::make_unique<Generators<UnderlyingType>>(generatorExpression())); } - }; - std::vector<size_t> randomiseIndices( size_t selectionSize, size_t sourceSize ); + auto const& generator = static_cast<IGenerator<UnderlyingType> const&>( *tracker.getGenerator() ); + return generator.get(); + } - template<typename T> - class GeneratorRandomiser : public IGenerator<T> { - Generator<T> m_baseGenerator; +} // namespace Generators +} // namespace Catch + +#define GENERATE( ... ) \ + Catch::Generators::generate( INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_UNIQUE_NAME(generator)), \ + CATCH_INTERNAL_LINEINFO, \ + [ ]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } ) //NOLINT(google-build-using-namespace) +#define GENERATE_COPY( ... ) \ + Catch::Generators::generate( INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_UNIQUE_NAME(generator)), \ + CATCH_INTERNAL_LINEINFO, \ + [=]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } ) //NOLINT(google-build-using-namespace) +#define GENERATE_REF( ... ) \ + Catch::Generators::generate( INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_UNIQUE_NAME(generator)), \ + CATCH_INTERNAL_LINEINFO, \ + [&]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } ) //NOLINT(google-build-using-namespace) - std::vector<size_t> m_indices; +// end catch_generators.hpp +// start catch_generators_generic.hpp + +namespace Catch { +namespace Generators { + + template <typename T> + class TakeGenerator : public IGenerator<T> { + GeneratorWrapper<T> m_generator; + size_t m_returned = 0; + size_t m_target; public: - GeneratorRandomiser( Generator<T>&& baseGenerator, size_t numberOfItems ) - : m_baseGenerator( std::move( baseGenerator ) ), - m_indices( randomiseIndices( numberOfItems, m_baseGenerator.size() ) ) - {} + TakeGenerator(size_t target, GeneratorWrapper<T>&& generator): + m_generator(std::move(generator)), + m_target(target) + { + assert(target != 0 && "Empty generators are not allowed"); + } + T const& get() const override { + return m_generator.get(); + } + bool next() override { + ++m_returned; + if (m_returned >= m_target) { + return false; + } - auto get( size_t index ) const -> T override { - return m_baseGenerator[m_indices[index]]; + const auto success = m_generator.next(); + // If the underlying generator does not contain enough values + // then we cut short as well + if (!success) { + m_returned = m_target; + } + return success; } }; - template<typename T> - struct RequiresASpecialisationFor; + template <typename T> + GeneratorWrapper<T> take(size_t target, GeneratorWrapper<T>&& generator) { + return GeneratorWrapper<T>(pf::make_unique<TakeGenerator<T>>(target, std::move(generator))); + } - template<typename T> - auto all() -> Generator<T> { return RequiresASpecialisationFor<T>(); } + template <typename T, typename Predicate> + class FilterGenerator : public IGenerator<T> { + GeneratorWrapper<T> m_generator; + Predicate m_predicate; + public: + template <typename P = Predicate> + FilterGenerator(P&& pred, GeneratorWrapper<T>&& generator): + m_generator(std::move(generator)), + m_predicate(std::forward<P>(pred)) + { + if (!m_predicate(m_generator.get())) { + // It might happen that there are no values that pass the + // filter. In that case we throw an exception. + auto has_initial_value = nextImpl(); + if (!has_initial_value) { + Catch::throw_exception(GeneratorException("No valid value found in filtered generator")); + } + } + } - template<> - auto all<int>() -> Generator<int>; + T const& get() const override { + return m_generator.get(); + } - template<typename T> - auto range( T const& first, T const& last ) -> Generator<T> { - return Generator<T>( (last-first), pf::make_unique<RangeGenerator<T>>( first, last ) ); + bool next() override { + return nextImpl(); + } + + private: + bool nextImpl() { + bool success = m_generator.next(); + if (!success) { + return false; + } + while (!m_predicate(m_generator.get()) && (success = m_generator.next()) == true); + return success; + } + }; + + template <typename T, typename Predicate> + GeneratorWrapper<T> filter(Predicate&& pred, GeneratorWrapper<T>&& generator) { + return GeneratorWrapper<T>(std::unique_ptr<IGenerator<T>>(pf::make_unique<FilterGenerator<T, Predicate>>(std::forward<Predicate>(pred), std::move(generator)))); } - template<typename T> - auto random( T const& first, T const& last ) -> Generator<T> { - auto gen = range( first, last ); - auto size = gen.size(); + template <typename T> + class RepeatGenerator : public IGenerator<T> { + static_assert(!std::is_same<T, bool>::value, + "RepeatGenerator currently does not support bools" + "because of std::vector<bool> specialization"); + GeneratorWrapper<T> m_generator; + mutable std::vector<T> m_returned; + size_t m_target_repeats; + size_t m_current_repeat = 0; + size_t m_repeat_index = 0; + public: + RepeatGenerator(size_t repeats, GeneratorWrapper<T>&& generator): + m_generator(std::move(generator)), + m_target_repeats(repeats) + { + assert(m_target_repeats > 0 && "Repeat generator must repeat at least once"); + } + + T const& get() const override { + if (m_current_repeat == 0) { + m_returned.push_back(m_generator.get()); + return m_returned.back(); + } + return m_returned[m_repeat_index]; + } + + bool next() override { + // There are 2 basic cases: + // 1) We are still reading the generator + // 2) We are reading our own cache - return Generator<T>( size, pf::make_unique<GeneratorRandomiser<T>>( std::move( gen ), size ) ); + // In the first case, we need to poke the underlying generator. + // If it happily moves, we are left in that state, otherwise it is time to start reading from our cache + if (m_current_repeat == 0) { + const auto success = m_generator.next(); + if (!success) { + ++m_current_repeat; + } + return m_current_repeat < m_target_repeats; + } + + // In the second case, we need to move indices forward and check that we haven't run up against the end + ++m_repeat_index; + if (m_repeat_index == m_returned.size()) { + m_repeat_index = 0; + ++m_current_repeat; + } + return m_current_repeat < m_target_repeats; + } + }; + + template <typename T> + GeneratorWrapper<T> repeat(size_t repeats, GeneratorWrapper<T>&& generator) { + return GeneratorWrapper<T>(pf::make_unique<RepeatGenerator<T>>(repeats, std::move(generator))); } - template<typename T> - auto random( size_t size ) -> Generator<T> { - return Generator<T>( size, pf::make_unique<GeneratorRandomiser<T>>( all<T>(), size ) ); + + template <typename T, typename U, typename Func> + class MapGenerator : public IGenerator<T> { + // TBD: provide static assert for mapping function, for friendly error message + GeneratorWrapper<U> m_generator; + Func m_function; + // To avoid returning dangling reference, we have to save the values + T m_cache; + public: + template <typename F2 = Func> + MapGenerator(F2&& function, GeneratorWrapper<U>&& generator) : + m_generator(std::move(generator)), + m_function(std::forward<F2>(function)), + m_cache(m_function(m_generator.get())) + {} + + T const& get() const override { + return m_cache; + } + bool next() override { + const auto success = m_generator.next(); + if (success) { + m_cache = m_function(m_generator.get()); + } + return success; + } + }; + + template <typename Func, typename U, typename T = FunctionReturnType<Func, U>> + GeneratorWrapper<T> map(Func&& function, GeneratorWrapper<U>&& generator) { + return GeneratorWrapper<T>( + pf::make_unique<MapGenerator<T, U, Func>>(std::forward<Func>(function), std::move(generator)) + ); } - template<typename T> - auto values( std::initializer_list<T> values ) -> Generator<T> { - return Generator<T>( values.size(), pf::make_unique<FixedValuesGenerator<T>>( values ) ); + template <typename T, typename U, typename Func> + GeneratorWrapper<T> map(Func&& function, GeneratorWrapper<U>&& generator) { + return GeneratorWrapper<T>( + pf::make_unique<MapGenerator<T, U, Func>>(std::forward<Func>(function), std::move(generator)) + ); } - template<typename T> - auto value( T const& val ) -> Generator<T> { - return Generator<T>( 1, pf::make_unique<SingleValueGenerator<T>>( val ) ); + + template <typename T> + class ChunkGenerator final : public IGenerator<std::vector<T>> { + std::vector<T> m_chunk; + size_t m_chunk_size; + GeneratorWrapper<T> m_generator; + bool m_used_up = false; + public: + ChunkGenerator(size_t size, GeneratorWrapper<T> generator) : + m_chunk_size(size), m_generator(std::move(generator)) + { + m_chunk.reserve(m_chunk_size); + if (m_chunk_size != 0) { + m_chunk.push_back(m_generator.get()); + for (size_t i = 1; i < m_chunk_size; ++i) { + if (!m_generator.next()) { + Catch::throw_exception(GeneratorException("Not enough values to initialize the first chunk")); + } + m_chunk.push_back(m_generator.get()); + } + } + } + std::vector<T> const& get() const override { + return m_chunk; + } + bool next() override { + m_chunk.clear(); + for (size_t idx = 0; idx < m_chunk_size; ++idx) { + if (!m_generator.next()) { + return false; + } + m_chunk.push_back(m_generator.get()); + } + return true; + } + }; + + template <typename T> + GeneratorWrapper<std::vector<T>> chunk(size_t size, GeneratorWrapper<T>&& generator) { + return GeneratorWrapper<std::vector<T>>( + pf::make_unique<ChunkGenerator<T>>(size, std::move(generator)) + ); } - template<typename T> - auto as() -> Generator<T> { - return Generator<T>( 0, pf::make_unique<NullGenerator<T>>() ); +} // namespace Generators +} // namespace Catch + +// end catch_generators_generic.hpp +// start catch_generators_specific.hpp + +// start catch_context.h + +#include <memory> + +namespace Catch { + + struct IResultCapture; + struct IRunner; + struct IConfig; + struct IMutableContext; + + using IConfigPtr = std::shared_ptr<IConfig const>; + + struct IContext + { + virtual ~IContext(); + + virtual IResultCapture* getResultCapture() = 0; + virtual IRunner* getRunner() = 0; + virtual IConfigPtr const& getConfig() const = 0; + }; + + struct IMutableContext : IContext + { + virtual ~IMutableContext(); + virtual void setResultCapture( IResultCapture* resultCapture ) = 0; + virtual void setRunner( IRunner* runner ) = 0; + virtual void setConfig( IConfigPtr const& config ) = 0; + + private: + static IMutableContext *currentContext; + friend IMutableContext& getCurrentMutableContext(); + friend void cleanUpContext(); + static void createContext(); + }; + + inline IMutableContext& getCurrentMutableContext() + { + if( !IMutableContext::currentContext ) + IMutableContext::createContext(); + // NOLINTNEXTLINE(clang-analyzer-core.uninitialized.UndefReturn) + return *IMutableContext::currentContext; } - template<typename... Ts> - auto table( std::initializer_list<std::tuple<Ts...>>&& tuples ) -> Generator<std::tuple<Ts...>> { - return values<std::tuple<Ts...>>( std::forward<std::initializer_list<std::tuple<Ts...>>>( tuples ) ); + inline IContext& getCurrentContext() + { + return getCurrentMutableContext(); } - template<typename T> - struct Generators : GeneratorBase { - std::vector<Generator<T>> m_generators; + void cleanUpContext(); - using type = T; + class SimplePcg32; + SimplePcg32& rng(); +} + +// end catch_context.h +// start catch_interfaces_config.h + +// start catch_option.hpp - Generators() : GeneratorBase( 0 ) {} +namespace Catch { - void populate( T&& val ) { - m_size += 1; - m_generators.emplace_back( value( std::move( val ) ) ); + // An optional type + template<typename T> + class Option { + public: + Option() : nullableValue( nullptr ) {} + Option( T const& _value ) + : nullableValue( new( storage ) T( _value ) ) + {} + Option( Option const& _other ) + : nullableValue( _other ? new( storage ) T( *_other ) : nullptr ) + {} + + ~Option() { + reset(); } - template<typename U> - void populate( U&& val ) { - populate( T( std::move( val ) ) ); + + Option& operator= ( Option const& _other ) { + if( &_other != this ) { + reset(); + if( _other ) + nullableValue = new( storage ) T( *_other ); + } + return *this; + } + Option& operator = ( T const& _value ) { + reset(); + nullableValue = new( storage ) T( _value ); + return *this; } - void populate( Generator<T>&& generator ) { - m_size += generator.size(); - m_generators.emplace_back( std::move( generator ) ); + + void reset() { + if( nullableValue ) + nullableValue->~T(); + nullableValue = nullptr; } - template<typename U, typename... Gs> - void populate( U&& valueOrGenerator, Gs... moreGenerators ) { - populate( std::forward<U>( valueOrGenerator ) ); - populate( std::forward<Gs>( moreGenerators )... ); + T& operator*() { return *nullableValue; } + T const& operator*() const { return *nullableValue; } + T* operator->() { return nullableValue; } + const T* operator->() const { return nullableValue; } + + T valueOr( T const& defaultValue ) const { + return nullableValue ? *nullableValue : defaultValue; } - auto operator[]( size_t index ) const -> T { - size_t sizes = 0; - for( auto const& gen : m_generators ) { - auto localIndex = index-sizes; - sizes += gen.size(); - if( index < sizes ) - return gen[localIndex]; - } - CATCH_INTERNAL_ERROR("Index '" << index << "' is out of range (" << sizes << ')'); + bool some() const { return nullableValue != nullptr; } + bool none() const { return nullableValue == nullptr; } + + bool operator !() const { return nullableValue == nullptr; } + explicit operator bool() const { + return some(); } + + private: + T *nullableValue; + alignas(alignof(T)) char storage[sizeof(T)]; }; - template<typename T, typename... Gs> - auto makeGenerators( Generator<T>&& generator, Gs... moreGenerators ) -> Generators<T> { - Generators<T> generators; - generators.m_generators.reserve( 1+sizeof...(Gs) ); - generators.populate( std::move( generator ), std::forward<Gs>( moreGenerators )... ); - return generators; +} // end namespace Catch + +// end catch_option.hpp +#include <chrono> +#include <iosfwd> +#include <string> +#include <vector> +#include <memory> + +namespace Catch { + + enum class Verbosity { + Quiet = 0, + Normal, + High + }; + + struct WarnAbout { enum What { + Nothing = 0x00, + NoAssertions = 0x01, + NoTests = 0x02 + }; }; + + struct ShowDurations { enum OrNot { + DefaultForReporter, + Always, + Never + }; }; + struct RunTests { enum InWhatOrder { + InDeclarationOrder, + InLexicographicalOrder, + InRandomOrder + }; }; + struct UseColour { enum YesOrNo { + Auto, + Yes, + No + }; }; + struct WaitForKeypress { enum When { + Never, + BeforeStart = 1, + BeforeExit = 2, + BeforeStartAndExit = BeforeStart | BeforeExit + }; }; + + class TestSpec; + + struct IConfig : NonCopyable { + + virtual ~IConfig(); + + virtual bool allowThrows() const = 0; + virtual std::ostream& stream() const = 0; + virtual std::string name() const = 0; + virtual bool includeSuccessfulResults() const = 0; + virtual bool shouldDebugBreak() const = 0; + virtual bool warnAboutMissingAssertions() const = 0; + virtual bool warnAboutNoTests() const = 0; + virtual int abortAfter() const = 0; + virtual bool showInvisibles() const = 0; + virtual ShowDurations::OrNot showDurations() const = 0; + virtual double minDuration() const = 0; + virtual TestSpec const& testSpec() const = 0; + virtual bool hasTestFilters() const = 0; + virtual std::vector<std::string> const& getTestsOrTags() const = 0; + virtual RunTests::InWhatOrder runOrder() const = 0; + virtual unsigned int rngSeed() const = 0; + virtual UseColour::YesOrNo useColour() const = 0; + virtual std::vector<std::string> const& getSectionsToRun() const = 0; + virtual Verbosity verbosity() const = 0; + + virtual bool benchmarkNoAnalysis() const = 0; + virtual int benchmarkSamples() const = 0; + virtual double benchmarkConfidenceInterval() const = 0; + virtual unsigned int benchmarkResamples() const = 0; + virtual std::chrono::milliseconds benchmarkWarmupTime() const = 0; + }; + + using IConfigPtr = std::shared_ptr<IConfig const>; +} + +// end catch_interfaces_config.h +// start catch_random_number_generator.h + +#include <cstdint> + +namespace Catch { + + // This is a simple implementation of C++11 Uniform Random Number + // Generator. It does not provide all operators, because Catch2 + // does not use it, but it should behave as expected inside stdlib's + // distributions. + // The implementation is based on the PCG family (http://pcg-random.org) + class SimplePcg32 { + using state_type = std::uint64_t; + public: + using result_type = std::uint32_t; + static constexpr result_type (min)() { + return 0; + } + static constexpr result_type (max)() { + return static_cast<result_type>(-1); + } + + // Provide some default initial state for the default constructor + SimplePcg32():SimplePcg32(0xed743cc4U) {} + + explicit SimplePcg32(result_type seed_); + + void seed(result_type seed_); + void discard(uint64_t skip); + + result_type operator()(); + + private: + friend bool operator==(SimplePcg32 const& lhs, SimplePcg32 const& rhs); + friend bool operator!=(SimplePcg32 const& lhs, SimplePcg32 const& rhs); + + // In theory we also need operator<< and operator>> + // In practice we do not use them, so we will skip them for now + + std::uint64_t m_state; + // This part of the state determines which "stream" of the numbers + // is chosen -- we take it as a constant for Catch2, so we only + // need to deal with seeding the main state. + // Picked by reading 8 bytes from `/dev/random` :-) + static const std::uint64_t s_inc = (0x13ed0cc53f939476ULL << 1ULL) | 1ULL; + }; + +} // end namespace Catch + +// end catch_random_number_generator.h +#include <random> + +namespace Catch { +namespace Generators { + +template <typename Float> +class RandomFloatingGenerator final : public IGenerator<Float> { + Catch::SimplePcg32& m_rng; + std::uniform_real_distribution<Float> m_dist; + Float m_current_number; +public: + + RandomFloatingGenerator(Float a, Float b): + m_rng(rng()), + m_dist(a, b) { + static_cast<void>(next()); } - template<typename T> - auto makeGenerators( Generator<T>&& generator ) -> Generators<T> { - Generators<T> generators; - generators.populate( std::move( generator ) ); - return generators; + + Float const& get() const override { + return m_current_number; } - template<typename T, typename... Gs> - auto makeGenerators( T&& val, Gs... moreGenerators ) -> Generators<T> { - return makeGenerators( value( std::forward<T>( val ) ), std::forward<Gs>( moreGenerators )... ); + bool next() override { + m_current_number = m_dist(m_rng); + return true; } - template<typename T, typename U, typename... Gs> - auto makeGenerators( U&& val, Gs... moreGenerators ) -> Generators<T> { - return makeGenerators( value( T( std::forward<U>( val ) ) ), std::forward<Gs>( moreGenerators )... ); +}; + +template <typename Integer> +class RandomIntegerGenerator final : public IGenerator<Integer> { + Catch::SimplePcg32& m_rng; + std::uniform_int_distribution<Integer> m_dist; + Integer m_current_number; +public: + + RandomIntegerGenerator(Integer a, Integer b): + m_rng(rng()), + m_dist(a, b) { + static_cast<void>(next()); } - auto acquireGeneratorTracker( SourceLineInfo const& lineInfo ) -> IGeneratorTracker&; + Integer const& get() const override { + return m_current_number; + } + bool next() override { + m_current_number = m_dist(m_rng); + return true; + } +}; - template<typename L> - // Note: The type after -> is weird, because VS2015 cannot parse - // the expression used in the typedef inside, when it is in - // return type. Yeah, ¯\_(ツ)_/¯ - auto generate( SourceLineInfo const& lineInfo, L const& generatorExpression ) -> decltype(std::declval<decltype(generatorExpression())>()[0]) { - using UnderlyingType = typename decltype(generatorExpression())::type; +// TODO: Ideally this would be also constrained against the various char types, +// but I don't expect users to run into that in practice. +template <typename T> +typename std::enable_if<std::is_integral<T>::value && !std::is_same<T, bool>::value, +GeneratorWrapper<T>>::type +random(T a, T b) { + return GeneratorWrapper<T>( + pf::make_unique<RandomIntegerGenerator<T>>(a, b) + ); +} + +template <typename T> +typename std::enable_if<std::is_floating_point<T>::value, +GeneratorWrapper<T>>::type +random(T a, T b) { + return GeneratorWrapper<T>( + pf::make_unique<RandomFloatingGenerator<T>>(a, b) + ); +} + +template <typename T> +class RangeGenerator final : public IGenerator<T> { + T m_current; + T m_end; + T m_step; + bool m_positive; + +public: + RangeGenerator(T const& start, T const& end, T const& step): + m_current(start), + m_end(end), + m_step(step), + m_positive(m_step > T(0)) + { + assert(m_current != m_end && "Range start and end cannot be equal"); + assert(m_step != T(0) && "Step size cannot be zero"); + assert(((m_positive && m_current <= m_end) || (!m_positive && m_current >= m_end)) && "Step moves away from end"); + } + + RangeGenerator(T const& start, T const& end): + RangeGenerator(start, end, (start < end) ? T(1) : T(-1)) + {} + + T const& get() const override { + return m_current; + } - IGeneratorTracker& tracker = acquireGeneratorTracker( lineInfo ); - if( !tracker.hasGenerator() ) - tracker.setGenerator( pf::make_unique<Generators<UnderlyingType>>( generatorExpression() ) ); + bool next() override { + m_current += m_step; + return (m_positive) ? (m_current < m_end) : (m_current > m_end); + } +}; + +template <typename T> +GeneratorWrapper<T> range(T const& start, T const& end, T const& step) { + static_assert(std::is_arithmetic<T>::value && !std::is_same<T, bool>::value, "Type must be numeric"); + return GeneratorWrapper<T>(pf::make_unique<RangeGenerator<T>>(start, end, step)); +} + +template <typename T> +GeneratorWrapper<T> range(T const& start, T const& end) { + static_assert(std::is_integral<T>::value && !std::is_same<T, bool>::value, "Type must be an integer"); + return GeneratorWrapper<T>(pf::make_unique<RangeGenerator<T>>(start, end)); +} + +template <typename T> +class IteratorGenerator final : public IGenerator<T> { + static_assert(!std::is_same<T, bool>::value, + "IteratorGenerator currently does not support bools" + "because of std::vector<bool> specialization"); - auto const& generator = static_cast<Generators<UnderlyingType> const&>( *tracker.getGenerator() ); - return generator[tracker.getIndex()]; + std::vector<T> m_elems; + size_t m_current = 0; +public: + template <typename InputIterator, typename InputSentinel> + IteratorGenerator(InputIterator first, InputSentinel last):m_elems(first, last) { + if (m_elems.empty()) { + Catch::throw_exception(GeneratorException("IteratorGenerator received no valid values")); + } } + T const& get() const override { + return m_elems[m_current]; + } + + bool next() override { + ++m_current; + return m_current != m_elems.size(); + } +}; + +template <typename InputIterator, + typename InputSentinel, + typename ResultType = typename std::iterator_traits<InputIterator>::value_type> +GeneratorWrapper<ResultType> from_range(InputIterator from, InputSentinel to) { + return GeneratorWrapper<ResultType>(pf::make_unique<IteratorGenerator<ResultType>>(from, to)); +} + +template <typename Container, + typename ResultType = typename Container::value_type> +GeneratorWrapper<ResultType> from_range(Container const& cnt) { + return GeneratorWrapper<ResultType>(pf::make_unique<IteratorGenerator<ResultType>>(cnt.begin(), cnt.end())); +} + } // namespace Generators } // namespace Catch -#define GENERATE( ... ) \ - Catch::Generators::generate( CATCH_INTERNAL_LINEINFO, []{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } ) - -// end catch_generators.hpp +// end catch_generators_specific.hpp // These files are included here so the single_include script doesn't put them // in the conditionally compiled sections @@ -3662,7 +4950,7 @@ namespace Catch { arcSafeRelease( m_substr ); } - bool match( NSString* arg ) const override { + bool match( NSString* str ) const override { return false; } @@ -3685,7 +4973,7 @@ namespace Catch { struct Contains : StringHolder { Contains( NSString* substr ) : StringHolder( substr ){} - bool match( NSString* str ) const { + bool match( NSString* str ) const override { return (str != nil || m_substr == nil ) && [str rangeOfString:m_substr].location != NSNotFound; } @@ -3761,7 +5049,8 @@ return @ desc; \ // end catch_objc.hpp #endif -#ifdef CATCH_CONFIG_EXTERNAL_INTERFACES +// Benchmarking needs the externally-facing parts of reporters to work +#if defined(CATCH_CONFIG_EXTERNAL_INTERFACES) || defined(CATCH_CONFIG_ENABLE_BENCHMARKING) // start catch_external_interfaces.h // start catch_reporter_bases.hpp @@ -3803,7 +5092,7 @@ namespace Catch virtual bool matches( std::string const& str ) const; private: - std::string adjustCase( std::string const& str ) const; + std::string normaliseString( std::string const& str ) const; CaseSensitive::Choice m_caseSensitivity; WildcardPosition m_wildcard = NoWildcard; std::string m_pattern; @@ -3817,36 +5106,40 @@ namespace Catch namespace Catch { + struct IConfig; + class TestSpec { - struct Pattern { + class Pattern { + public: + explicit Pattern( std::string const& name ); virtual ~Pattern(); virtual bool matches( TestCaseInfo const& testCase ) const = 0; + std::string const& name() const; + private: + std::string const m_name; }; using PatternPtr = std::shared_ptr<Pattern>; class NamePattern : public Pattern { public: - NamePattern( std::string const& name ); - virtual ~NamePattern(); - virtual bool matches( TestCaseInfo const& testCase ) const override; + explicit NamePattern( std::string const& name, std::string const& filterString ); + bool matches( TestCaseInfo const& testCase ) const override; private: WildcardPattern m_wildcardPattern; }; class TagPattern : public Pattern { public: - TagPattern( std::string const& tag ); - virtual ~TagPattern(); - virtual bool matches( TestCaseInfo const& testCase ) const override; + explicit TagPattern( std::string const& tag, std::string const& filterString ); + bool matches( TestCaseInfo const& testCase ) const override; private: std::string m_tag; }; class ExcludedPattern : public Pattern { public: - ExcludedPattern( PatternPtr const& underlyingPattern ); - virtual ~ExcludedPattern(); - virtual bool matches( TestCaseInfo const& testCase ) const override; + explicit ExcludedPattern( PatternPtr const& underlyingPattern ); + bool matches( TestCaseInfo const& testCase ) const override; private: PatternPtr m_underlyingPattern; }; @@ -3855,15 +5148,25 @@ namespace Catch { std::vector<PatternPtr> m_patterns; bool matches( TestCaseInfo const& testCase ) const; + std::string name() const; }; public: + struct FilterMatch { + std::string name; + std::vector<TestCase const*> tests; + }; + using Matches = std::vector<FilterMatch>; + using vectorStrings = std::vector<std::string>; + bool hasFilters() const; bool matches( TestCaseInfo const& testCase ) const; + Matches matchesByFilter( std::vector<TestCase> const& testCases, IConfig const& config ) const; + const vectorStrings & getInvalidArgs() const; private: std::vector<Filter> m_filters; - + std::vector<std::string> m_invalidArgs; friend class TestSpecParser; }; } @@ -3898,9 +5201,13 @@ namespace Catch { class TestSpecParser { enum Mode{ None, Name, QuotedName, Tag, EscapedName }; Mode m_mode = None; + Mode lastMode = None; bool m_exclusion = false; - std::size_t m_start = std::string::npos, m_pos = 0; + std::size_t m_pos = 0; + std::size_t m_realPatternPos = 0; std::string m_arg; + std::string m_substring; + std::string m_patternName; std::vector<std::size_t> m_escapeChars; TestSpec::Filter m_currentFilter; TestSpec m_testSpec; @@ -3913,32 +5220,32 @@ namespace Catch { TestSpec testSpec(); private: - void visitChar( char c ); - void startNewMode( Mode mode, std::size_t start ); + bool visitChar( char c ); + void startNewMode( Mode mode ); + bool processNoneChar( char c ); + void processNameChar( char c ); + bool processOtherChar( char c ); + void endMode(); void escape(); - std::string subString() const; + bool isControlChar( char c ) const; + void saveLastMode(); + void revertBackToLastMode(); + void addFilter(); + bool separate(); - template<typename T> - void addPattern() { - std::string token = subString(); - for( std::size_t i = 0; i < m_escapeChars.size(); ++i ) - token = token.substr( 0, m_escapeChars[i]-m_start-i ) + token.substr( m_escapeChars[i]-m_start-i+1 ); - m_escapeChars.clear(); - if( startsWith( token, "exclude:" ) ) { - m_exclusion = true; - token = token.substr( 8 ); - } - if( !token.empty() ) { - TestSpec::PatternPtr pattern = std::make_shared<T>( token ); - if( m_exclusion ) - pattern = std::make_shared<TestSpec::ExcludedPattern>( pattern ); - m_currentFilter.m_patterns.push_back( pattern ); - } - m_exclusion = false; - m_mode = None; + // Handles common preprocessing of the pattern for name/tag patterns + std::string preprocessPattern(); + // Adds the current pattern as a test name + void addNamePattern(); + // Adds the current pattern as a tag + void addTagPattern(); + + inline void addCharToPattern(char c) { + m_substring += c; + m_patternName += c; + m_realPatternPos++; } - void addFilter(); }; TestSpec parseTestSpec( std::string const& arg ); @@ -3949,79 +5256,6 @@ namespace Catch { #endif // end catch_test_spec_parser.h -// start catch_interfaces_config.h - -#include <iosfwd> -#include <string> -#include <vector> -#include <memory> - -namespace Catch { - - enum class Verbosity { - Quiet = 0, - Normal, - High - }; - - struct WarnAbout { enum What { - Nothing = 0x00, - NoAssertions = 0x01, - NoTests = 0x02 - }; }; - - struct ShowDurations { enum OrNot { - DefaultForReporter, - Always, - Never - }; }; - struct RunTests { enum InWhatOrder { - InDeclarationOrder, - InLexicographicalOrder, - InRandomOrder - }; }; - struct UseColour { enum YesOrNo { - Auto, - Yes, - No - }; }; - struct WaitForKeypress { enum When { - Never, - BeforeStart = 1, - BeforeExit = 2, - BeforeStartAndExit = BeforeStart | BeforeExit - }; }; - - class TestSpec; - - struct IConfig : NonCopyable { - - virtual ~IConfig(); - - virtual bool allowThrows() const = 0; - virtual std::ostream& stream() const = 0; - virtual std::string name() const = 0; - virtual bool includeSuccessfulResults() const = 0; - virtual bool shouldDebugBreak() const = 0; - virtual bool warnAboutMissingAssertions() const = 0; - virtual bool warnAboutNoTests() const = 0; - virtual int abortAfter() const = 0; - virtual bool showInvisibles() const = 0; - virtual ShowDurations::OrNot showDurations() const = 0; - virtual TestSpec const& testSpec() const = 0; - virtual bool hasTestFilters() const = 0; - virtual RunTests::InWhatOrder runOrder() const = 0; - virtual unsigned int rngSeed() const = 0; - virtual int benchmarkResolutionMultiple() const = 0; - virtual UseColour::YesOrNo useColour() const = 0; - virtual std::vector<std::string> const& getSectionsToRun() const = 0; - virtual Verbosity verbosity() const = 0; - }; - - using IConfigPtr = std::shared_ptr<IConfig const>; -} - -// end catch_interfaces_config.h // Libstdc++ doesn't like incomplete classes for unique_ptr #include <memory> @@ -4052,11 +5286,17 @@ namespace Catch { int abortAfter = -1; unsigned int rngSeed = 0; - int benchmarkResolutionMultiple = 100; + + bool benchmarkNoAnalysis = false; + unsigned int benchmarkSamples = 100; + double benchmarkConfidenceInterval = 0.95; + unsigned int benchmarkResamples = 100000; + std::chrono::milliseconds::rep benchmarkWarmupTime = 100; Verbosity verbosity = Verbosity::Normal; WarnAbout::What warnings = WarnAbout::Nothing; ShowDurations::OrNot showDurations = ShowDurations::DefaultForReporter; + double minDuration = -1; RunTests::InWhatOrder runOrder = RunTests::InDeclarationOrder; UseColour::YesOrNo useColour = UseColour::Auto; WaitForKeypress::When waitForKeypress = WaitForKeypress::Never; @@ -4091,10 +5331,10 @@ namespace Catch { std::string getProcessName() const; std::string const& getReporterName() const; - std::vector<std::string> const& getTestsOrTags() const; + std::vector<std::string> const& getTestsOrTags() const override; std::vector<std::string> const& getSectionsToRun() const override; - virtual TestSpec const& testSpec() const override; + TestSpec const& testSpec() const override; bool hasTestFilters() const override; bool showHelp() const; @@ -4107,14 +5347,19 @@ namespace Catch { bool warnAboutMissingAssertions() const override; bool warnAboutNoTests() const override; ShowDurations::OrNot showDurations() const override; + double minDuration() const override; RunTests::InWhatOrder runOrder() const override; unsigned int rngSeed() const override; - int benchmarkResolutionMultiple() const override; UseColour::YesOrNo useColour() const override; bool shouldDebugBreak() const override; int abortAfter() const override; bool showInvisibles() const override; Verbosity verbosity() const override; + bool benchmarkNoAnalysis() const override; + int benchmarkSamples() const override; + double benchmarkConfidenceInterval() const override; + unsigned int benchmarkResamples() const override; + std::chrono::milliseconds benchmarkWarmupTime() const override; private: @@ -4175,76 +5420,61 @@ namespace Catch { } // end namespace Catch // end catch_assertionresult.h -// start catch_option.hpp +#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING) +// start catch_estimate.hpp -namespace Catch { - - // An optional type - template<typename T> - class Option { - public: - Option() : nullableValue( nullptr ) {} - Option( T const& _value ) - : nullableValue( new( storage ) T( _value ) ) - {} - Option( Option const& _other ) - : nullableValue( _other ? new( storage ) T( *_other ) : nullptr ) - {} + // Statistics estimates - ~Option() { - reset(); - } - Option& operator= ( Option const& _other ) { - if( &_other != this ) { - reset(); - if( _other ) - nullableValue = new( storage ) T( *_other ); +namespace Catch { + namespace Benchmark { + template <typename Duration> + struct Estimate { + Duration point; + Duration lower_bound; + Duration upper_bound; + double confidence_interval; + + template <typename Duration2> + operator Estimate<Duration2>() const { + return { point, lower_bound, upper_bound, confidence_interval }; } - return *this; - } - Option& operator = ( T const& _value ) { - reset(); - nullableValue = new( storage ) T( _value ); - return *this; - } - - void reset() { - if( nullableValue ) - nullableValue->~T(); - nullableValue = nullptr; - } + }; + } // namespace Benchmark +} // namespace Catch - T& operator*() { return *nullableValue; } - T const& operator*() const { return *nullableValue; } - T* operator->() { return nullableValue; } - const T* operator->() const { return nullableValue; } +// end catch_estimate.hpp +// start catch_outlier_classification.hpp - T valueOr( T const& defaultValue ) const { - return nullableValue ? *nullableValue : defaultValue; - } - - bool some() const { return nullableValue != nullptr; } - bool none() const { return nullableValue == nullptr; } +// Outlier information - bool operator !() const { return nullableValue == nullptr; } - explicit operator bool() const { - return some(); - } +namespace Catch { + namespace Benchmark { + struct OutlierClassification { + int samples_seen = 0; + int low_severe = 0; // more than 3 times IQR below Q1 + int low_mild = 0; // 1.5 to 3 times IQR below Q1 + int high_mild = 0; // 1.5 to 3 times IQR above Q3 + int high_severe = 0; // more than 3 times IQR above Q3 + + int total() const { + return low_severe + low_mild + high_mild + high_severe; + } + }; + } // namespace Benchmark +} // namespace Catch - private: - T *nullableValue; - alignas(alignof(T)) char storage[sizeof(T)]; - }; +// end catch_outlier_classification.hpp -} // end namespace Catch +#include <iterator> +#endif // CATCH_CONFIG_ENABLE_BENCHMARKING -// end catch_option.hpp #include <string> #include <iosfwd> #include <map> #include <set> #include <memory> +#include <algorithm> namespace Catch { @@ -4301,8 +5531,8 @@ namespace Catch { AssertionStats( AssertionStats const& ) = default; AssertionStats( AssertionStats && ) = default; - AssertionStats& operator = ( AssertionStats const& ) = default; - AssertionStats& operator = ( AssertionStats && ) = default; + AssertionStats& operator = ( AssertionStats const& ) = delete; + AssertionStats& operator = ( AssertionStats && ) = delete; virtual ~AssertionStats(); AssertionResult assertionResult; @@ -4380,14 +5610,43 @@ namespace Catch { bool aborting; }; +#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING) struct BenchmarkInfo { std::string name; + double estimatedDuration; + int iterations; + int samples; + unsigned int resamples; + double clockResolution; + double clockCost; }; + + template <class Duration> struct BenchmarkStats { BenchmarkInfo info; - std::size_t iterations; - uint64_t elapsedTimeInNanoseconds; + + std::vector<Duration> samples; + Benchmark::Estimate<Duration> mean; + Benchmark::Estimate<Duration> standardDeviation; + Benchmark::OutlierClassification outliers; + double outlierVariance; + + template <typename Duration2> + operator BenchmarkStats<Duration2>() const { + std::vector<Duration2> samples2; + samples2.reserve(samples.size()); + std::transform(samples.begin(), samples.end(), std::back_inserter(samples2), [](Duration d) { return Duration2(d); }); + return { + info, + std::move(samples2), + mean, + standardDeviation, + outliers, + outlierVariance, + }; + } }; +#endif // CATCH_CONFIG_ENABLE_BENCHMARKING struct IStreamingReporter { virtual ~IStreamingReporter() = default; @@ -4400,23 +5659,26 @@ namespace Catch { virtual void noMatchingTestCases( std::string const& spec ) = 0; + virtual void reportInvalidArguments(std::string const&) {} + virtual void testRunStarting( TestRunInfo const& testRunInfo ) = 0; virtual void testGroupStarting( GroupInfo const& groupInfo ) = 0; virtual void testCaseStarting( TestCaseInfo const& testInfo ) = 0; virtual void sectionStarting( SectionInfo const& sectionInfo ) = 0; - // *** experimental *** +#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING) + virtual void benchmarkPreparing( std::string const& ) {} virtual void benchmarkStarting( BenchmarkInfo const& ) {} + virtual void benchmarkEnded( BenchmarkStats<> const& ) {} + virtual void benchmarkFailed( std::string const& ) {} +#endif // CATCH_CONFIG_ENABLE_BENCHMARKING virtual void assertionStarting( AssertionInfo const& assertionInfo ) = 0; // The return value indicates if the messages buffer should be cleared: virtual bool assertionEnded( AssertionStats const& assertionStats ) = 0; - // *** experimental *** - virtual void benchmarkEnded( BenchmarkStats const& ) {} - virtual void sectionEnded( SectionStats const& sectionStats ) = 0; virtual void testCaseEnded( TestCaseStats const& testCaseStats ) = 0; virtual void testGroupEnded( TestGroupStats const& testGroupStats ) = 0; @@ -4465,6 +5727,11 @@ namespace Catch { // Returns double formatted as %.3f (format expected on output) std::string getFormattedDuration( double duration ); + //! Should the reporter show + bool shouldShowDuration( IConfig const& config, double duration ); + + std::string serializeFilters( std::vector<std::string> const& container ); + template<typename DerivedT> struct StreamingReporterBase : IStreamingReporter { @@ -4489,9 +5756,12 @@ namespace Catch { void noMatchingTestCases(std::string const&) override {} + void reportInvalidArguments(std::string const&) override {} + void testRunStarting(TestRunInfo const& _testRunInfo) override { currentTestRunInfo = _testRunInfo; } + void testGroupStarting(GroupInfo const& _groupInfo) override { currentGroupInfo = _groupInfo; } @@ -4782,11 +6052,11 @@ namespace Catch { class ReporterFactory : public IReporterFactory { - virtual IStreamingReporterPtr create( ReporterConfig const& config ) const override { + IStreamingReporterPtr create( ReporterConfig const& config ) const override { return std::unique_ptr<T>( new T( config ) ); } - virtual std::string getDescription() const override { + std::string getDescription() const override { return T::getDescription(); } }; @@ -4803,10 +6073,10 @@ namespace Catch { class ListenerFactory : public IReporterFactory { - virtual IStreamingReporterPtr create( ReporterConfig const& config ) const override { + IStreamingReporterPtr create( ReporterConfig const& config ) const override { return std::unique_ptr<T>( new T( config ) ); } - virtual std::string getDescription() const override { + std::string getDescription() const override { return std::string(); } }; @@ -4822,14 +6092,16 @@ namespace Catch { #if !defined(CATCH_CONFIG_DISABLE) #define CATCH_REGISTER_REPORTER( name, reporterType ) \ + CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ namespace{ Catch::ReporterRegistrar<reporterType> catch_internal_RegistrarFor##reporterType( name ); } \ - CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS + CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION #define CATCH_REGISTER_LISTENER( listenerType ) \ - CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ - namespace{ Catch::ListenerRegistrar<listenerType> catch_internal_RegistrarFor##listenerType; } \ - CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS + CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ + CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ + namespace{ Catch::ListenerRegistrar<listenerType> catch_internal_RegistrarFor##listenerType; } \ + CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION #else // CATCH_CONFIG_DISABLE #define CATCH_REGISTER_REPORTER(name, reporterType) @@ -4851,8 +6123,6 @@ namespace Catch { static std::string getDescription(); - ReporterPreferences getPreferences() const override; - void noMatchingTestCases(std::string const& spec) override; void assertionStarting(AssertionInfo const&) override; @@ -4891,6 +6161,8 @@ namespace Catch { void noMatchingTestCases(std::string const& spec) override; + void reportInvalidArguments(std::string const&arg) override; + void assertionStarting(AssertionInfo const&) override; bool assertionEnded(AssertionStats const& _assertionStats) override; @@ -4898,13 +6170,17 @@ namespace Catch { void sectionStarting(SectionInfo const& _sectionInfo) override; void sectionEnded(SectionStats const& _sectionStats) override; +#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING) + void benchmarkPreparing(std::string const& name) override; void benchmarkStarting(BenchmarkInfo const& info) override; - void benchmarkEnded(BenchmarkStats const& stats) override; + void benchmarkEnded(BenchmarkStats<> const& stats) override; + void benchmarkFailed(std::string const& error) override; +#endif // CATCH_CONFIG_ENABLE_BENCHMARKING void testCaseEnded(TestCaseStats const& _testCaseStats) override; void testGroupEnded(TestGroupStats const& _testGroupStats) override; void testRunEnded(TestRunStats const& _testRunStats) override; - + void testRunStarting(TestRunInfo const& _testRunInfo) override; private: void lazyPrint(); @@ -4926,6 +6202,7 @@ namespace Catch { void printTotalsDivider(Totals const& totals); void printSummaryDivider(); + void printTestFilters(); private: bool m_headerPrinted = false; @@ -4945,6 +6222,14 @@ namespace Catch { #include <vector> namespace Catch { + enum class XmlFormatting { + None = 0x00, + Indent = 0x01, + Newline = 0x02, + }; + + XmlFormatting operator | (XmlFormatting lhs, XmlFormatting rhs); + XmlFormatting operator & (XmlFormatting lhs, XmlFormatting rhs); class XmlEncode { public: @@ -4966,14 +6251,14 @@ namespace Catch { class ScopedElement { public: - ScopedElement( XmlWriter* writer ); + ScopedElement( XmlWriter* writer, XmlFormatting fmt ); ScopedElement( ScopedElement&& other ) noexcept; ScopedElement& operator=( ScopedElement&& other ) noexcept; ~ScopedElement(); - ScopedElement& writeText( std::string const& text, bool indent = true ); + ScopedElement& writeText( std::string const& text, XmlFormatting fmt = XmlFormatting::Newline | XmlFormatting::Indent ); template<typename T> ScopedElement& writeAttribute( std::string const& name, T const& attribute ) { @@ -4983,6 +6268,7 @@ namespace Catch { private: mutable XmlWriter* m_writer = nullptr; + XmlFormatting m_fmt; }; XmlWriter( std::ostream& os = Catch::cout() ); @@ -4991,11 +6277,11 @@ namespace Catch { XmlWriter( XmlWriter const& ) = delete; XmlWriter& operator=( XmlWriter const& ) = delete; - XmlWriter& startElement( std::string const& name ); + XmlWriter& startElement( std::string const& name, XmlFormatting fmt = XmlFormatting::Newline | XmlFormatting::Indent); - ScopedElement scopedElement( std::string const& name ); + ScopedElement scopedElement( std::string const& name, XmlFormatting fmt = XmlFormatting::Newline | XmlFormatting::Indent); - XmlWriter& endElement(); + XmlWriter& endElement(XmlFormatting fmt = XmlFormatting::Newline | XmlFormatting::Indent); XmlWriter& writeAttribute( std::string const& name, std::string const& attribute ); @@ -5008,9 +6294,9 @@ namespace Catch { return writeAttribute( name, rss.str() ); } - XmlWriter& writeText( std::string const& text, bool indent = true ); + XmlWriter& writeText( std::string const& text, XmlFormatting fmt = XmlFormatting::Newline | XmlFormatting::Indent); - XmlWriter& writeComment( std::string const& text ); + XmlWriter& writeComment(std::string const& text, XmlFormatting fmt = XmlFormatting::Newline | XmlFormatting::Indent); void writeStylesheetRef( std::string const& url ); @@ -5020,6 +6306,8 @@ namespace Catch { private: + void applyFormatting(XmlFormatting fmt); + void writeDeclaration(); void newlineIfNecessary(); @@ -5063,9 +6351,10 @@ namespace Catch { void writeTestCase(TestCaseNode const& testCaseNode); - void writeSection(std::string const& className, - std::string const& rootName, - SectionNode const& sectionNode); + void writeSection( std::string const& className, + std::string const& rootName, + SectionNode const& sectionNode, + bool testOkToFail ); void writeAssertions(SectionNode const& sectionNode); void writeAssertion(AssertionStats const& stats); @@ -5120,6 +6409,13 @@ namespace Catch { void testRunEnded(TestRunStats const& testRunStats) override; +#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING) + void benchmarkPreparing(std::string const& name) override; + void benchmarkStarting(BenchmarkInfo const&) override; + void benchmarkEnded(BenchmarkStats<> const&) override; + void benchmarkFailed(std::string const&) override; +#endif // CATCH_CONFIG_ENABLE_BENCHMARKING + private: Timer m_testCaseTimer; XmlWriter m_xml; @@ -5133,6 +6429,1032 @@ namespace Catch { // end catch_external_interfaces.h #endif +#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING) +// start catch_benchmarking_all.hpp + +// A proxy header that includes all of the benchmarking headers to allow +// concise include of the benchmarking features. You should prefer the +// individual includes in standard use. + +// start catch_benchmark.hpp + + // Benchmark + +// start catch_chronometer.hpp + +// User-facing chronometer + + +// start catch_clock.hpp + +// Clocks + + +#include <chrono> +#include <ratio> + +namespace Catch { + namespace Benchmark { + template <typename Clock> + using ClockDuration = typename Clock::duration; + template <typename Clock> + using FloatDuration = std::chrono::duration<double, typename Clock::period>; + + template <typename Clock> + using TimePoint = typename Clock::time_point; + + using default_clock = std::chrono::steady_clock; + + template <typename Clock> + struct now { + TimePoint<Clock> operator()() const { + return Clock::now(); + } + }; + + using fp_seconds = std::chrono::duration<double, std::ratio<1>>; + } // namespace Benchmark +} // namespace Catch + +// end catch_clock.hpp +// start catch_optimizer.hpp + + // Hinting the optimizer + + +#if defined(_MSC_VER) +# include <atomic> // atomic_thread_fence +#endif + +namespace Catch { + namespace Benchmark { +#if defined(__GNUC__) || defined(__clang__) + template <typename T> + inline void keep_memory(T* p) { + asm volatile("" : : "g"(p) : "memory"); + } + inline void keep_memory() { + asm volatile("" : : : "memory"); + } + + namespace Detail { + inline void optimizer_barrier() { keep_memory(); } + } // namespace Detail +#elif defined(_MSC_VER) + +#pragma optimize("", off) + template <typename T> + inline void keep_memory(T* p) { + // thanks @milleniumbug + *reinterpret_cast<char volatile*>(p) = *reinterpret_cast<char const volatile*>(p); + } + // TODO equivalent keep_memory() +#pragma optimize("", on) + + namespace Detail { + inline void optimizer_barrier() { + std::atomic_thread_fence(std::memory_order_seq_cst); + } + } // namespace Detail + +#endif + + template <typename T> + inline void deoptimize_value(T&& x) { + keep_memory(&x); + } + + template <typename Fn, typename... Args> + inline auto invoke_deoptimized(Fn&& fn, Args&&... args) -> typename std::enable_if<!std::is_same<void, decltype(fn(args...))>::value>::type { + deoptimize_value(std::forward<Fn>(fn) (std::forward<Args...>(args...))); + } + + template <typename Fn, typename... Args> + inline auto invoke_deoptimized(Fn&& fn, Args&&... args) -> typename std::enable_if<std::is_same<void, decltype(fn(args...))>::value>::type { + std::forward<Fn>(fn) (std::forward<Args...>(args...)); + } + } // namespace Benchmark +} // namespace Catch + +// end catch_optimizer.hpp +// start catch_complete_invoke.hpp + +// Invoke with a special case for void + + +#include <type_traits> +#include <utility> + +namespace Catch { + namespace Benchmark { + namespace Detail { + template <typename T> + struct CompleteType { using type = T; }; + template <> + struct CompleteType<void> { struct type {}; }; + + template <typename T> + using CompleteType_t = typename CompleteType<T>::type; + + template <typename Result> + struct CompleteInvoker { + template <typename Fun, typename... Args> + static Result invoke(Fun&& fun, Args&&... args) { + return std::forward<Fun>(fun)(std::forward<Args>(args)...); + } + }; + template <> + struct CompleteInvoker<void> { + template <typename Fun, typename... Args> + static CompleteType_t<void> invoke(Fun&& fun, Args&&... args) { + std::forward<Fun>(fun)(std::forward<Args>(args)...); + return {}; + } + }; + + // invoke and not return void :( + template <typename Fun, typename... Args> + CompleteType_t<FunctionReturnType<Fun, Args...>> complete_invoke(Fun&& fun, Args&&... args) { + return CompleteInvoker<FunctionReturnType<Fun, Args...>>::invoke(std::forward<Fun>(fun), std::forward<Args>(args)...); + } + + const std::string benchmarkErrorMsg = "a benchmark failed to run successfully"; + } // namespace Detail + + template <typename Fun> + Detail::CompleteType_t<FunctionReturnType<Fun>> user_code(Fun&& fun) { + CATCH_TRY{ + return Detail::complete_invoke(std::forward<Fun>(fun)); + } CATCH_CATCH_ALL{ + getResultCapture().benchmarkFailed(translateActiveException()); + CATCH_RUNTIME_ERROR(Detail::benchmarkErrorMsg); + } + } + } // namespace Benchmark +} // namespace Catch + +// end catch_complete_invoke.hpp +namespace Catch { + namespace Benchmark { + namespace Detail { + struct ChronometerConcept { + virtual void start() = 0; + virtual void finish() = 0; + virtual ~ChronometerConcept() = default; + }; + template <typename Clock> + struct ChronometerModel final : public ChronometerConcept { + void start() override { started = Clock::now(); } + void finish() override { finished = Clock::now(); } + + ClockDuration<Clock> elapsed() const { return finished - started; } + + TimePoint<Clock> started; + TimePoint<Clock> finished; + }; + } // namespace Detail + + struct Chronometer { + public: + template <typename Fun> + void measure(Fun&& fun) { measure(std::forward<Fun>(fun), is_callable<Fun(int)>()); } + + int runs() const { return k; } + + Chronometer(Detail::ChronometerConcept& meter, int k) + : impl(&meter) + , k(k) {} + + private: + template <typename Fun> + void measure(Fun&& fun, std::false_type) { + measure([&fun](int) { return fun(); }, std::true_type()); + } + + template <typename Fun> + void measure(Fun&& fun, std::true_type) { + Detail::optimizer_barrier(); + impl->start(); + for (int i = 0; i < k; ++i) invoke_deoptimized(fun, i); + impl->finish(); + Detail::optimizer_barrier(); + } + + Detail::ChronometerConcept* impl; + int k; + }; + } // namespace Benchmark +} // namespace Catch + +// end catch_chronometer.hpp +// start catch_environment.hpp + +// Environment information + + +namespace Catch { + namespace Benchmark { + template <typename Duration> + struct EnvironmentEstimate { + Duration mean; + OutlierClassification outliers; + + template <typename Duration2> + operator EnvironmentEstimate<Duration2>() const { + return { mean, outliers }; + } + }; + template <typename Clock> + struct Environment { + using clock_type = Clock; + EnvironmentEstimate<FloatDuration<Clock>> clock_resolution; + EnvironmentEstimate<FloatDuration<Clock>> clock_cost; + }; + } // namespace Benchmark +} // namespace Catch + +// end catch_environment.hpp +// start catch_execution_plan.hpp + + // Execution plan + + +// start catch_benchmark_function.hpp + + // Dumb std::function implementation for consistent call overhead + + +#include <cassert> +#include <type_traits> +#include <utility> +#include <memory> + +namespace Catch { + namespace Benchmark { + namespace Detail { + template <typename T> + using Decay = typename std::decay<T>::type; + template <typename T, typename U> + struct is_related + : std::is_same<Decay<T>, Decay<U>> {}; + + /// We need to reinvent std::function because every piece of code that might add overhead + /// in a measurement context needs to have consistent performance characteristics so that we + /// can account for it in the measurement. + /// Implementations of std::function with optimizations that aren't always applicable, like + /// small buffer optimizations, are not uncommon. + /// This is effectively an implementation of std::function without any such optimizations; + /// it may be slow, but it is consistently slow. + struct BenchmarkFunction { + private: + struct callable { + virtual void call(Chronometer meter) const = 0; + virtual callable* clone() const = 0; + virtual ~callable() = default; + }; + template <typename Fun> + struct model : public callable { + model(Fun&& fun) : fun(std::move(fun)) {} + model(Fun const& fun) : fun(fun) {} + + model<Fun>* clone() const override { return new model<Fun>(*this); } + + void call(Chronometer meter) const override { + call(meter, is_callable<Fun(Chronometer)>()); + } + void call(Chronometer meter, std::true_type) const { + fun(meter); + } + void call(Chronometer meter, std::false_type) const { + meter.measure(fun); + } + + Fun fun; + }; + + struct do_nothing { void operator()() const {} }; + + template <typename T> + BenchmarkFunction(model<T>* c) : f(c) {} + + public: + BenchmarkFunction() + : f(new model<do_nothing>{ {} }) {} + + template <typename Fun, + typename std::enable_if<!is_related<Fun, BenchmarkFunction>::value, int>::type = 0> + BenchmarkFunction(Fun&& fun) + : f(new model<typename std::decay<Fun>::type>(std::forward<Fun>(fun))) {} + + BenchmarkFunction(BenchmarkFunction&& that) + : f(std::move(that.f)) {} + + BenchmarkFunction(BenchmarkFunction const& that) + : f(that.f->clone()) {} + + BenchmarkFunction& operator=(BenchmarkFunction&& that) { + f = std::move(that.f); + return *this; + } + + BenchmarkFunction& operator=(BenchmarkFunction const& that) { + f.reset(that.f->clone()); + return *this; + } + + void operator()(Chronometer meter) const { f->call(meter); } + + private: + std::unique_ptr<callable> f; + }; + } // namespace Detail + } // namespace Benchmark +} // namespace Catch + +// end catch_benchmark_function.hpp +// start catch_repeat.hpp + +// repeat algorithm + + +#include <type_traits> +#include <utility> + +namespace Catch { + namespace Benchmark { + namespace Detail { + template <typename Fun> + struct repeater { + void operator()(int k) const { + for (int i = 0; i < k; ++i) { + fun(); + } + } + Fun fun; + }; + template <typename Fun> + repeater<typename std::decay<Fun>::type> repeat(Fun&& fun) { + return { std::forward<Fun>(fun) }; + } + } // namespace Detail + } // namespace Benchmark +} // namespace Catch + +// end catch_repeat.hpp +// start catch_run_for_at_least.hpp + +// Run a function for a minimum amount of time + + +// start catch_measure.hpp + +// Measure + + +// start catch_timing.hpp + +// Timing + + +#include <tuple> +#include <type_traits> + +namespace Catch { + namespace Benchmark { + template <typename Duration, typename Result> + struct Timing { + Duration elapsed; + Result result; + int iterations; + }; + template <typename Clock, typename Func, typename... Args> + using TimingOf = Timing<ClockDuration<Clock>, Detail::CompleteType_t<FunctionReturnType<Func, Args...>>>; + } // namespace Benchmark +} // namespace Catch + +// end catch_timing.hpp +#include <utility> + +namespace Catch { + namespace Benchmark { + namespace Detail { + template <typename Clock, typename Fun, typename... Args> + TimingOf<Clock, Fun, Args...> measure(Fun&& fun, Args&&... args) { + auto start = Clock::now(); + auto&& r = Detail::complete_invoke(fun, std::forward<Args>(args)...); + auto end = Clock::now(); + auto delta = end - start; + return { delta, std::forward<decltype(r)>(r), 1 }; + } + } // namespace Detail + } // namespace Benchmark +} // namespace Catch + +// end catch_measure.hpp +#include <utility> +#include <type_traits> + +namespace Catch { + namespace Benchmark { + namespace Detail { + template <typename Clock, typename Fun> + TimingOf<Clock, Fun, int> measure_one(Fun&& fun, int iters, std::false_type) { + return Detail::measure<Clock>(fun, iters); + } + template <typename Clock, typename Fun> + TimingOf<Clock, Fun, Chronometer> measure_one(Fun&& fun, int iters, std::true_type) { + Detail::ChronometerModel<Clock> meter; + auto&& result = Detail::complete_invoke(fun, Chronometer(meter, iters)); + + return { meter.elapsed(), std::move(result), iters }; + } + + template <typename Clock, typename Fun> + using run_for_at_least_argument_t = typename std::conditional<is_callable<Fun(Chronometer)>::value, Chronometer, int>::type; + + struct optimized_away_error : std::exception { + const char* what() const noexcept override { + return "could not measure benchmark, maybe it was optimized away"; + } + }; + + template <typename Clock, typename Fun> + TimingOf<Clock, Fun, run_for_at_least_argument_t<Clock, Fun>> run_for_at_least(ClockDuration<Clock> how_long, int seed, Fun&& fun) { + auto iters = seed; + while (iters < (1 << 30)) { + auto&& Timing = measure_one<Clock>(fun, iters, is_callable<Fun(Chronometer)>()); + + if (Timing.elapsed >= how_long) { + return { Timing.elapsed, std::move(Timing.result), iters }; + } + iters *= 2; + } + Catch::throw_exception(optimized_away_error{}); + } + } // namespace Detail + } // namespace Benchmark +} // namespace Catch + +// end catch_run_for_at_least.hpp +#include <algorithm> +#include <iterator> + +namespace Catch { + namespace Benchmark { + template <typename Duration> + struct ExecutionPlan { + int iterations_per_sample; + Duration estimated_duration; + Detail::BenchmarkFunction benchmark; + Duration warmup_time; + int warmup_iterations; + + template <typename Duration2> + operator ExecutionPlan<Duration2>() const { + return { iterations_per_sample, estimated_duration, benchmark, warmup_time, warmup_iterations }; + } + + template <typename Clock> + std::vector<FloatDuration<Clock>> run(const IConfig &cfg, Environment<FloatDuration<Clock>> env) const { + // warmup a bit + Detail::run_for_at_least<Clock>(std::chrono::duration_cast<ClockDuration<Clock>>(warmup_time), warmup_iterations, Detail::repeat(now<Clock>{})); + + std::vector<FloatDuration<Clock>> times; + times.reserve(cfg.benchmarkSamples()); + std::generate_n(std::back_inserter(times), cfg.benchmarkSamples(), [this, env] { + Detail::ChronometerModel<Clock> model; + this->benchmark(Chronometer(model, iterations_per_sample)); + auto sample_time = model.elapsed() - env.clock_cost.mean; + if (sample_time < FloatDuration<Clock>::zero()) sample_time = FloatDuration<Clock>::zero(); + return sample_time / iterations_per_sample; + }); + return times; + } + }; + } // namespace Benchmark +} // namespace Catch + +// end catch_execution_plan.hpp +// start catch_estimate_clock.hpp + + // Environment measurement + + +// start catch_stats.hpp + +// Statistical analysis tools + + +#include <algorithm> +#include <functional> +#include <vector> +#include <iterator> +#include <numeric> +#include <tuple> +#include <cmath> +#include <utility> +#include <cstddef> +#include <random> + +namespace Catch { + namespace Benchmark { + namespace Detail { + using sample = std::vector<double>; + + double weighted_average_quantile(int k, int q, std::vector<double>::iterator first, std::vector<double>::iterator last); + + template <typename Iterator> + OutlierClassification classify_outliers(Iterator first, Iterator last) { + std::vector<double> copy(first, last); + + auto q1 = weighted_average_quantile(1, 4, copy.begin(), copy.end()); + auto q3 = weighted_average_quantile(3, 4, copy.begin(), copy.end()); + auto iqr = q3 - q1; + auto los = q1 - (iqr * 3.); + auto lom = q1 - (iqr * 1.5); + auto him = q3 + (iqr * 1.5); + auto his = q3 + (iqr * 3.); + + OutlierClassification o; + for (; first != last; ++first) { + auto&& t = *first; + if (t < los) ++o.low_severe; + else if (t < lom) ++o.low_mild; + else if (t > his) ++o.high_severe; + else if (t > him) ++o.high_mild; + ++o.samples_seen; + } + return o; + } + + template <typename Iterator> + double mean(Iterator first, Iterator last) { + auto count = last - first; + double sum = std::accumulate(first, last, 0.); + return sum / count; + } + + template <typename URng, typename Iterator, typename Estimator> + sample resample(URng& rng, int resamples, Iterator first, Iterator last, Estimator& estimator) { + auto n = last - first; + std::uniform_int_distribution<decltype(n)> dist(0, n - 1); + + sample out; + out.reserve(resamples); + std::generate_n(std::back_inserter(out), resamples, [n, first, &estimator, &dist, &rng] { + std::vector<double> resampled; + resampled.reserve(n); + std::generate_n(std::back_inserter(resampled), n, [first, &dist, &rng] { return first[dist(rng)]; }); + return estimator(resampled.begin(), resampled.end()); + }); + std::sort(out.begin(), out.end()); + return out; + } + + template <typename Estimator, typename Iterator> + sample jackknife(Estimator&& estimator, Iterator first, Iterator last) { + auto n = last - first; + auto second = std::next(first); + sample results; + results.reserve(n); + + for (auto it = first; it != last; ++it) { + std::iter_swap(it, first); + results.push_back(estimator(second, last)); + } + + return results; + } + + inline double normal_cdf(double x) { + return std::erfc(-x / std::sqrt(2.0)) / 2.0; + } + + double erfc_inv(double x); + + double normal_quantile(double p); + + template <typename Iterator, typename Estimator> + Estimate<double> bootstrap(double confidence_level, Iterator first, Iterator last, sample const& resample, Estimator&& estimator) { + auto n_samples = last - first; + + double point = estimator(first, last); + // Degenerate case with a single sample + if (n_samples == 1) return { point, point, point, confidence_level }; + + sample jack = jackknife(estimator, first, last); + double jack_mean = mean(jack.begin(), jack.end()); + double sum_squares, sum_cubes; + std::tie(sum_squares, sum_cubes) = std::accumulate(jack.begin(), jack.end(), std::make_pair(0., 0.), [jack_mean](std::pair<double, double> sqcb, double x) -> std::pair<double, double> { + auto d = jack_mean - x; + auto d2 = d * d; + auto d3 = d2 * d; + return { sqcb.first + d2, sqcb.second + d3 }; + }); + + double accel = sum_cubes / (6 * std::pow(sum_squares, 1.5)); + int n = static_cast<int>(resample.size()); + double prob_n = std::count_if(resample.begin(), resample.end(), [point](double x) { return x < point; }) / (double)n; + // degenerate case with uniform samples + if (prob_n == 0) return { point, point, point, confidence_level }; + + double bias = normal_quantile(prob_n); + double z1 = normal_quantile((1. - confidence_level) / 2.); + + auto cumn = [n](double x) -> int { + return std::lround(normal_cdf(x) * n); }; + auto a = [bias, accel](double b) { return bias + b / (1. - accel * b); }; + double b1 = bias + z1; + double b2 = bias - z1; + double a1 = a(b1); + double a2 = a(b2); + auto lo = (std::max)(cumn(a1), 0); + auto hi = (std::min)(cumn(a2), n - 1); + + return { point, resample[lo], resample[hi], confidence_level }; + } + + double outlier_variance(Estimate<double> mean, Estimate<double> stddev, int n); + + struct bootstrap_analysis { + Estimate<double> mean; + Estimate<double> standard_deviation; + double outlier_variance; + }; + + bootstrap_analysis analyse_samples(double confidence_level, int n_resamples, std::vector<double>::iterator first, std::vector<double>::iterator last); + } // namespace Detail + } // namespace Benchmark +} // namespace Catch + +// end catch_stats.hpp +#include <algorithm> +#include <iterator> +#include <tuple> +#include <vector> +#include <cmath> + +namespace Catch { + namespace Benchmark { + namespace Detail { + template <typename Clock> + std::vector<double> resolution(int k) { + std::vector<TimePoint<Clock>> times; + times.reserve(k + 1); + std::generate_n(std::back_inserter(times), k + 1, now<Clock>{}); + + std::vector<double> deltas; + deltas.reserve(k); + std::transform(std::next(times.begin()), times.end(), times.begin(), + std::back_inserter(deltas), + [](TimePoint<Clock> a, TimePoint<Clock> b) { return static_cast<double>((a - b).count()); }); + + return deltas; + } + + const auto warmup_iterations = 10000; + const auto warmup_time = std::chrono::milliseconds(100); + const auto minimum_ticks = 1000; + const auto warmup_seed = 10000; + const auto clock_resolution_estimation_time = std::chrono::milliseconds(500); + const auto clock_cost_estimation_time_limit = std::chrono::seconds(1); + const auto clock_cost_estimation_tick_limit = 100000; + const auto clock_cost_estimation_time = std::chrono::milliseconds(10); + const auto clock_cost_estimation_iterations = 10000; + + template <typename Clock> + int warmup() { + return run_for_at_least<Clock>(std::chrono::duration_cast<ClockDuration<Clock>>(warmup_time), warmup_seed, &resolution<Clock>) + .iterations; + } + template <typename Clock> + EnvironmentEstimate<FloatDuration<Clock>> estimate_clock_resolution(int iterations) { + auto r = run_for_at_least<Clock>(std::chrono::duration_cast<ClockDuration<Clock>>(clock_resolution_estimation_time), iterations, &resolution<Clock>) + .result; + return { + FloatDuration<Clock>(mean(r.begin(), r.end())), + classify_outliers(r.begin(), r.end()), + }; + } + template <typename Clock> + EnvironmentEstimate<FloatDuration<Clock>> estimate_clock_cost(FloatDuration<Clock> resolution) { + auto time_limit = (std::min)( + resolution * clock_cost_estimation_tick_limit, + FloatDuration<Clock>(clock_cost_estimation_time_limit)); + auto time_clock = [](int k) { + return Detail::measure<Clock>([k] { + for (int i = 0; i < k; ++i) { + volatile auto ignored = Clock::now(); + (void)ignored; + } + }).elapsed; + }; + time_clock(1); + int iters = clock_cost_estimation_iterations; + auto&& r = run_for_at_least<Clock>(std::chrono::duration_cast<ClockDuration<Clock>>(clock_cost_estimation_time), iters, time_clock); + std::vector<double> times; + int nsamples = static_cast<int>(std::ceil(time_limit / r.elapsed)); + times.reserve(nsamples); + std::generate_n(std::back_inserter(times), nsamples, [time_clock, &r] { + return static_cast<double>((time_clock(r.iterations) / r.iterations).count()); + }); + return { + FloatDuration<Clock>(mean(times.begin(), times.end())), + classify_outliers(times.begin(), times.end()), + }; + } + + template <typename Clock> + Environment<FloatDuration<Clock>> measure_environment() { + static Environment<FloatDuration<Clock>>* env = nullptr; + if (env) { + return *env; + } + + auto iters = Detail::warmup<Clock>(); + auto resolution = Detail::estimate_clock_resolution<Clock>(iters); + auto cost = Detail::estimate_clock_cost<Clock>(resolution.mean); + + env = new Environment<FloatDuration<Clock>>{ resolution, cost }; + return *env; + } + } // namespace Detail + } // namespace Benchmark +} // namespace Catch + +// end catch_estimate_clock.hpp +// start catch_analyse.hpp + + // Run and analyse one benchmark + + +// start catch_sample_analysis.hpp + +// Benchmark results + + +#include <algorithm> +#include <vector> +#include <string> +#include <iterator> + +namespace Catch { + namespace Benchmark { + template <typename Duration> + struct SampleAnalysis { + std::vector<Duration> samples; + Estimate<Duration> mean; + Estimate<Duration> standard_deviation; + OutlierClassification outliers; + double outlier_variance; + + template <typename Duration2> + operator SampleAnalysis<Duration2>() const { + std::vector<Duration2> samples2; + samples2.reserve(samples.size()); + std::transform(samples.begin(), samples.end(), std::back_inserter(samples2), [](Duration d) { return Duration2(d); }); + return { + std::move(samples2), + mean, + standard_deviation, + outliers, + outlier_variance, + }; + } + }; + } // namespace Benchmark +} // namespace Catch + +// end catch_sample_analysis.hpp +#include <algorithm> +#include <iterator> +#include <vector> + +namespace Catch { + namespace Benchmark { + namespace Detail { + template <typename Duration, typename Iterator> + SampleAnalysis<Duration> analyse(const IConfig &cfg, Environment<Duration>, Iterator first, Iterator last) { + if (!cfg.benchmarkNoAnalysis()) { + std::vector<double> samples; + samples.reserve(last - first); + std::transform(first, last, std::back_inserter(samples), [](Duration d) { return d.count(); }); + + auto analysis = Catch::Benchmark::Detail::analyse_samples(cfg.benchmarkConfidenceInterval(), cfg.benchmarkResamples(), samples.begin(), samples.end()); + auto outliers = Catch::Benchmark::Detail::classify_outliers(samples.begin(), samples.end()); + + auto wrap_estimate = [](Estimate<double> e) { + return Estimate<Duration> { + Duration(e.point), + Duration(e.lower_bound), + Duration(e.upper_bound), + e.confidence_interval, + }; + }; + std::vector<Duration> samples2; + samples2.reserve(samples.size()); + std::transform(samples.begin(), samples.end(), std::back_inserter(samples2), [](double d) { return Duration(d); }); + return { + std::move(samples2), + wrap_estimate(analysis.mean), + wrap_estimate(analysis.standard_deviation), + outliers, + analysis.outlier_variance, + }; + } else { + std::vector<Duration> samples; + samples.reserve(last - first); + + Duration mean = Duration(0); + int i = 0; + for (auto it = first; it < last; ++it, ++i) { + samples.push_back(Duration(*it)); + mean += Duration(*it); + } + mean /= i; + + return { + std::move(samples), + Estimate<Duration>{mean, mean, mean, 0.0}, + Estimate<Duration>{Duration(0), Duration(0), Duration(0), 0.0}, + OutlierClassification{}, + 0.0 + }; + } + } + } // namespace Detail + } // namespace Benchmark +} // namespace Catch + +// end catch_analyse.hpp +#include <algorithm> +#include <functional> +#include <string> +#include <vector> +#include <cmath> + +namespace Catch { + namespace Benchmark { + struct Benchmark { + Benchmark(std::string &&name) + : name(std::move(name)) {} + + template <class FUN> + Benchmark(std::string &&name, FUN &&func) + : fun(std::move(func)), name(std::move(name)) {} + + template <typename Clock> + ExecutionPlan<FloatDuration<Clock>> prepare(const IConfig &cfg, Environment<FloatDuration<Clock>> env) const { + auto min_time = env.clock_resolution.mean * Detail::minimum_ticks; + auto run_time = std::max(min_time, std::chrono::duration_cast<decltype(min_time)>(cfg.benchmarkWarmupTime())); + auto&& test = Detail::run_for_at_least<Clock>(std::chrono::duration_cast<ClockDuration<Clock>>(run_time), 1, fun); + int new_iters = static_cast<int>(std::ceil(min_time * test.iterations / test.elapsed)); + return { new_iters, test.elapsed / test.iterations * new_iters * cfg.benchmarkSamples(), fun, std::chrono::duration_cast<FloatDuration<Clock>>(cfg.benchmarkWarmupTime()), Detail::warmup_iterations }; + } + + template <typename Clock = default_clock> + void run() { + IConfigPtr cfg = getCurrentContext().getConfig(); + + auto env = Detail::measure_environment<Clock>(); + + getResultCapture().benchmarkPreparing(name); + CATCH_TRY{ + auto plan = user_code([&] { + return prepare<Clock>(*cfg, env); + }); + + BenchmarkInfo info { + name, + plan.estimated_duration.count(), + plan.iterations_per_sample, + cfg->benchmarkSamples(), + cfg->benchmarkResamples(), + env.clock_resolution.mean.count(), + env.clock_cost.mean.count() + }; + + getResultCapture().benchmarkStarting(info); + + auto samples = user_code([&] { + return plan.template run<Clock>(*cfg, env); + }); + + auto analysis = Detail::analyse(*cfg, env, samples.begin(), samples.end()); + BenchmarkStats<FloatDuration<Clock>> stats{ info, analysis.samples, analysis.mean, analysis.standard_deviation, analysis.outliers, analysis.outlier_variance }; + getResultCapture().benchmarkEnded(stats); + + } CATCH_CATCH_ALL{ + if (translateActiveException() != Detail::benchmarkErrorMsg) // benchmark errors have been reported, otherwise rethrow. + std::rethrow_exception(std::current_exception()); + } + } + + // sets lambda to be used in fun *and* executes benchmark! + template <typename Fun, + typename std::enable_if<!Detail::is_related<Fun, Benchmark>::value, int>::type = 0> + Benchmark & operator=(Fun func) { + fun = Detail::BenchmarkFunction(func); + run(); + return *this; + } + + explicit operator bool() { + return true; + } + + private: + Detail::BenchmarkFunction fun; + std::string name; + }; + } +} // namespace Catch + +#define INTERNAL_CATCH_GET_1_ARG(arg1, arg2, ...) arg1 +#define INTERNAL_CATCH_GET_2_ARG(arg1, arg2, ...) arg2 + +#define INTERNAL_CATCH_BENCHMARK(BenchmarkName, name, benchmarkIndex)\ + if( Catch::Benchmark::Benchmark BenchmarkName{name} ) \ + BenchmarkName = [&](int benchmarkIndex) + +#define INTERNAL_CATCH_BENCHMARK_ADVANCED(BenchmarkName, name)\ + if( Catch::Benchmark::Benchmark BenchmarkName{name} ) \ + BenchmarkName = [&] + +// end catch_benchmark.hpp +// start catch_constructor.hpp + +// Constructor and destructor helpers + + +#include <type_traits> + +namespace Catch { + namespace Benchmark { + namespace Detail { + template <typename T, bool Destruct> + struct ObjectStorage + { + using TStorage = typename std::aligned_storage<sizeof(T), std::alignment_of<T>::value>::type; + + ObjectStorage() : data() {} + + ObjectStorage(const ObjectStorage& other) + { + new(&data) T(other.stored_object()); + } + + ObjectStorage(ObjectStorage&& other) + { + new(&data) T(std::move(other.stored_object())); + } + + ~ObjectStorage() { destruct_on_exit<T>(); } + + template <typename... Args> + void construct(Args&&... args) + { + new (&data) T(std::forward<Args>(args)...); + } + + template <bool AllowManualDestruction = !Destruct> + typename std::enable_if<AllowManualDestruction>::type destruct() + { + stored_object().~T(); + } + + private: + // If this is a constructor benchmark, destruct the underlying object + template <typename U> + void destruct_on_exit(typename std::enable_if<Destruct, U>::type* = 0) { destruct<true>(); } + // Otherwise, don't + template <typename U> + void destruct_on_exit(typename std::enable_if<!Destruct, U>::type* = 0) { } + + T& stored_object() { + return *static_cast<T*>(static_cast<void*>(&data)); + } + + T const& stored_object() const { + return *static_cast<T*>(static_cast<void*>(&data)); + } + + TStorage data; + }; + } + + template <typename T> + using storage_for = Detail::ObjectStorage<T, true>; + + template <typename T> + using destructable_object = Detail::ObjectStorage<T, false>; + } +} + +// end catch_constructor.hpp +// end catch_benchmarking_all.hpp +#endif + #endif // ! CATCH_CONFIG_IMPL_ONLY #ifdef CATCH_IMPL @@ -5158,23 +7480,37 @@ namespace TestCaseTracking { SourceLineInfo location; NameAndLocation( std::string const& _name, SourceLineInfo const& _location ); + friend bool operator==(NameAndLocation const& lhs, NameAndLocation const& rhs) { + return lhs.name == rhs.name + && lhs.location == rhs.location; + } }; - struct ITracker; + class ITracker; using ITrackerPtr = std::shared_ptr<ITracker>; - struct ITracker { - virtual ~ITracker(); + class ITracker { + NameAndLocation m_nameAndLocation; + + public: + ITracker(NameAndLocation const& nameAndLoc) : + m_nameAndLocation(nameAndLoc) + {} // static queries - virtual NameAndLocation const& nameAndLocation() const = 0; + NameAndLocation const& nameAndLocation() const { + return m_nameAndLocation; + } + + virtual ~ITracker(); // dynamic queries virtual bool isComplete() const = 0; // Successfully completed or failed virtual bool isSuccessfullyCompleted() const = 0; virtual bool isOpen() const = 0; // Started but not complete virtual bool hasChildren() const = 0; + virtual bool hasStarted() const = 0; virtual ITracker& parent() = 0; @@ -5189,7 +7525,7 @@ namespace TestCaseTracking { // Debug/ checking virtual bool isSectionTracker() const = 0; - virtual bool isIndexTracker() const = 0; + virtual bool isGeneratorTracker() const = 0; }; class TrackerContext { @@ -5206,8 +7542,6 @@ namespace TestCaseTracking { public: - static TrackerContext& instance(); - ITracker& startRun(); void endRun(); @@ -5231,7 +7565,6 @@ namespace TestCaseTracking { }; using Children = std::vector<ITrackerPtr>; - NameAndLocation m_nameAndLocation; TrackerContext& m_ctx; ITracker* m_parent; Children m_children; @@ -5240,11 +7573,13 @@ namespace TestCaseTracking { public: TrackerBase( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent ); - NameAndLocation const& nameAndLocation() const override; bool isComplete() const override; bool isSuccessfullyCompleted() const override; bool isOpen() const override; bool hasChildren() const override; + bool hasStarted() const override { + return m_runState != NotStarted; + } void addChild( ITrackerPtr const& child ) override; @@ -5254,7 +7589,7 @@ namespace TestCaseTracking { void openChild() override; bool isSectionTracker() const override; - bool isIndexTracker() const override; + bool isGeneratorTracker() const override; void open(); @@ -5269,33 +7604,24 @@ namespace TestCaseTracking { class SectionTracker : public TrackerBase { std::vector<std::string> m_filters; + std::string m_trimmed_name; public: SectionTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent ); bool isSectionTracker() const override; + bool isComplete() const override; + static SectionTracker& acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation ); void tryOpen(); void addInitialFilters( std::vector<std::string> const& filters ); void addNextFilters( std::vector<std::string> const& filters ); - }; - - class IndexTracker : public TrackerBase { - int m_size; - int m_index = -1; - public: - IndexTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent, int size ); - - bool isIndexTracker() const override; - void close() override; - - static IndexTracker& acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation, int size ); - - int index() const; - - void moveNext(); + //! Returns filters active in this tracker + std::vector<std::string> const& getFilters() const; + //! Returns whitespace-trimmed name of the tracked section + std::string const& trimmedName() const; }; } // namespace TestCaseTracking @@ -5303,7 +7629,6 @@ namespace TestCaseTracking { using TestCaseTracking::ITracker; using TestCaseTracking::TrackerContext; using TestCaseTracking::SectionTracker; -using TestCaseTracking::IndexTracker; } // namespace Catch @@ -5321,6 +7646,217 @@ namespace Catch { } // end catch_leak_detector.h // Cpp files will be included in the single-header file here +// start catch_stats.cpp + +// Statistical analysis tools + +#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING) + +#include <cassert> +#include <random> + +#if defined(CATCH_CONFIG_USE_ASYNC) +#include <future> +#endif + +namespace { + double erf_inv(double x) { + // Code accompanying the article "Approximating the erfinv function" in GPU Computing Gems, Volume 2 + double w, p; + + w = -log((1.0 - x) * (1.0 + x)); + + if (w < 6.250000) { + w = w - 3.125000; + p = -3.6444120640178196996e-21; + p = -1.685059138182016589e-19 + p * w; + p = 1.2858480715256400167e-18 + p * w; + p = 1.115787767802518096e-17 + p * w; + p = -1.333171662854620906e-16 + p * w; + p = 2.0972767875968561637e-17 + p * w; + p = 6.6376381343583238325e-15 + p * w; + p = -4.0545662729752068639e-14 + p * w; + p = -8.1519341976054721522e-14 + p * w; + p = 2.6335093153082322977e-12 + p * w; + p = -1.2975133253453532498e-11 + p * w; + p = -5.4154120542946279317e-11 + p * w; + p = 1.051212273321532285e-09 + p * w; + p = -4.1126339803469836976e-09 + p * w; + p = -2.9070369957882005086e-08 + p * w; + p = 4.2347877827932403518e-07 + p * w; + p = -1.3654692000834678645e-06 + p * w; + p = -1.3882523362786468719e-05 + p * w; + p = 0.0001867342080340571352 + p * w; + p = -0.00074070253416626697512 + p * w; + p = -0.0060336708714301490533 + p * w; + p = 0.24015818242558961693 + p * w; + p = 1.6536545626831027356 + p * w; + } else if (w < 16.000000) { + w = sqrt(w) - 3.250000; + p = 2.2137376921775787049e-09; + p = 9.0756561938885390979e-08 + p * w; + p = -2.7517406297064545428e-07 + p * w; + p = 1.8239629214389227755e-08 + p * w; + p = 1.5027403968909827627e-06 + p * w; + p = -4.013867526981545969e-06 + p * w; + p = 2.9234449089955446044e-06 + p * w; + p = 1.2475304481671778723e-05 + p * w; + p = -4.7318229009055733981e-05 + p * w; + p = 6.8284851459573175448e-05 + p * w; + p = 2.4031110387097893999e-05 + p * w; + p = -0.0003550375203628474796 + p * w; + p = 0.00095328937973738049703 + p * w; + p = -0.0016882755560235047313 + p * w; + p = 0.0024914420961078508066 + p * w; + p = -0.0037512085075692412107 + p * w; + p = 0.005370914553590063617 + p * w; + p = 1.0052589676941592334 + p * w; + p = 3.0838856104922207635 + p * w; + } else { + w = sqrt(w) - 5.000000; + p = -2.7109920616438573243e-11; + p = -2.5556418169965252055e-10 + p * w; + p = 1.5076572693500548083e-09 + p * w; + p = -3.7894654401267369937e-09 + p * w; + p = 7.6157012080783393804e-09 + p * w; + p = -1.4960026627149240478e-08 + p * w; + p = 2.9147953450901080826e-08 + p * w; + p = -6.7711997758452339498e-08 + p * w; + p = 2.2900482228026654717e-07 + p * w; + p = -9.9298272942317002539e-07 + p * w; + p = 4.5260625972231537039e-06 + p * w; + p = -1.9681778105531670567e-05 + p * w; + p = 7.5995277030017761139e-05 + p * w; + p = -0.00021503011930044477347 + p * w; + p = -0.00013871931833623122026 + p * w; + p = 1.0103004648645343977 + p * w; + p = 4.8499064014085844221 + p * w; + } + return p * x; + } + + double standard_deviation(std::vector<double>::iterator first, std::vector<double>::iterator last) { + auto m = Catch::Benchmark::Detail::mean(first, last); + double variance = std::accumulate(first, last, 0., [m](double a, double b) { + double diff = b - m; + return a + diff * diff; + }) / (last - first); + return std::sqrt(variance); + } + +} + +namespace Catch { + namespace Benchmark { + namespace Detail { + + double weighted_average_quantile(int k, int q, std::vector<double>::iterator first, std::vector<double>::iterator last) { + auto count = last - first; + double idx = (count - 1) * k / static_cast<double>(q); + int j = static_cast<int>(idx); + double g = idx - j; + std::nth_element(first, first + j, last); + auto xj = first[j]; + if (g == 0) return xj; + + auto xj1 = *std::min_element(first + (j + 1), last); + return xj + g * (xj1 - xj); + } + + double erfc_inv(double x) { + return erf_inv(1.0 - x); + } + + double normal_quantile(double p) { + static const double ROOT_TWO = std::sqrt(2.0); + + double result = 0.0; + assert(p >= 0 && p <= 1); + if (p < 0 || p > 1) { + return result; + } + + result = -erfc_inv(2.0 * p); + // result *= normal distribution standard deviation (1.0) * sqrt(2) + result *= /*sd * */ ROOT_TWO; + // result += normal disttribution mean (0) + return result; + } + + double outlier_variance(Estimate<double> mean, Estimate<double> stddev, int n) { + double sb = stddev.point; + double mn = mean.point / n; + double mg_min = mn / 2.; + double sg = (std::min)(mg_min / 4., sb / std::sqrt(n)); + double sg2 = sg * sg; + double sb2 = sb * sb; + + auto c_max = [n, mn, sb2, sg2](double x) -> double { + double k = mn - x; + double d = k * k; + double nd = n * d; + double k0 = -n * nd; + double k1 = sb2 - n * sg2 + nd; + double det = k1 * k1 - 4 * sg2 * k0; + return (int)(-2. * k0 / (k1 + std::sqrt(det))); + }; + + auto var_out = [n, sb2, sg2](double c) { + double nc = n - c; + return (nc / n) * (sb2 - nc * sg2); + }; + + return (std::min)(var_out(1), var_out((std::min)(c_max(0.), c_max(mg_min)))) / sb2; + } + + bootstrap_analysis analyse_samples(double confidence_level, int n_resamples, std::vector<double>::iterator first, std::vector<double>::iterator last) { + CATCH_INTERNAL_START_WARNINGS_SUPPRESSION + CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS + static std::random_device entropy; + CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION + + auto n = static_cast<int>(last - first); // seriously, one can't use integral types without hell in C++ + + auto mean = &Detail::mean<std::vector<double>::iterator>; + auto stddev = &standard_deviation; + +#if defined(CATCH_CONFIG_USE_ASYNC) + auto Estimate = [=](double(*f)(std::vector<double>::iterator, std::vector<double>::iterator)) { + auto seed = entropy(); + return std::async(std::launch::async, [=] { + std::mt19937 rng(seed); + auto resampled = resample(rng, n_resamples, first, last, f); + return bootstrap(confidence_level, first, last, resampled, f); + }); + }; + + auto mean_future = Estimate(mean); + auto stddev_future = Estimate(stddev); + + auto mean_estimate = mean_future.get(); + auto stddev_estimate = stddev_future.get(); +#else + auto Estimate = [=](double(*f)(std::vector<double>::iterator, std::vector<double>::iterator)) { + auto seed = entropy(); + std::mt19937 rng(seed); + auto resampled = resample(rng, n_resamples, first, last, f); + return bootstrap(confidence_level, first, last, resampled, f); + }; + + auto mean_estimate = Estimate(mean); + auto stddev_estimate = Estimate(stddev); +#endif // CATCH_USE_ASYNC + + double outlier_variance = Detail::outlier_variance(mean_estimate, stddev_estimate, n); + + return { mean_estimate, stddev_estimate, outlier_variance }; + } + } // namespace Detail + } // namespace Benchmark +} // namespace Catch + +#endif // CATCH_CONFIG_ENABLE_BENCHMARKING +// end catch_stats.cpp // start catch_approx.cpp #include <cmath> @@ -5365,21 +7901,22 @@ namespace Detail { bool Approx::equalityComparisonImpl(const double other) const { // First try with fixed margin, then compute margin based on epsilon, scale and Approx's value // Thanks to Richard Harris for his help refining the scaled margin value - return marginComparison(m_value, other, m_margin) || marginComparison(m_value, other, m_epsilon * (m_scale + std::fabs(m_value))); + return marginComparison(m_value, other, m_margin) + || marginComparison(m_value, other, m_epsilon * (m_scale + std::fabs(std::isinf(m_value)? 0 : m_value))); } - void Approx::setMargin(double margin) { - CATCH_ENFORCE(margin >= 0, - "Invalid Approx::margin: " << margin << '.' + void Approx::setMargin(double newMargin) { + CATCH_ENFORCE(newMargin >= 0, + "Invalid Approx::margin: " << newMargin << '.' << " Approx::Margin has to be non-negative."); - m_margin = margin; + m_margin = newMargin; } - void Approx::setEpsilon(double epsilon) { - CATCH_ENFORCE(epsilon >= 0 && epsilon <= 1.0, - "Invalid Approx::epsilon: " << epsilon << '.' + void Approx::setEpsilon(double newEpsilon) { + CATCH_ENFORCE(newEpsilon >= 0 && newEpsilon <= 1.0, + "Invalid Approx::epsilon: " << newEpsilon << '.' << " Approx::epsilon has to be in [0, 1]"); - m_epsilon = epsilon; + m_epsilon = newEpsilon; } } // end namespace Detail @@ -5401,58 +7938,6 @@ std::string StringMaker<Catch::Detail::Approx>::convert(Catch::Detail::Approx co // end catch_approx.cpp // start catch_assertionhandler.cpp -// start catch_context.h - -#include <memory> - -namespace Catch { - - struct IResultCapture; - struct IRunner; - struct IConfig; - struct IMutableContext; - - using IConfigPtr = std::shared_ptr<IConfig const>; - - struct IContext - { - virtual ~IContext(); - - virtual IResultCapture* getResultCapture() = 0; - virtual IRunner* getRunner() = 0; - virtual IConfigPtr const& getConfig() const = 0; - }; - - struct IMutableContext : IContext - { - virtual ~IMutableContext(); - virtual void setResultCapture( IResultCapture* resultCapture ) = 0; - virtual void setRunner( IRunner* runner ) = 0; - virtual void setConfig( IConfigPtr const& config ) = 0; - - private: - static IMutableContext *currentContext; - friend IMutableContext& getCurrentMutableContext(); - friend void cleanUpContext(); - static void createContext(); - }; - - inline IMutableContext& getCurrentMutableContext() - { - if( !IMutableContext::currentContext ) - IMutableContext::createContext(); - return *IMutableContext::currentContext; - } - - inline IContext& getCurrentContext() - { - return getCurrentMutableContext(); - } - - void cleanUpContext(); -} - -// end catch_context.h // start catch_debugger.h namespace Catch { @@ -5461,7 +7946,24 @@ namespace Catch { #ifdef CATCH_PLATFORM_MAC - #define CATCH_TRAP() __asm__("int $3\n" : : ) /* NOLINT */ + #if defined(__i386__) || defined(__x86_64__) + #define CATCH_TRAP() __asm__("int $3\n" : : ) /* NOLINT */ + #elif defined(__aarch64__) + #define CATCH_TRAP() __asm__(".inst 0xd4200000") + #endif + +#elif defined(CATCH_PLATFORM_IPHONE) + + // use inline assembler + #if defined(__i386__) || defined(__x86_64__) + #define CATCH_TRAP() __asm__("int $3") + #elif defined(__aarch64__) + #define CATCH_TRAP() __asm__(".inst 0xd4200000") + #elif defined(__arm__) && !defined(__thumb__) + #define CATCH_TRAP() __asm__(".inst 0xe7f001f0") + #elif defined(__arm__) && defined(__thumb__) + #define CATCH_TRAP() __asm__(".inst 0xde01") + #endif #elif defined(CATCH_PLATFORM_LINUX) // If we can use inline assembler, do it because this allows us to break @@ -5481,13 +7983,12 @@ namespace Catch { #define CATCH_TRAP() DebugBreak() #endif -#ifdef CATCH_TRAP - #define CATCH_BREAK_INTO_DEBUGGER() if( Catch::isDebuggerActive() ) { CATCH_TRAP(); } -#else - namespace Catch { - inline void doNothing() {} - } - #define CATCH_BREAK_INTO_DEBUGGER() Catch::doNothing() +#ifndef CATCH_BREAK_INTO_DEBUGGER + #ifdef CATCH_TRAP + #define CATCH_BREAK_INTO_DEBUGGER() []{ if( Catch::isDebuggerActive() ) { CATCH_TRAP(); } }() + #else + #define CATCH_BREAK_INTO_DEBUGGER() []{}() + #endif #endif // end catch_debugger.h @@ -5495,86 +7996,58 @@ namespace Catch { // start catch_fatal_condition.h -// start catch_windows_h_proxy.h - - -#if defined(CATCH_PLATFORM_WINDOWS) - -#if !defined(NOMINMAX) && !defined(CATCH_CONFIG_NO_NOMINMAX) -# define CATCH_DEFINED_NOMINMAX -# define NOMINMAX -#endif -#if !defined(WIN32_LEAN_AND_MEAN) && !defined(CATCH_CONFIG_NO_WIN32_LEAN_AND_MEAN) -# define CATCH_DEFINED_WIN32_LEAN_AND_MEAN -# define WIN32_LEAN_AND_MEAN -#endif - -#ifdef __AFXDLL -#include <AfxWin.h> -#else -#include <windows.h> -#endif - -#ifdef CATCH_DEFINED_NOMINMAX -# undef NOMINMAX -#endif -#ifdef CATCH_DEFINED_WIN32_LEAN_AND_MEAN -# undef WIN32_LEAN_AND_MEAN -#endif - -#endif // defined(CATCH_PLATFORM_WINDOWS) - -// end catch_windows_h_proxy.h -#if defined( CATCH_CONFIG_WINDOWS_SEH ) +#include <cassert> namespace Catch { - struct FatalConditionHandler { - - static LONG CALLBACK handleVectoredException(PEXCEPTION_POINTERS ExceptionInfo); + // Wrapper for platform-specific fatal error (signals/SEH) handlers + // + // Tries to be cooperative with other handlers, and not step over + // other handlers. This means that unknown structured exceptions + // are passed on, previous signal handlers are called, and so on. + // + // Can only be instantiated once, and assumes that once a signal + // is caught, the binary will end up terminating. Thus, there + class FatalConditionHandler { + bool m_started = false; + + // Install/disengage implementation for specific platform. + // Should be if-defed to work on current platform, can assume + // engage-disengage 1:1 pairing. + void engage_platform(); + void disengage_platform(); + public: + // Should also have platform-specific implementations as needed FatalConditionHandler(); - static void reset(); ~FatalConditionHandler(); - private: - static bool isSet; - static ULONG guaranteeSize; - static PVOID exceptionHandlerHandle; - }; - -} // namespace Catch - -#elif defined ( CATCH_CONFIG_POSIX_SIGNALS ) - -#include <signal.h> - -namespace Catch { - - struct FatalConditionHandler { - - static bool isSet; - static struct sigaction oldSigActions[]; - static stack_t oldSigStack; - static char altStackMem[]; - - static void handleSignal( int sig ); + void engage() { + assert(!m_started && "Handler cannot be installed twice."); + m_started = true; + engage_platform(); + } - FatalConditionHandler(); - ~FatalConditionHandler(); - static void reset(); + void disengage() { + assert(m_started && "Handler cannot be uninstalled without being installed first"); + m_started = false; + disengage_platform(); + } }; -} // namespace Catch - -#else - -namespace Catch { - struct FatalConditionHandler { - void reset(); + //! Simple RAII guard for (dis)engaging the FatalConditionHandler + class FatalConditionHandlerGuard { + FatalConditionHandler* m_handler; + public: + FatalConditionHandlerGuard(FatalConditionHandler* handler): + m_handler(handler) { + m_handler->engage(); + } + ~FatalConditionHandlerGuard() { + m_handler->disengage(); + } }; -} -#endif +} // end namespace Catch // end catch_fatal_condition.h #include <string> @@ -5634,14 +8107,20 @@ namespace Catch { void sectionEnded( SectionEndInfo const& endInfo ) override; void sectionEndedEarly( SectionEndInfo const& endInfo ) override; - auto acquireGeneratorTracker( SourceLineInfo const& lineInfo ) -> IGeneratorTracker& override; + auto acquireGeneratorTracker( StringRef generatorName, SourceLineInfo const& lineInfo ) -> IGeneratorTracker& override; +#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING) + void benchmarkPreparing( std::string const& name ) override; void benchmarkStarting( BenchmarkInfo const& info ) override; - void benchmarkEnded( BenchmarkStats const& stats ) override; + void benchmarkEnded( BenchmarkStats<> const& stats ) override; + void benchmarkFailed( std::string const& error ) override; +#endif // CATCH_CONFIG_ENABLE_BENCHMARKING void pushScopedMessage( MessageInfo const& message ) override; void popScopedMessage( MessageInfo const& message ) override; + void emplaceUnscopedMessage( MessageBuilder const& builder ) override; + std::string getCurrentTestName() const override; const AssertionResult* getLastResult() const override; @@ -5682,22 +8161,26 @@ namespace Catch { TestRunInfo m_runInfo; IMutableContext& m_context; TestCase const* m_activeTestCase = nullptr; - ITracker* m_testCaseTracker; + ITracker* m_testCaseTracker = nullptr; Option<AssertionResult> m_lastResult; IConfigPtr m_config; Totals m_totals; IStreamingReporterPtr m_reporter; std::vector<MessageInfo> m_messages; + std::vector<ScopedMessage> m_messageScopes; /* Keeps owners of so-called unscoped messages. */ AssertionInfo m_lastAssertionInfo; std::vector<SectionEndInfo> m_unfinishedSections; std::vector<ITracker*> m_activeSections; TrackerContext m_trackerContext; + FatalConditionHandler m_fatalConditionhandler; bool m_lastAssertionPassed = false; bool m_shouldReportUnexpected = true; bool m_includeSuccessfulResults; }; + void seedRng(IConfig const& config); + unsigned int rngSeed(); } // end namespace Catch // end catch_run_context.h @@ -5844,7 +8327,7 @@ namespace Catch { } bool AssertionResult::hasExpression() const { - return m_info.capturedExpression[0] != 0; + return !m_info.capturedExpression.empty(); } bool AssertionResult::hasMessage() const { @@ -5852,16 +8335,22 @@ namespace Catch { } std::string AssertionResult::getExpression() const { - if( isFalseTest( m_info.resultDisposition ) ) - return "!(" + m_info.capturedExpression + ")"; - else - return m_info.capturedExpression; + // Possibly overallocating by 3 characters should be basically free + std::string expr; expr.reserve(m_info.capturedExpression.size() + 3); + if (isFalseTest(m_info.resultDisposition)) { + expr += "!("; + } + expr += m_info.capturedExpression; + if (isFalseTest(m_info.resultDisposition)) { + expr += ')'; + } + return expr; } std::string AssertionResult::getExpressionInMacro() const { std::string expr; - if( m_info.macroName[0] == 0 ) - expr = m_info.capturedExpression; + if( m_info.macroName.empty() ) + expr = static_cast<std::string>(m_info.capturedExpression); else { expr.reserve( m_info.macroName.size() + m_info.capturedExpression.size() + 4 ); expr += m_info.macroName; @@ -5896,32 +8385,6 @@ namespace Catch { } // end namespace Catch // end catch_assertionresult.cpp -// start catch_benchmark.cpp - -namespace Catch { - - auto BenchmarkLooper::getResolution() -> uint64_t { - return getEstimatedClockResolution() * getCurrentContext().getConfig()->benchmarkResolutionMultiple(); - } - - void BenchmarkLooper::reportStart() { - getResultCapture().benchmarkStarting( { m_name } ); - } - auto BenchmarkLooper::needsMoreIterations() -> bool { - auto elapsed = m_timer.getElapsedNanoseconds(); - - // Exponentially increasing iterations until we're confident in our timer resolution - if( elapsed < m_resolution ) { - m_iterationsToRun *= 10; - return true; - } - - getResultCapture().benchmarkEnded( { { m_name }, m_count, elapsed } ); - return false; - } - -} // end namespace Catch -// end catch_benchmark.cpp // start catch_capture_matchers.cpp namespace Catch { @@ -6067,6 +8530,9 @@ public: m_suffix = false; auto width = m_column.m_width - indent(); m_end = m_pos; + if (line()[m_pos] == '\n') { + ++m_end; + } while (m_end < line().size() && line()[m_end] != '\n') ++m_end; @@ -6325,6 +8791,7 @@ inline auto Column::operator + (Column const& other) -> Columns { // ----------- end of #include from clara_textflow.hpp ----------- // ........... back in clara.hpp +#include <cctype> #include <string> #include <memory> #include <set> @@ -6617,7 +9084,7 @@ namespace detail { } inline auto convertInto( std::string const &source, bool &target ) -> ParserResult { std::string srcLC = source; - std::transform( srcLC.begin(), srcLC.end(), srcLC.begin(), []( char c ) { return static_cast<char>( ::tolower(c) ); } ); + std::transform( srcLC.begin(), srcLC.end(), srcLC.begin(), []( unsigned char c ) { return static_cast<char>( std::tolower(c) ); } ); if (srcLC == "y" || srcLC == "1" || srcLC == "true" || srcLC == "yes" || srcLC == "on") target = true; else if (srcLC == "n" || srcLC == "0" || srcLC == "false" || srcLC == "no" || srcLC == "off") @@ -7265,9 +9732,14 @@ namespace Catch { if( !line.empty() && !startsWith( line, '#' ) ) { if( !startsWith( line, '"' ) ) line = '"' + line + '"'; - config.testsOrTags.push_back( line + ',' ); + config.testsOrTags.push_back( line ); + config.testsOrTags.emplace_back( "," ); } } + //Remove comma in the end + if(!config.testsOrTags.empty()) + config.testsOrTags.erase( config.testsOrTags.end()-1 ); + return ParserResult::ok( ParseResultType::Matched ); }; auto const setTestOrder = [&]( std::string const& order ) { @@ -7302,14 +9774,16 @@ namespace Catch { }; auto const setWaitForKeypress = [&]( std::string const& keypress ) { auto keypressLc = toLower( keypress ); - if( keypressLc == "start" ) + if (keypressLc == "never") + config.waitForKeypress = WaitForKeypress::Never; + else if( keypressLc == "start" ) config.waitForKeypress = WaitForKeypress::BeforeStart; else if( keypressLc == "exit" ) config.waitForKeypress = WaitForKeypress::BeforeExit; else if( keypressLc == "both" ) config.waitForKeypress = WaitForKeypress::BeforeStartAndExit; else - return ParserResult::runtimeError( "keypress argument must be one of: start, exit or both. '" + keypress + "' not recognised" ); + return ParserResult::runtimeError( "keypress argument must be one of: never, start, exit or both. '" + keypress + "' not recognised" ); return ParserResult::ok( ParseResultType::Matched ); }; auto const setVerbosity = [&]( std::string const& verbosity ) { @@ -7379,6 +9853,9 @@ namespace Catch { | Opt( [&]( bool flag ) { config.showDurations = flag ? ShowDurations::Always : ShowDurations::Never; }, "yes|no" ) ["-d"]["--durations"] ( "show test durations" ) + | Opt( config.minDuration, "seconds" ) + ["-D"]["--min-duration"] + ( "show test durations for tests taking at least the given number of seconds" ) | Opt( loadTestNamesFromFile, "filename" ) ["-f"]["--input-file"] ( "load test names to run from a file" ) @@ -7409,13 +9886,24 @@ namespace Catch { | Opt( config.libIdentify ) ["--libidentify"] ( "report name and version according to libidentify standard" ) - | Opt( setWaitForKeypress, "start|exit|both" ) + | Opt( setWaitForKeypress, "never|start|exit|both" ) ["--wait-for-keypress"] ( "waits for a keypress before exiting" ) - | Opt( config.benchmarkResolutionMultiple, "multiplier" ) - ["--benchmark-resolution-multiple"] - ( "multiple of clock resolution to run benchmarks" ) - + | Opt( config.benchmarkSamples, "samples" ) + ["--benchmark-samples"] + ( "number of samples to collect (default: 100)" ) + | Opt( config.benchmarkResamples, "resamples" ) + ["--benchmark-resamples"] + ( "number of resamples for the bootstrap (default: 100000)" ) + | Opt( config.benchmarkConfidenceInterval, "confidence interval" ) + ["--benchmark-confidence-interval"] + ( "confidence interval for the bootstrap (between 0 and 1, default: 0.95)" ) + | Opt( config.benchmarkNoAnalysis ) + ["--benchmark-no-analysis"] + ( "perform only measurements; do not perform any analysis" ) + | Opt( config.benchmarkWarmupTime, "benchmarkWarmupTime" ) + ["--benchmark-warmup-time"] + ( "amount of time in milliseconds spent on warming up each test (default: 100)" ) | Arg( config.testsOrTags, "test name|pattern|tags" ) ( "which test or tests to use" ); @@ -7431,9 +9919,6 @@ namespace Catch { namespace Catch { - bool SourceLineInfo::empty() const noexcept { - return file[0] == '\0'; - } bool SourceLineInfo::operator == ( SourceLineInfo const& other ) const noexcept { return line == other.line && (file == other.file || std::strcmp(file, other.file) == 0); } @@ -7469,14 +9954,23 @@ namespace Catch { : m_data( data ), m_stream( openStream() ) { - TestSpecParser parser(ITagAliasRegistry::get()); - if (data.testsOrTags.empty()) { - parser.parse("~[.]"); // All not hidden tests + // We need to trim filter specs to avoid trouble with superfluous + // whitespace (esp. important for bdd macros, as those are manually + // aligned with whitespace). + + for (auto& elem : m_data.testsOrTags) { + elem = trim(elem); } - else { + for (auto& elem : m_data.sectionsToRun) { + elem = trim(elem); + } + + TestSpecParser parser(ITagAliasRegistry::get()); + if (!m_data.testsOrTags.empty()) { m_hasTestFilters = true; - for( auto const& testOrTags : data.testsOrTags ) - parser.parse( testOrTags ); + for (auto const& testOrTags : m_data.testsOrTags) { + parser.parse(testOrTags); + } } m_testSpec = parser.testSpec(); } @@ -7509,15 +10003,21 @@ namespace Catch { bool Config::warnAboutMissingAssertions() const { return !!(m_data.warnings & WarnAbout::NoAssertions); } bool Config::warnAboutNoTests() const { return !!(m_data.warnings & WarnAbout::NoTests); } ShowDurations::OrNot Config::showDurations() const { return m_data.showDurations; } + double Config::minDuration() const { return m_data.minDuration; } RunTests::InWhatOrder Config::runOrder() const { return m_data.runOrder; } unsigned int Config::rngSeed() const { return m_data.rngSeed; } - int Config::benchmarkResolutionMultiple() const { return m_data.benchmarkResolutionMultiple; } UseColour::YesOrNo Config::useColour() const { return m_data.useColour; } bool Config::shouldDebugBreak() const { return m_data.shouldDebugBreak; } int Config::abortAfter() const { return m_data.abortAfter; } bool Config::showInvisibles() const { return m_data.showInvisibles; } Verbosity Config::verbosity() const { return m_data.verbosity; } + bool Config::benchmarkNoAnalysis() const { return m_data.benchmarkNoAnalysis; } + int Config::benchmarkSamples() const { return m_data.benchmarkSamples; } + double Config::benchmarkConfidenceInterval() const { return m_data.benchmarkConfidenceInterval; } + unsigned int Config::benchmarkResamples() const { return m_data.benchmarkResamples; } + std::chrono::milliseconds Config::benchmarkWarmupTime() const { return std::chrono::milliseconds(m_data.benchmarkWarmupTime); } + IStream const* Config::openStream() { return Catch::makeStream(m_data.outputFilename); } @@ -7546,6 +10046,36 @@ namespace Catch { } // end catch_errno_guard.h +// start catch_windows_h_proxy.h + + +#if defined(CATCH_PLATFORM_WINDOWS) + +#if !defined(NOMINMAX) && !defined(CATCH_CONFIG_NO_NOMINMAX) +# define CATCH_DEFINED_NOMINMAX +# define NOMINMAX +#endif +#if !defined(WIN32_LEAN_AND_MEAN) && !defined(CATCH_CONFIG_NO_WIN32_LEAN_AND_MEAN) +# define CATCH_DEFINED_WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +#endif + +#ifdef __AFXDLL +#include <AfxWin.h> +#else +#include <windows.h> +#endif + +#ifdef CATCH_DEFINED_NOMINMAX +# undef NOMINMAX +#endif +#ifdef CATCH_DEFINED_WIN32_LEAN_AND_MEAN +# undef WIN32_LEAN_AND_MEAN +#endif + +#endif // defined(CATCH_PLATFORM_WINDOWS) + +// end catch_windows_h_proxy.h #include <sstream> namespace Catch { @@ -7557,7 +10087,7 @@ namespace Catch { }; struct NoColourImpl : IColourImpl { - void use( Colour::Code ) {} + void use( Colour::Code ) override {} static IColourImpl* instance() { static NoColourImpl s_instance; @@ -7591,7 +10121,7 @@ namespace { originalBackgroundAttributes = csbiInfo.wAttributes & ~( FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_INTENSITY ); } - virtual void use( Colour::Code _colourCode ) override { + void use( Colour::Code _colourCode ) override { switch( _colourCode ) { case Colour::None: return setTextAttribute( originalForegroundAttributes ); case Colour::White: return setTextAttribute( FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE ); @@ -7654,7 +10184,7 @@ namespace { // https://github.com/philsquared/Catch/pull/131 class PosixColourImpl : public IColourImpl { public: - virtual void use( Colour::Code _colourCode ) override { + void use( Colour::Code _colourCode ) override { switch( _colourCode ) { case Colour::None: case Colour::White: return setColour( "[0m" ); @@ -7682,13 +10212,14 @@ namespace { private: void setColour( const char* _escapeCode ) { - Catch::cout() << '\033' << _escapeCode; + getCurrentContext().getConfig()->stream() + << '\033' << _escapeCode; } }; bool useColourOnPlatform() { return -#ifdef CATCH_PLATFORM_MAC +#if defined(CATCH_PLATFORM_MAC) || defined(CATCH_PLATFORM_IPHONE) !isDebuggerActive() && #endif #if !(defined(__DJGPP__) && defined(__STRICT_ANSI__)) @@ -7729,13 +10260,13 @@ namespace Catch { namespace Catch { Colour::Colour( Code _colourCode ) { use( _colourCode ); } - Colour::Colour( Colour&& rhs ) noexcept { - m_moved = rhs.m_moved; - rhs.m_moved = true; + Colour::Colour( Colour&& other ) noexcept { + m_moved = other.m_moved; + other.m_moved = true; } - Colour& Colour::operator=( Colour&& rhs ) noexcept { - m_moved = rhs.m_moved; - rhs.m_moved = true; + Colour& Colour::operator=( Colour&& other ) noexcept { + m_moved = other.m_moved; + other.m_moved = true; return *this; } @@ -7743,7 +10274,13 @@ namespace Catch { void Colour::use( Code _colourCode ) { static IColourImpl* impl = platformColourInstance(); - impl->use( _colourCode ); + // Strictly speaking, this cannot possibly happen. + // However, under some conditions it does happen (see #1626), + // and this change is small enough that we can let practicality + // triumph over purity in this case. + if (impl != nullptr) { + impl->use( _colourCode ); + } } std::ostream& operator << ( std::ostream& os, Colour const& ) { @@ -7764,27 +10301,27 @@ namespace Catch { class Context : public IMutableContext, NonCopyable { public: // IContext - virtual IResultCapture* getResultCapture() override { + IResultCapture* getResultCapture() override { return m_resultCapture; } - virtual IRunner* getRunner() override { + IRunner* getRunner() override { return m_runner; } - virtual IConfigPtr const& getConfig() const override { + IConfigPtr const& getConfig() const override { return m_config; } - virtual ~Context() override; + ~Context() override; public: // IMutableContext - virtual void setResultCapture( IResultCapture* resultCapture ) override { + void setResultCapture( IResultCapture* resultCapture ) override { m_resultCapture = resultCapture; } - virtual void setRunner( IRunner* runner ) override { + void setRunner( IRunner* runner ) override { m_runner = runner; } - virtual void setConfig( IConfigPtr const& config ) override { + void setConfig( IConfigPtr const& config ) override { m_config = config; } @@ -7810,6 +10347,12 @@ namespace Catch { IContext::~IContext() = default; IMutableContext::~IMutableContext() = default; Context::~Context() = default; + + SimplePcg32& rng() { + static SimplePcg32 s_rng; + return s_rng; + } + } // end catch_context.cpp // start catch_debug_console.cpp @@ -7823,7 +10366,16 @@ namespace Catch { } // end catch_debug_console.h -#ifdef CATCH_PLATFORM_WINDOWS +#if defined(CATCH_CONFIG_ANDROID_LOGWRITE) +#include <android/log.h> + + namespace Catch { + void writeToDebugConsole( std::string const& text ) { + __android_log_write( ANDROID_LOG_DEBUG, "Catch", text.c_str() ); + } + } + +#elif defined(CATCH_PLATFORM_WINDOWS) namespace Catch { void writeToDebugConsole( std::string const& text ) { @@ -7844,25 +10396,28 @@ namespace Catch { // end catch_debug_console.cpp // start catch_debugger.cpp -#ifdef CATCH_PLATFORM_MAC +#if defined(CATCH_PLATFORM_MAC) || defined(CATCH_PLATFORM_IPHONE) -# include <assert.h> -# include <stdbool.h> +# include <cassert> # include <sys/types.h> # include <unistd.h> -# include <sys/sysctl.h> # include <cstddef> # include <ostream> -namespace Catch { +#ifdef __apple_build_version__ + // These headers will only compile with AppleClang (XCode) + // For other compilers (Clang, GCC, ... ) we need to exclude them +# include <sys/sysctl.h> +#endif + namespace Catch { + #ifdef __apple_build_version__ // The following function is taken directly from the following technical note: - // http://developer.apple.com/library/mac/#qa/qa2004/qa1361.html + // https://developer.apple.com/library/archive/qa/qa1361/_index.html // Returns true if the current process is being debugged (either // running under the debugger or has a debugger attached post facto). bool isDebuggerActive(){ - int mib[4]; struct kinfo_proc info; std::size_t size; @@ -7892,6 +10447,12 @@ namespace Catch { return ( (info.kp_proc.p_flag & P_TRACED) != 0 ); } + #else + bool isDebuggerActive() { + // We need to find another way to determine this for non-appleclang compilers on macOS + return false; + } + #endif } // namespace Catch #elif defined(CATCH_PLATFORM_LINUX) @@ -7962,6 +10523,8 @@ namespace Catch { // end catch_decomposer.cpp // start catch_enforce.cpp +#include <stdexcept> + namespace Catch { #if defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) && !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS_CUSTOM_HANDLER) [[noreturn]] @@ -7971,8 +10534,116 @@ namespace Catch { std::terminate(); } #endif + + [[noreturn]] + void throw_logic_error(std::string const& msg) { + throw_exception(std::logic_error(msg)); + } + + [[noreturn]] + void throw_domain_error(std::string const& msg) { + throw_exception(std::domain_error(msg)); + } + + [[noreturn]] + void throw_runtime_error(std::string const& msg) { + throw_exception(std::runtime_error(msg)); + } + } // namespace Catch; // end catch_enforce.cpp +// start catch_enum_values_registry.cpp +// start catch_enum_values_registry.h + +#include <vector> +#include <memory> + +namespace Catch { + + namespace Detail { + + std::unique_ptr<EnumInfo> makeEnumInfo( StringRef enumName, StringRef allValueNames, std::vector<int> const& values ); + + class EnumValuesRegistry : public IMutableEnumValuesRegistry { + + std::vector<std::unique_ptr<EnumInfo>> m_enumInfos; + + EnumInfo const& registerEnum( StringRef enumName, StringRef allEnums, std::vector<int> const& values) override; + }; + + std::vector<StringRef> parseEnums( StringRef enums ); + + } // Detail + +} // Catch + +// end catch_enum_values_registry.h + +#include <map> +#include <cassert> + +namespace Catch { + + IMutableEnumValuesRegistry::~IMutableEnumValuesRegistry() {} + + namespace Detail { + + namespace { + // Extracts the actual name part of an enum instance + // In other words, it returns the Blue part of Bikeshed::Colour::Blue + StringRef extractInstanceName(StringRef enumInstance) { + // Find last occurrence of ":" + size_t name_start = enumInstance.size(); + while (name_start > 0 && enumInstance[name_start - 1] != ':') { + --name_start; + } + return enumInstance.substr(name_start, enumInstance.size() - name_start); + } + } + + std::vector<StringRef> parseEnums( StringRef enums ) { + auto enumValues = splitStringRef( enums, ',' ); + std::vector<StringRef> parsed; + parsed.reserve( enumValues.size() ); + for( auto const& enumValue : enumValues ) { + parsed.push_back(trim(extractInstanceName(enumValue))); + } + return parsed; + } + + EnumInfo::~EnumInfo() {} + + StringRef EnumInfo::lookup( int value ) const { + for( auto const& valueToName : m_values ) { + if( valueToName.first == value ) + return valueToName.second; + } + return "{** unexpected enum value **}"_sr; + } + + std::unique_ptr<EnumInfo> makeEnumInfo( StringRef enumName, StringRef allValueNames, std::vector<int> const& values ) { + std::unique_ptr<EnumInfo> enumInfo( new EnumInfo ); + enumInfo->m_name = enumName; + enumInfo->m_values.reserve( values.size() ); + + const auto valueNames = Catch::Detail::parseEnums( allValueNames ); + assert( valueNames.size() == values.size() ); + std::size_t i = 0; + for( auto value : values ) + enumInfo->m_values.emplace_back(value, valueNames[i++]); + + return enumInfo; + } + + EnumInfo const& EnumValuesRegistry::registerEnum( StringRef enumName, StringRef allValueNames, std::vector<int> const& values ) { + m_enumInfos.push_back(makeEnumInfo(enumName, allValueNames, values)); + return *m_enumInfos.back(); + } + + } // Detail +} // Catch + +// end catch_enum_values_registry.cpp // start catch_errno_guard.cpp #include <cerrno> @@ -7996,7 +10667,7 @@ namespace Catch { public: ~ExceptionTranslatorRegistry(); virtual void registerTranslator( const IExceptionTranslator* translator ); - virtual std::string translateActiveException() const override; + std::string translateActiveException() const override; std::string tryTranslators() const; private: @@ -8061,54 +10732,82 @@ namespace Catch { } } + std::string ExceptionTranslatorRegistry::tryTranslators() const { + if (m_translators.empty()) { + std::rethrow_exception(std::current_exception()); + } else { + return m_translators[0]->translate(m_translators.begin() + 1, m_translators.end()); + } + } + #else // ^^ Exceptions are enabled // Exceptions are disabled vv std::string ExceptionTranslatorRegistry::translateActiveException() const { CATCH_INTERNAL_ERROR("Attempted to translate active exception under CATCH_CONFIG_DISABLE_EXCEPTIONS!"); } -#endif std::string ExceptionTranslatorRegistry::tryTranslators() const { - if( m_translators.empty() ) - std::rethrow_exception(std::current_exception()); - else - return m_translators[0]->translate( m_translators.begin()+1, m_translators.end() ); + CATCH_INTERNAL_ERROR("Attempted to use exception translators under CATCH_CONFIG_DISABLE_EXCEPTIONS!"); } +#endif + } // end catch_exception_translator_registry.cpp // start catch_fatal_condition.cpp -#if defined(__GNUC__) -# pragma GCC diagnostic push -# pragma GCC diagnostic ignored "-Wmissing-field-initializers" -#endif +#include <algorithm> + +#if !defined( CATCH_CONFIG_WINDOWS_SEH ) && !defined( CATCH_CONFIG_POSIX_SIGNALS ) + +namespace Catch { + + // If neither SEH nor signal handling is required, the handler impls + // do not have to do anything, and can be empty. + void FatalConditionHandler::engage_platform() {} + void FatalConditionHandler::disengage_platform() {} + FatalConditionHandler::FatalConditionHandler() = default; + FatalConditionHandler::~FatalConditionHandler() = default; + +} // end namespace Catch + +#endif // !CATCH_CONFIG_WINDOWS_SEH && !CATCH_CONFIG_POSIX_SIGNALS + +#if defined( CATCH_CONFIG_WINDOWS_SEH ) && defined( CATCH_CONFIG_POSIX_SIGNALS ) +#error "Inconsistent configuration: Windows' SEH handling and POSIX signals cannot be enabled at the same time" +#endif // CATCH_CONFIG_WINDOWS_SEH && CATCH_CONFIG_POSIX_SIGNALS #if defined( CATCH_CONFIG_WINDOWS_SEH ) || defined( CATCH_CONFIG_POSIX_SIGNALS ) namespace { - // Report the error condition + //! Signals fatal error message to the run context void reportFatal( char const * const message ) { Catch::getCurrentContext().getResultCapture()->handleFatalErrorCondition( message ); } -} -#endif // signals/SEH handling + //! Minimal size Catch2 needs for its own fatal error handling. + //! Picked anecdotally, so it might not be sufficient on all + //! platforms, and for all configurations. + constexpr std::size_t minStackSizeForErrors = 32 * 1024; +} // end unnamed namespace + +#endif // CATCH_CONFIG_WINDOWS_SEH || CATCH_CONFIG_POSIX_SIGNALS #if defined( CATCH_CONFIG_WINDOWS_SEH ) namespace Catch { + struct SignalDefs { DWORD id; const char* name; }; // There is no 1-1 mapping between signals and windows exceptions. // Windows can easily distinguish between SO and SigSegV, // but SigInt, SigTerm, etc are handled differently. static SignalDefs signalDefs[] = { - { EXCEPTION_ILLEGAL_INSTRUCTION, "SIGILL - Illegal instruction signal" }, - { EXCEPTION_STACK_OVERFLOW, "SIGSEGV - Stack overflow" }, - { EXCEPTION_ACCESS_VIOLATION, "SIGSEGV - Segmentation violation signal" }, - { EXCEPTION_INT_DIVIDE_BY_ZERO, "Divide by zero error" }, + { static_cast<DWORD>(EXCEPTION_ILLEGAL_INSTRUCTION), "SIGILL - Illegal instruction signal" }, + { static_cast<DWORD>(EXCEPTION_STACK_OVERFLOW), "SIGSEGV - Stack overflow" }, + { static_cast<DWORD>(EXCEPTION_ACCESS_VIOLATION), "SIGSEGV - Segmentation violation signal" }, + { static_cast<DWORD>(EXCEPTION_INT_DIVIDE_BY_ZERO), "Divide by zero error" }, }; - LONG CALLBACK FatalConditionHandler::handleVectoredException(PEXCEPTION_POINTERS ExceptionInfo) { + static LONG CALLBACK handleVectoredException(PEXCEPTION_POINTERS ExceptionInfo) { for (auto const& def : signalDefs) { if (ExceptionInfo->ExceptionRecord->ExceptionCode == def.id) { reportFatal(def.name); @@ -8119,38 +10818,50 @@ namespace Catch { return EXCEPTION_CONTINUE_SEARCH; } + // Since we do not support multiple instantiations, we put these + // into global variables and rely on cleaning them up in outlined + // constructors/destructors + static PVOID exceptionHandlerHandle = nullptr; + + // For MSVC, we reserve part of the stack memory for handling + // memory overflow structured exception. FatalConditionHandler::FatalConditionHandler() { - isSet = true; - // 32k seems enough for Catch to handle stack overflow, - // but the value was found experimentally, so there is no strong guarantee - guaranteeSize = 32 * 1024; - exceptionHandlerHandle = nullptr; + ULONG guaranteeSize = static_cast<ULONG>(minStackSizeForErrors); + if (!SetThreadStackGuarantee(&guaranteeSize)) { + // We do not want to fully error out, because needing + // the stack reserve should be rare enough anyway. + Catch::cerr() + << "Failed to reserve piece of stack." + << " Stack overflows will not be reported successfully."; + } + } + + // We do not attempt to unset the stack guarantee, because + // Windows does not support lowering the stack size guarantee. + FatalConditionHandler::~FatalConditionHandler() = default; + + void FatalConditionHandler::engage_platform() { // Register as first handler in current chain exceptionHandlerHandle = AddVectoredExceptionHandler(1, handleVectoredException); - // Pass in guarantee size to be filled - SetThreadStackGuarantee(&guaranteeSize); + if (!exceptionHandlerHandle) { + CATCH_RUNTIME_ERROR("Could not register vectored exception handler"); + } } - void FatalConditionHandler::reset() { - if (isSet) { - RemoveVectoredExceptionHandler(exceptionHandlerHandle); - SetThreadStackGuarantee(&guaranteeSize); - exceptionHandlerHandle = nullptr; - isSet = false; + void FatalConditionHandler::disengage_platform() { + if (!RemoveVectoredExceptionHandler(exceptionHandlerHandle)) { + CATCH_RUNTIME_ERROR("Could not unregister vectored exception handler"); } + exceptionHandlerHandle = nullptr; } - FatalConditionHandler::~FatalConditionHandler() { - reset(); - } +} // end namespace Catch -bool FatalConditionHandler::isSet = false; -ULONG FatalConditionHandler::guaranteeSize = 0; -PVOID FatalConditionHandler::exceptionHandlerHandle = nullptr; +#endif // CATCH_CONFIG_WINDOWS_SEH -} // namespace Catch +#if defined( CATCH_CONFIG_POSIX_SIGNALS ) -#elif defined( CATCH_CONFIG_POSIX_SIGNALS ) +#include <signal.h> namespace Catch { @@ -8159,10 +10870,6 @@ namespace Catch { const char* name; }; - // 32kb for the alternate stack seems to be sufficient. However, this value - // is experimentally determined, so that's not guaranteed. - constexpr static std::size_t sigStackSize = 32768 >= MINSIGSTKSZ ? 32768 : MINSIGSTKSZ; - static SignalDefs signalDefs[] = { { SIGINT, "SIGINT - Terminal interrupt signal" }, { SIGILL, "SIGILL - Illegal instruction signal" }, @@ -8172,7 +10879,32 @@ namespace Catch { { SIGABRT, "SIGABRT - Abort (abnormal termination) signal" } }; - void FatalConditionHandler::handleSignal( int sig ) { +// Older GCCs trigger -Wmissing-field-initializers for T foo = {} +// which is zero initialization, but not explicit. We want to avoid +// that. +#if defined(__GNUC__) +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wmissing-field-initializers" +#endif + + static char* altStackMem = nullptr; + static std::size_t altStackSize = 0; + static stack_t oldSigStack{}; + static struct sigaction oldSigActions[sizeof(signalDefs) / sizeof(SignalDefs)]{}; + + static void restorePreviousSignalHandlers() { + // We set signal handlers back to the previous ones. Hopefully + // nobody overwrote them in the meantime, and doesn't expect + // their signal handlers to live past ours given that they + // installed them after ours.. + for (std::size_t i = 0; i < sizeof(signalDefs) / sizeof(SignalDefs); ++i) { + sigaction(signalDefs[i].id, &oldSigActions[i], nullptr); + } + // Return the old stack + sigaltstack(&oldSigStack, nullptr); + } + + static void handleSignal( int sig ) { char const * name = "<unknown signal>"; for (auto const& def : signalDefs) { if (sig == def.id) { @@ -8180,16 +10912,33 @@ namespace Catch { break; } } - reset(); - reportFatal(name); + // We need to restore previous signal handlers and let them do + // their thing, so that the users can have the debugger break + // when a signal is raised, and so on. + restorePreviousSignalHandlers(); + reportFatal( name ); raise( sig ); } FatalConditionHandler::FatalConditionHandler() { - isSet = true; + assert(!altStackMem && "Cannot initialize POSIX signal handler when one already exists"); + if (altStackSize == 0) { + altStackSize = std::max(static_cast<size_t>(SIGSTKSZ), minStackSizeForErrors); + } + altStackMem = new char[altStackSize](); + } + + FatalConditionHandler::~FatalConditionHandler() { + delete[] altStackMem; + // We signal that another instance can be constructed by zeroing + // out the pointer. + altStackMem = nullptr; + } + + void FatalConditionHandler::engage_platform() { stack_t sigStack; sigStack.ss_sp = altStackMem; - sigStack.ss_size = sigStackSize; + sigStack.ss_size = altStackSize; sigStack.ss_flags = 0; sigaltstack(&sigStack, &oldSigStack); struct sigaction sa = { }; @@ -8201,59 +10950,20 @@ namespace Catch { } } - FatalConditionHandler::~FatalConditionHandler() { - reset(); - } - - void FatalConditionHandler::reset() { - if( isSet ) { - // Set signals back to previous values -- hopefully nobody overwrote them in the meantime - for( std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i ) { - sigaction(signalDefs[i].id, &oldSigActions[i], nullptr); - } - // Return the old stack - sigaltstack(&oldSigStack, nullptr); - isSet = false; - } - } - - bool FatalConditionHandler::isSet = false; - struct sigaction FatalConditionHandler::oldSigActions[sizeof(signalDefs)/sizeof(SignalDefs)] = {}; - stack_t FatalConditionHandler::oldSigStack = {}; - char FatalConditionHandler::altStackMem[sigStackSize] = {}; - -} // namespace Catch - -#else - -namespace Catch { - void FatalConditionHandler::reset() {} -} - -#endif // signals/SEH handling - #if defined(__GNUC__) # pragma GCC diagnostic pop #endif -// end catch_fatal_condition.cpp -// start catch_generators.cpp - -// start catch_random_number_generator.h - -#include <algorithm> -#include <random> - -namespace Catch { - struct IConfig; + void FatalConditionHandler::disengage_platform() { + restorePreviousSignalHandlers(); + } - std::mt19937& rng(); - void seedRng( IConfig const& config ); - unsigned int rngSeed(); +} // end namespace Catch -} +#endif // CATCH_CONFIG_POSIX_SIGNALS +// end catch_fatal_condition.cpp +// start catch_generators.cpp -// end catch_random_number_generator.h #include <limits> #include <set> @@ -8261,34 +10971,16 @@ namespace Catch { IGeneratorTracker::~IGeneratorTracker() {} -namespace Generators { - - GeneratorBase::~GeneratorBase() {} - - std::vector<size_t> randomiseIndices( size_t selectionSize, size_t sourceSize ) { +const char* GeneratorException::what() const noexcept { + return m_msg; +} - assert( selectionSize <= sourceSize ); - std::vector<size_t> indices; - indices.reserve( selectionSize ); - std::uniform_int_distribution<size_t> uid( 0, sourceSize-1 ); +namespace Generators { - std::set<size_t> seen; - // !TBD: improve this algorithm - while( indices.size() < selectionSize ) { - auto index = uid( rng() ); - if( seen.insert( index ).second ) - indices.push_back( index ); - } - return indices; - } + GeneratorUntypedBase::~GeneratorUntypedBase() {} - auto acquireGeneratorTracker( SourceLineInfo const& lineInfo ) -> IGeneratorTracker& { - return getResultCapture().acquireGeneratorTracker( lineInfo ); - } - - template<> - auto all<int>() -> Generator<int> { - return range( std::numeric_limits<int>::min(), std::numeric_limits<int>::max() ); + auto acquireGeneratorTracker( StringRef generatorName, SourceLineInfo const& lineInfo ) -> IGeneratorTracker& { + return getResultCapture().acquireGeneratorTracker( generatorName, lineInfo ); } } // namespace Generators @@ -8344,10 +11036,16 @@ namespace Catch { void noMatchingTestCases( std::string const& spec ) override; + void reportInvalidArguments(std::string const&arg) override; + static std::set<Verbosity> getSupportedVerbosities(); +#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING) + void benchmarkPreparing(std::string const& name) override; void benchmarkStarting( BenchmarkInfo const& benchmarkInfo ) override; - void benchmarkEnded( BenchmarkStats const& benchmarkStats ) override; + void benchmarkEnded( BenchmarkStats<> const& benchmarkStats ) override; + void benchmarkFailed(std::string const&) override; +#endif // CATCH_CONFIG_ENABLE_BENCHMARKING void testRunStarting( TestRunInfo const& testRunInfo ) override; void testGroupStarting( GroupInfo const& groupInfo ) override; @@ -8538,7 +11236,7 @@ namespace Catch { std::size_t listReporters(); - Option<std::size_t> list( Config const& config ); + Option<std::size_t> list( std::shared_ptr<Config> const& config ); } // end namespace Catch @@ -8557,7 +11255,7 @@ namespace Catch { namespace Catch { std::size_t listTests( Config const& config ) { - TestSpec testSpec = config.testSpec(); + TestSpec const& testSpec = config.testSpec(); if( config.hasTestFilters() ) Catch::cout() << "Matching test cases:\n"; else { @@ -8591,7 +11289,7 @@ namespace Catch { } std::size_t listTestsNamesOnly( Config const& config ) { - TestSpec testSpec = config.testSpec(); + TestSpec const& testSpec = config.testSpec(); std::size_t matchedTests = 0; std::vector<TestCase> matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config ); for( auto const& testCaseInfo : matchedTestCases ) { @@ -8613,14 +11311,23 @@ namespace Catch { } std::string TagInfo::all() const { - std::string out; - for( auto const& spelling : spellings ) - out += "[" + spelling + "]"; + size_t size = 0; + for (auto const& spelling : spellings) { + // Add 2 for the brackes + size += spelling.size() + 2; + } + + std::string out; out.reserve(size); + for (auto const& spelling : spellings) { + out += '['; + out += spelling; + out += ']'; + } return out; } std::size_t listTags( Config const& config ) { - TestSpec testSpec = config.testSpec(); + TestSpec const& testSpec = config.testSpec(); if( config.hasTestFilters() ) Catch::cout() << "Tags for matching test cases:\n"; else { @@ -8676,15 +11383,16 @@ namespace Catch { return factories.size(); } - Option<std::size_t> list( Config const& config ) { + Option<std::size_t> list( std::shared_ptr<Config> const& config ) { Option<std::size_t> listedCount; - if( config.listTests() ) - listedCount = listedCount.valueOr(0) + listTests( config ); - if( config.listTestNamesOnly() ) - listedCount = listedCount.valueOr(0) + listTestsNamesOnly( config ); - if( config.listTags() ) - listedCount = listedCount.valueOr(0) + listTags( config ); - if( config.listReporters() ) + getCurrentMutableContext().setConfig( config ); + if( config->listTests() ) + listedCount = listedCount.valueOr(0) + listTests( *config ); + if( config->listTestNamesOnly() ) + listedCount = listedCount.valueOr(0) + listTestsNamesOnly( *config ); + if( config->listTags() ) + listedCount = listedCount.valueOr(0) + listTags( *config ); + if( config->listReporters() ) listedCount = listedCount.valueOr(0) + listReporters(); return listedCount; } @@ -8713,6 +11421,29 @@ using Matchers::Impl::MatcherBase; } // namespace Catch // end catch_matchers.cpp +// start catch_matchers_exception.cpp + +namespace Catch { +namespace Matchers { +namespace Exception { + +bool ExceptionMessageMatcher::match(std::exception const& ex) const { + return ex.what() == m_message; +} + +std::string ExceptionMessageMatcher::describe() const { + return "exception message matches \"" + m_message + "\""; +} + +} +Exception::ExceptionMessageMatcher Message(std::string const& message) { + return Exception::ExceptionMessageMatcher(message); +} + +// namespace Exception +} // namespace Matchers +} // namespace Catch +// end catch_matchers_exception.cpp // start catch_matchers_floating.cpp // start catch_polyfills.hpp @@ -8741,74 +11472,101 @@ namespace Catch { } // end namespace Catch // end catch_to_string.hpp +#include <algorithm> +#include <cmath> #include <cstdlib> #include <cstdint> #include <cstring> +#include <sstream> +#include <type_traits> +#include <iomanip> +#include <limits> namespace Catch { -namespace Matchers { -namespace Floating { -enum class FloatingPointKind : uint8_t { - Float, - Double -}; -} -} -} - namespace { -template <typename T> -struct Converter; - -template <> -struct Converter<float> { - static_assert(sizeof(float) == sizeof(int32_t), "Important ULP matcher assumption violated"); - Converter(float f) { + int32_t convert(float f) { + static_assert(sizeof(float) == sizeof(int32_t), "Important ULP matcher assumption violated"); + int32_t i; std::memcpy(&i, &f, sizeof(f)); + return i; } - int32_t i; -}; -template <> -struct Converter<double> { - static_assert(sizeof(double) == sizeof(int64_t), "Important ULP matcher assumption violated"); - Converter(double d) { + int64_t convert(double d) { + static_assert(sizeof(double) == sizeof(int64_t), "Important ULP matcher assumption violated"); + int64_t i; std::memcpy(&i, &d, sizeof(d)); + return i; } - int64_t i; -}; -template <typename T> -auto convert(T t) -> Converter<T> { - return Converter<T>(t); -} + template <typename FP> + bool almostEqualUlps(FP lhs, FP rhs, uint64_t maxUlpDiff) { + // Comparison with NaN should always be false. + // This way we can rule it out before getting into the ugly details + if (Catch::isnan(lhs) || Catch::isnan(rhs)) { + return false; + } -template <typename FP> -bool almostEqualUlps(FP lhs, FP rhs, int maxUlpDiff) { - // Comparison with NaN should always be false. - // This way we can rule it out before getting into the ugly details - if (Catch::isnan(lhs) || Catch::isnan(rhs)) { - return false; + auto lc = convert(lhs); + auto rc = convert(rhs); + + if ((lc < 0) != (rc < 0)) { + // Potentially we can have +0 and -0 + return lhs == rhs; + } + + // static cast as a workaround for IBM XLC + auto ulpDiff = std::abs(static_cast<FP>(lc - rc)); + return static_cast<uint64_t>(ulpDiff) <= maxUlpDiff; } - auto lc = convert(lhs); - auto rc = convert(rhs); +#if defined(CATCH_CONFIG_GLOBAL_NEXTAFTER) - if ((lc.i < 0) != (rc.i < 0)) { - // Potentially we can have +0 and -0 - return lhs == rhs; + float nextafter(float x, float y) { + return ::nextafterf(x, y); } - auto ulpDiff = std::abs(lc.i - rc.i); - return ulpDiff <= maxUlpDiff; + double nextafter(double x, double y) { + return ::nextafter(x, y); + } + +#endif // ^^^ CATCH_CONFIG_GLOBAL_NEXTAFTER ^^^ + +template <typename FP> +FP step(FP start, FP direction, uint64_t steps) { + for (uint64_t i = 0; i < steps; ++i) { +#if defined(CATCH_CONFIG_GLOBAL_NEXTAFTER) + start = Catch::nextafter(start, direction); +#else + start = std::nextafter(start, direction); +#endif + } + return start; } +// Performs equivalent check of std::fabs(lhs - rhs) <= margin +// But without the subtraction to allow for INFINITY in comparison +bool marginComparison(double lhs, double rhs, double margin) { + return (lhs + margin >= rhs) && (rhs + margin >= lhs); } -namespace Catch { +template <typename FloatingPoint> +void write(std::ostream& out, FloatingPoint num) { + out << std::scientific + << std::setprecision(std::numeric_limits<FloatingPoint>::max_digits10 - 1) + << num; +} + +} // end anonymous namespace + namespace Matchers { namespace Floating { + + enum class FloatingPointKind : uint8_t { + Float, + Double + }; + WithinAbsMatcher::WithinAbsMatcher(double target, double margin) :m_target{ target }, m_margin{ margin } { CATCH_ENFORCE(margin >= 0, "Invalid margin: " << margin << '.' @@ -8825,10 +11583,11 @@ namespace Floating { return "is within " + ::Catch::Detail::stringify(m_margin) + " of " + ::Catch::Detail::stringify(m_target); } - WithinUlpsMatcher::WithinUlpsMatcher(double target, int ulps, FloatingPointKind baseType) + WithinUlpsMatcher::WithinUlpsMatcher(double target, uint64_t ulps, FloatingPointKind baseType) :m_target{ target }, m_ulps{ ulps }, m_type{ baseType } { - CATCH_ENFORCE(ulps >= 0, "Invalid ULP setting: " << ulps << '.' - << " ULPs have to be non-negative."); + CATCH_ENFORCE(m_type == FloatingPointKind::Double + || m_ulps < (std::numeric_limits<uint32_t>::max)(), + "Provided ULP is impossibly large for a float comparison."); } #if defined(__clang__) @@ -8853,16 +11612,59 @@ namespace Floating { #endif std::string WithinUlpsMatcher::describe() const { - return "is within " + Catch::to_string(m_ulps) + " ULPs of " + ::Catch::Detail::stringify(m_target) + ((m_type == FloatingPointKind::Float)? "f" : ""); + std::stringstream ret; + + ret << "is within " << m_ulps << " ULPs of "; + + if (m_type == FloatingPointKind::Float) { + write(ret, static_cast<float>(m_target)); + ret << 'f'; + } else { + write(ret, m_target); + } + + ret << " (["; + if (m_type == FloatingPointKind::Double) { + write(ret, step(m_target, static_cast<double>(-INFINITY), m_ulps)); + ret << ", "; + write(ret, step(m_target, static_cast<double>( INFINITY), m_ulps)); + } else { + // We have to cast INFINITY to float because of MinGW, see #1782 + write(ret, step(static_cast<float>(m_target), static_cast<float>(-INFINITY), m_ulps)); + ret << ", "; + write(ret, step(static_cast<float>(m_target), static_cast<float>( INFINITY), m_ulps)); + } + ret << "])"; + + return ret.str(); + } + + WithinRelMatcher::WithinRelMatcher(double target, double epsilon): + m_target(target), + m_epsilon(epsilon){ + CATCH_ENFORCE(m_epsilon >= 0., "Relative comparison with epsilon < 0 does not make sense."); + CATCH_ENFORCE(m_epsilon < 1., "Relative comparison with epsilon >= 1 does not make sense."); + } + + bool WithinRelMatcher::match(double const& matchee) const { + const auto relMargin = m_epsilon * (std::max)(std::fabs(matchee), std::fabs(m_target)); + return marginComparison(matchee, m_target, + std::isinf(relMargin)? 0 : relMargin); + } + + std::string WithinRelMatcher::describe() const { + Catch::ReusableStringStream sstr; + sstr << "and " << m_target << " are within " << m_epsilon * 100. << "% of each other"; + return sstr.str(); } }// namespace Floating -Floating::WithinUlpsMatcher WithinULP(double target, int maxUlpDiff) { +Floating::WithinUlpsMatcher WithinULP(double target, uint64_t maxUlpDiff) { return Floating::WithinUlpsMatcher(target, maxUlpDiff, Floating::FloatingPointKind::Double); } -Floating::WithinUlpsMatcher WithinULP(float target, int maxUlpDiff) { +Floating::WithinUlpsMatcher WithinULP(float target, uint64_t maxUlpDiff) { return Floating::WithinUlpsMatcher(target, maxUlpDiff, Floating::FloatingPointKind::Float); } @@ -8870,9 +11672,24 @@ Floating::WithinAbsMatcher WithinAbs(double target, double margin) { return Floating::WithinAbsMatcher(target, margin); } +Floating::WithinRelMatcher WithinRel(double target, double eps) { + return Floating::WithinRelMatcher(target, eps); +} + +Floating::WithinRelMatcher WithinRel(double target) { + return Floating::WithinRelMatcher(target, std::numeric_limits<double>::epsilon() * 100); +} + +Floating::WithinRelMatcher WithinRel(float target, float eps) { + return Floating::WithinRelMatcher(target, eps); +} + +Floating::WithinRelMatcher WithinRel(float target) { + return Floating::WithinRelMatcher(target, std::numeric_limits<float>::epsilon() * 100); +} + } // namespace Matchers } // namespace Catch - // end catch_matchers_floating.cpp // start catch_matchers_generic.cpp @@ -9030,28 +11847,43 @@ namespace Catch { //////////////////////////////////////////////////////////////////////////// ScopedMessage::ScopedMessage( MessageBuilder const& builder ) - : m_info( builder.m_info ) + : m_info( builder.m_info ), m_moved() { m_info.message = builder.m_stream.str(); getResultCapture().pushScopedMessage( m_info ); } + ScopedMessage::ScopedMessage( ScopedMessage&& old ) + : m_info( old.m_info ), m_moved() + { + old.m_moved = true; + } + ScopedMessage::~ScopedMessage() { - if ( !uncaught_exceptions() ){ + if ( !uncaught_exceptions() && !m_moved ){ getResultCapture().popScopedMessage(m_info); } } Capturer::Capturer( StringRef macroName, SourceLineInfo const& lineInfo, ResultWas::OfType resultType, StringRef names ) { auto trimmed = [&] (size_t start, size_t end) { - while (names[start] == ',' || isspace(names[start])) { + while (names[start] == ',' || isspace(static_cast<unsigned char>(names[start]))) { ++start; } - while (names[end] == ',' || isspace(names[end])) { + while (names[end] == ',' || isspace(static_cast<unsigned char>(names[end]))) { --end; } return names.substr(start, end - start + 1); }; + auto skipq = [&] (size_t start, char quote) { + for (auto i = start + 1; i < names.size() ; ++i) { + if (names[i] == quote) + return i; + if (names[i] == '\\') + ++i; + } + CATCH_INTERNAL_ERROR("CAPTURE parsing encountered unmatched quote"); + }; size_t start = 0; std::stack<char> openings; @@ -9072,18 +11904,22 @@ namespace Catch { // case '>': openings.pop(); break; + case '"': + case '\'': + pos = skipq(pos, c); + break; case ',': - if (start != pos && openings.size() == 0) { + if (start != pos && openings.empty()) { m_messages.emplace_back(macroName, lineInfo, resultType); - m_messages.back().message = trimmed(start, pos); + m_messages.back().message = static_cast<std::string>(trimmed(start, pos)); m_messages.back().message += " := "; start = pos; } } } - assert(openings.size() == 0 && "Mismatched openings"); + assert(openings.empty() && "Mismatched openings"); m_messages.emplace_back(macroName, lineInfo, resultType); - m_messages.back().message = trimmed(start, names.size() - 1); + m_messages.back().message = static_cast<std::string>(trimmed(start, names.size() - 1)); m_messages.back().message += " := "; } Capturer::~Capturer() { @@ -9145,6 +11981,22 @@ namespace Catch { auto str() const -> std::string; }; + class RedirectedStreams { + public: + RedirectedStreams(RedirectedStreams const&) = delete; + RedirectedStreams& operator=(RedirectedStreams const&) = delete; + RedirectedStreams(RedirectedStreams&&) = delete; + RedirectedStreams& operator=(RedirectedStreams&&) = delete; + + RedirectedStreams(std::string& redirectedCout, std::string& redirectedCerr); + ~RedirectedStreams(); + private: + std::string& m_redirectedCout; + std::string& m_redirectedCerr; + RedirectedStdOut m_redirectedStdOut; + RedirectedStdErr m_redirectedStdErr; + }; + #if defined(CATCH_CONFIG_NEW_CAPTURE) // Windows's implementation of std::tmpfile is terrible (it tries @@ -9236,6 +12088,16 @@ namespace Catch { {} auto RedirectedStdErr::str() const -> std::string { return m_rss.str(); } + RedirectedStreams::RedirectedStreams(std::string& redirectedCout, std::string& redirectedCerr) + : m_redirectedCout(redirectedCout), + m_redirectedCerr(redirectedCerr) + {} + + RedirectedStreams::~RedirectedStreams() { + m_redirectedCout += m_redirectedStdOut.str(); + m_redirectedCerr += m_redirectedStdErr.str(); + } + #if defined(CATCH_CONFIG_NEW_CAPTURE) #if defined(_MSC_VER) @@ -9243,12 +12105,12 @@ namespace Catch { if (tmpnam_s(m_buffer)) { CATCH_RUNTIME_ERROR("Could not get a temp filename"); } - if (fopen_s(&m_file, m_buffer, "w")) { + if (fopen_s(&m_file, m_buffer, "w+")) { char buffer[100]; if (strerror_s(buffer, errno)) { CATCH_RUNTIME_ERROR("Could not translate errno to a string"); } - CATCH_RUNTIME_ERROR("Coul dnot open the temp file: '" << m_buffer << "' because: " << buffer); + CATCH_RUNTIME_ERROR("Could not open the temp file: '" << m_buffer << "' because: " << buffer); } } #else @@ -9351,20 +12213,61 @@ namespace Catch { namespace Catch { - std::mt19937& rng() { - static std::mt19937 s_rng; - return s_rng; +namespace { + +#if defined(_MSC_VER) +#pragma warning(push) +#pragma warning(disable:4146) // we negate uint32 during the rotate +#endif + // Safe rotr implementation thanks to John Regehr + uint32_t rotate_right(uint32_t val, uint32_t count) { + const uint32_t mask = 31; + count &= mask; + return (val >> count) | (val << (-count & mask)); + } + +#if defined(_MSC_VER) +#pragma warning(pop) +#endif + +} + + SimplePcg32::SimplePcg32(result_type seed_) { + seed(seed_); + } + + void SimplePcg32::seed(result_type seed_) { + m_state = 0; + (*this)(); + m_state += seed_; + (*this)(); } - void seedRng( IConfig const& config ) { - if( config.rngSeed() != 0 ) { - std::srand( config.rngSeed() ); - rng().seed( config.rngSeed() ); + void SimplePcg32::discard(uint64_t skip) { + // We could implement this to run in O(log n) steps, but this + // should suffice for our use case. + for (uint64_t s = 0; s < skip; ++s) { + static_cast<void>((*this)()); } } - unsigned int rngSeed() { - return getCurrentContext().getConfig()->rngSeed(); + SimplePcg32::result_type SimplePcg32::operator()() { + // prepare the output value + const uint32_t xorshifted = static_cast<uint32_t>(((m_state >> 18u) ^ m_state) >> 27u); + const auto output = rotate_right(xorshifted, m_state >> 59u); + + // advance state + m_state = m_state * 6364136223846793005ULL + s_inc; + + return output; + } + + bool operator==(SimplePcg32 const& lhs, SimplePcg32 const& rhs) { + return lhs.m_state == rhs.m_state; + } + + bool operator!=(SimplePcg32 const& lhs, SimplePcg32 const& rhs) { + return lhs.m_state != rhs.m_state; } } // end catch_random_number_generator.cpp @@ -9383,6 +12286,8 @@ namespace Catch { struct IConfig; std::vector<TestCase> sortTests( IConfig const& config, std::vector<TestCase> const& unsortedTestCases ); + + bool isThrowSafe( TestCase const& testCase, IConfig const& config ); bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config ); void enforceNoDuplicateTestCases( std::vector<TestCase> const& functions ); @@ -9495,11 +12400,13 @@ namespace Catch { namespace Catch { class StartupExceptionRegistry { +#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) public: void add(std::exception_ptr const& exception) noexcept; std::vector<std::exception_ptr> const& getExceptions() const noexcept; private: std::vector<std::exception_ptr> m_exceptions; +#endif }; } // end namespace Catch @@ -9582,7 +12489,14 @@ namespace Catch { m_tagAliasRegistry.add( alias, tag, lineInfo ); } void registerStartupException() noexcept override { +#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) m_exceptionRegistry.add(std::current_exception()); +#else + CATCH_INTERNAL_ERROR("Attempted to register active exception under CATCH_CONFIG_DISABLE_EXCEPTIONS!"); +#endif + } + IMutableEnumValuesRegistry& getMutableEnumValuesRegistry() override { + return m_enumValuesRegistry; } private: @@ -9591,6 +12505,7 @@ namespace Catch { ExceptionTranslatorRegistry m_exceptionTranslatorRegistry; TagAliasRegistry m_tagAliasRegistry; StartupExceptionRegistry m_exceptionRegistry; + Detail::EnumValuesRegistry m_enumValuesRegistry; }; } @@ -9671,7 +12586,6 @@ namespace Catch { namespace Generators { struct GeneratorTracker : TestCaseTracking::TrackerBase, IGeneratorTracker { - size_t m_index = static_cast<size_t>( -1 ); GeneratorBasePtr m_generator; GeneratorTracker( TestCaseTracking::NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent ) @@ -9683,39 +12597,110 @@ namespace Catch { std::shared_ptr<GeneratorTracker> tracker; ITracker& currentTracker = ctx.currentTracker(); - if( TestCaseTracking::ITrackerPtr childTracker = currentTracker.findChild( nameAndLocation ) ) { + // Under specific circumstances, the generator we want + // to acquire is also the current tracker. If this is + // the case, we have to avoid looking through current + // tracker's children, and instead return the current + // tracker. + // A case where this check is important is e.g. + // for (int i = 0; i < 5; ++i) { + // int n = GENERATE(1, 2); + // } + // + // without it, the code above creates 5 nested generators. + if (currentTracker.nameAndLocation() == nameAndLocation) { + auto thisTracker = currentTracker.parent().findChild(nameAndLocation); + assert(thisTracker); + assert(thisTracker->isGeneratorTracker()); + tracker = std::static_pointer_cast<GeneratorTracker>(thisTracker); + } else if ( TestCaseTracking::ITrackerPtr childTracker = currentTracker.findChild( nameAndLocation ) ) { assert( childTracker ); - assert( childTracker->isIndexTracker() ); + assert( childTracker->isGeneratorTracker() ); tracker = std::static_pointer_cast<GeneratorTracker>( childTracker ); - } - else { + } else { tracker = std::make_shared<GeneratorTracker>( nameAndLocation, ctx, ¤tTracker ); currentTracker.addChild( tracker ); } - if( !ctx.completedCycle() && !tracker->isComplete() ) { - if( tracker->m_runState != ExecutingChildren && tracker->m_runState != NeedsAnotherRun ) - tracker->moveNext(); + if( !tracker->isComplete() ) { tracker->open(); } return *tracker; } - void moveNext() { - m_index++; - m_children.clear(); - } - // TrackerBase interface - bool isIndexTracker() const override { return true; } + bool isGeneratorTracker() const override { return true; } auto hasGenerator() const -> bool override { return !!m_generator; } void close() override { TrackerBase::close(); - if( m_runState == CompletedSuccessfully && m_index < m_generator->size()-1 ) + // If a generator has a child (it is followed by a section) + // and none of its children have started, then we must wait + // until later to start consuming its values. + // This catches cases where `GENERATE` is placed between two + // `SECTION`s. + // **The check for m_children.empty cannot be removed**. + // doing so would break `GENERATE` _not_ followed by `SECTION`s. + const bool should_wait_for_child = [&]() { + // No children -> nobody to wait for + if ( m_children.empty() ) { + return false; + } + // If at least one child started executing, don't wait + if ( std::find_if( + m_children.begin(), + m_children.end(), + []( TestCaseTracking::ITrackerPtr tracker ) { + return tracker->hasStarted(); + } ) != m_children.end() ) { + return false; + } + + // No children have started. We need to check if they _can_ + // start, and thus we should wait for them, or they cannot + // start (due to filters), and we shouldn't wait for them + auto* parent = m_parent; + // This is safe: there is always at least one section + // tracker in a test case tracking tree + while ( !parent->isSectionTracker() ) { + parent = &( parent->parent() ); + } + assert( parent && + "Missing root (test case) level section" ); + + auto const& parentSection = + static_cast<SectionTracker&>( *parent ); + auto const& filters = parentSection.getFilters(); + // No filters -> no restrictions on running sections + if ( filters.empty() ) { + return true; + } + + for ( auto const& child : m_children ) { + if ( child->isSectionTracker() && + std::find( filters.begin(), + filters.end(), + static_cast<SectionTracker&>( *child ) + .trimmedName() ) != + filters.end() ) { + return true; + } + } + return false; + }(); + + // This check is a bit tricky, because m_generator->next() + // has a side-effect, where it consumes generator's current + // value, but we do not want to invoke the side-effect if + // this generator is still waiting for any child to start. + if ( should_wait_for_child || + ( m_runState == CompletedSuccessfully && + m_generator->next() ) ) { + m_children.clear(); m_runState = Executing; + } } // IGeneratorTracker interface @@ -9725,9 +12710,6 @@ namespace Catch { void setGenerator( GeneratorBasePtr&& generator ) override { m_generator = std::move( generator ); } - auto getIndex() const -> size_t override { - return m_index; - } }; GeneratorTracker::~GeneratorTracker() {} } @@ -9825,6 +12807,9 @@ namespace Catch { // and should be let to clear themselves out. static_cast<void>(m_reporter->assertionEnded(AssertionStats(result, m_messages, m_totals))); + if (result.getResultType() != ResultWas::Warning) + m_messageScopes.clear(); + // Reset working state resetAssertionInfo(); m_lastResult = result; @@ -9848,10 +12833,10 @@ namespace Catch { return true; } - auto RunContext::acquireGeneratorTracker( SourceLineInfo const& lineInfo ) -> IGeneratorTracker& { + auto RunContext::acquireGeneratorTracker( StringRef generatorName, SourceLineInfo const& lineInfo ) -> IGeneratorTracker& { using namespace Generators; - GeneratorTracker& tracker = GeneratorTracker::acquire( m_trackerContext, TestCaseTracking::NameAndLocation( "generator", lineInfo ) ); - assert( tracker.isOpen() ); + GeneratorTracker& tracker = GeneratorTracker::acquire(m_trackerContext, + TestCaseTracking::NameAndLocation( static_cast<std::string>(generatorName), lineInfo ) ); m_lastAssertionInfo.lineInfo = lineInfo; return tracker; } @@ -9879,6 +12864,7 @@ namespace Catch { m_reporter->sectionEnded(SectionStats(endInfo.sectionInfo, assertions, endInfo.durationInSeconds, missingAssertions)); m_messages.clear(); + m_messageScopes.clear(); } void RunContext::sectionEndedEarly(SectionEndInfo const & endInfo) { @@ -9890,12 +12876,21 @@ namespace Catch { m_unfinishedSections.push_back(endInfo); } + +#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING) + void RunContext::benchmarkPreparing(std::string const& name) { + m_reporter->benchmarkPreparing(name); + } void RunContext::benchmarkStarting( BenchmarkInfo const& info ) { m_reporter->benchmarkStarting( info ); } - void RunContext::benchmarkEnded( BenchmarkStats const& stats ) { + void RunContext::benchmarkEnded( BenchmarkStats<> const& stats ) { m_reporter->benchmarkEnded( stats ); } + void RunContext::benchmarkFailed(std::string const & error) { + m_reporter->benchmarkFailed(error); + } +#endif // CATCH_CONFIG_ENABLE_BENCHMARKING void RunContext::pushScopedMessage(MessageInfo const & message) { m_messages.push_back(message); @@ -9905,6 +12900,10 @@ namespace Catch { m_messages.erase(std::remove(m_messages.begin(), m_messages.end(), message), m_messages.end()); } + void RunContext::emplaceUnscopedMessage( MessageBuilder const& builder ) { + m_messageScopes.emplace_back( builder ); + } + std::string RunContext::getCurrentTestName() const { return m_activeTestCase ? m_activeTestCase->getTestCaseInfo().name @@ -9926,7 +12925,7 @@ namespace Catch { // Don't rebuild the result -- the stringification itself can cause more fatal errors // Instead, fake a result data. AssertionResultData tempResult( ResultWas::FatalErrorCondition, { false } ); - tempResult.message = message; + tempResult.message = static_cast<std::string>(message); AssertionResult result(m_lastAssertionInfo, tempResult); assertionEnded(result); @@ -9965,6 +12964,7 @@ namespace Catch { m_lastAssertionPassed = true; ++m_totals.assertions.passed; resetAssertionInfo(); + m_messageScopes.clear(); } bool RunContext::aborting() const { @@ -9986,13 +12986,10 @@ namespace Catch { CATCH_TRY { if (m_reporter->getPreferences().shouldRedirectStdOut) { #if !defined(CATCH_CONFIG_EXPERIMENTAL_REDIRECT) - RedirectedStdOut redirectedStdOut; - RedirectedStdErr redirectedStdErr; + RedirectedStreams redirectedStreams(redirectedCout, redirectedCerr); timer.start(); invokeActiveTestCase(); - redirectedCout += redirectedStdOut.str(); - redirectedCerr += redirectedStdErr.str(); #else OutputRedirect r(redirectedCout, redirectedCerr); timer.start(); @@ -10019,15 +13016,15 @@ namespace Catch { m_testCaseTracker->close(); handleUnfinishedSections(); m_messages.clear(); + m_messageScopes.clear(); SectionStats testCaseSectionStats(testCaseSection, assertions, duration, missingAssertions); m_reporter->sectionEnded(testCaseSectionStats); } void RunContext::invokeActiveTestCase() { - FatalConditionHandler fatalConditionHandler; // Handle signals + FatalConditionHandlerGuard _(&m_fatalConditionhandler); m_activeTestCase->invoke(); - fatalConditionHandler.reset(); } void RunContext::handleUnfinishedSections() { @@ -10090,7 +13087,7 @@ namespace Catch { m_lastAssertionInfo = info; AssertionResultData data( resultType, LazyExpression( false ) ); - data.message = message; + data.message = static_cast<std::string>(message); AssertionResult assertionResult{ m_lastAssertionInfo, data }; assertionEnded( assertionResult ); if( !assertionResult.isOk() ) @@ -10153,6 +13150,18 @@ namespace Catch { else CATCH_INTERNAL_ERROR("No result capture instance"); } + + void seedRng(IConfig const& config) { + if (config.rngSeed() != 0) { + std::srand(config.rngSeed()); + rng().seed(config.rngSeed()); + } + } + + unsigned int rngSeed() { + return getCurrentContext().getConfig()->rngSeed(); + } + } // end catch_run_context.cpp // start catch_section.cpp @@ -10214,7 +13223,7 @@ namespace Catch { void libIdentify(); int applyCommandLine( int argc, char const * const * argv ); - #if defined(CATCH_CONFIG_WCHAR) && defined(WIN32) && defined(UNICODE) + #if defined(CATCH_CONFIG_WCHAR) && defined(_WIN32) && defined(UNICODE) int applyCommandLine( int argc, wchar_t const * const * argv ); #endif @@ -10281,6 +13290,8 @@ namespace Catch { // end catch_version.h #include <cstdlib> #include <iomanip> +#include <set> +#include <iterator> namespace Catch { @@ -10299,52 +13310,76 @@ namespace Catch { return createReporter(config->getReporterName(), config); } - auto multi = std::unique_ptr<ListeningReporter>(new ListeningReporter); - + // On older platforms, returning std::unique_ptr<ListeningReporter> + // when the return type is std::unique_ptr<IStreamingReporter> + // doesn't compile without a std::move call. However, this causes + // a warning on newer platforms. Thus, we have to work around + // it a bit and downcast the pointer manually. + auto ret = std::unique_ptr<IStreamingReporter>(new ListeningReporter); + auto& multi = static_cast<ListeningReporter&>(*ret); auto const& listeners = Catch::getRegistryHub().getReporterRegistry().getListeners(); for (auto const& listener : listeners) { - multi->addListener(listener->create(Catch::ReporterConfig(config))); + multi.addListener(listener->create(Catch::ReporterConfig(config))); } - multi->addReporter(createReporter(config->getReporterName(), config)); - return std::move(multi); + multi.addReporter(createReporter(config->getReporterName(), config)); + return ret; } - Catch::Totals runTests(std::shared_ptr<Config> const& config) { - auto reporter = makeReporter(config); - - RunContext context(config, std::move(reporter)); - - Totals totals; - - context.testGroupStarting(config->name(), 1, 1); - - TestSpec testSpec = config->testSpec(); - - auto const& allTestCases = getAllTestCasesSorted(*config); - for (auto const& testCase : allTestCases) { - if (!context.aborting() && matchTest(testCase, testSpec, *config)) - totals += context.runTest(testCase); - else - context.reporter().skipTest(testCase); + class TestGroup { + public: + explicit TestGroup(std::shared_ptr<Config> const& config) + : m_config{config} + , m_context{config, makeReporter(config)} + { + auto const& allTestCases = getAllTestCasesSorted(*m_config); + m_matches = m_config->testSpec().matchesByFilter(allTestCases, *m_config); + auto const& invalidArgs = m_config->testSpec().getInvalidArgs(); + + if (m_matches.empty() && invalidArgs.empty()) { + for (auto const& test : allTestCases) + if (!test.isHidden()) + m_tests.emplace(&test); + } else { + for (auto const& match : m_matches) + m_tests.insert(match.tests.begin(), match.tests.end()); + } } - if (config->warnAboutNoTests() && totals.testCases.total() == 0) { - ReusableStringStream testConfig; + Totals execute() { + auto const& invalidArgs = m_config->testSpec().getInvalidArgs(); + Totals totals; + m_context.testGroupStarting(m_config->name(), 1, 1); + for (auto const& testCase : m_tests) { + if (!m_context.aborting()) + totals += m_context.runTest(*testCase); + else + m_context.reporter().skipTest(*testCase); + } + + for (auto const& match : m_matches) { + if (match.tests.empty()) { + m_context.reporter().noMatchingTestCases(match.name); + totals.error = -1; + } + } - bool first = true; - for (const auto& input : config->getTestsOrTags()) { - if (!first) { testConfig << ' '; } - first = false; - testConfig << input; + if (!invalidArgs.empty()) { + for (auto const& invalidArg: invalidArgs) + m_context.reporter().reportInvalidArguments(invalidArg); } - context.reporter().noMatchingTestCases(testConfig.str()); - totals.error = -1; + m_context.testGroupEnded(m_config->name(), totals, 1, 1); + return totals; } - context.testGroupEnded(config->name(), totals, 1, 1); - return totals; - } + private: + using Tests = std::set<TestCase const*>; + + std::shared_ptr<Config> m_config; + RunContext m_context; + Tests m_tests; + TestSpec::Matches m_matches; + }; void applyFilenamesAsTags(Catch::IConfig const& config) { auto& tests = const_cast<std::vector<TestCase>&>(getAllTestCasesSorted(config)); @@ -10381,6 +13416,9 @@ namespace Catch { #if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) const auto& exceptions = getRegistryHub().getStartupExceptionRegistry().getExceptions(); if ( !exceptions.empty() ) { + config(); + getCurrentMutableContext().setConfig(m_config); + m_startupExceptions = true; Colour colourGuard( Colour::Red ); Catch::cerr() << "Errors occurred during startup!" << '\n'; @@ -10410,7 +13448,7 @@ namespace Catch { } void Session::libIdentify() { Catch::cout() - << std::left << std::setw(16) << "description: " << "A Catch test executable\n" + << std::left << std::setw(16) << "description: " << "A Catch2 test executable\n" << std::left << std::setw(16) << "category: " << "testframework\n" << std::left << std::setw(16) << "framework: " << "Catch Test\n" << std::left << std::setw(16) << "version: " << libraryVersion() << std::endl; @@ -10422,6 +13460,8 @@ namespace Catch { auto result = m_cli.parse( clara::Args( argc, argv ) ); if( !result ) { + config(); + getCurrentMutableContext().setConfig(m_config); Catch::cerr() << Colour( Colour::Red ) << "\nError(s) in input:\n" @@ -10439,17 +13479,17 @@ namespace Catch { return 0; } -#if defined(CATCH_CONFIG_WCHAR) && defined(WIN32) && defined(UNICODE) +#if defined(CATCH_CONFIG_WCHAR) && defined(_WIN32) && defined(UNICODE) int Session::applyCommandLine( int argc, wchar_t const * const * argv ) { char **utf8Argv = new char *[ argc ]; for ( int i = 0; i < argc; ++i ) { - int bufSize = WideCharToMultiByte( CP_UTF8, 0, argv[i], -1, NULL, 0, NULL, NULL ); + int bufSize = WideCharToMultiByte( CP_UTF8, 0, argv[i], -1, nullptr, 0, nullptr, nullptr ); utf8Argv[ i ] = new char[ bufSize ]; - WideCharToMultiByte( CP_UTF8, 0, argv[i], -1, utf8Argv[i], bufSize, NULL, NULL ); + WideCharToMultiByte( CP_UTF8, 0, argv[i], -1, utf8Argv[i], bufSize, nullptr, nullptr ); } int returnCode = applyCommandLine( argc, utf8Argv ); @@ -10513,10 +13553,15 @@ namespace Catch { applyFilenamesAsTags( *m_config ); // Handle list request - if( Option<std::size_t> listed = list( config() ) ) + if( Option<std::size_t> listed = list( m_config ) ) return static_cast<int>( *listed ); - auto totals = runTests( m_config ); + TestGroup tests { m_config }; + auto const totals = tests.execute(); + + if( m_config->warnAboutNoTests() && totals.error == -1 ) + return 2; + // Note that on unices only the lower 8 bits are usually used, clamping // the return value to 255 prevents false negative when some multiple // of 256 tests has failed @@ -10564,6 +13609,7 @@ namespace Catch { // end catch_singletons.cpp // start catch_startup_exception_registry.cpp +#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) namespace Catch { void StartupExceptionRegistry::add( std::exception_ptr const& exception ) noexcept { CATCH_TRY { @@ -10579,6 +13625,7 @@ void StartupExceptionRegistry::add( std::exception_ptr const& exception ) noexce } } // end namespace Catch +#endif // end catch_startup_exception_registry.cpp // start catch_stream.cpp @@ -10593,7 +13640,7 @@ namespace Catch { Catch::IStream::~IStream() = default; - namespace detail { namespace { + namespace Detail { namespace { template<typename WriterF, std::size_t bufferSize=256> class StreamBufImpl : public std::streambuf { char data[bufferSize]; @@ -10692,15 +13739,15 @@ namespace Catch { auto makeStream( StringRef const &filename ) -> IStream const* { if( filename.empty() ) - return new detail::CoutStream(); + return new Detail::CoutStream(); else if( filename[0] == '%' ) { if( filename == "%debug" ) - return new detail::DebugOutStream(); + return new Detail::DebugOutStream(); else CATCH_ERROR( "Unrecognised stream: '" << filename << "'" ); } else - return new detail::FileStream( filename ); + return new Detail::FileStream( filename ); } // This class encapsulates the idea of a pool of ostringstreams that can be reused. @@ -10757,12 +13804,13 @@ namespace Catch { #include <ostream> #include <cstring> #include <cctype> +#include <vector> namespace Catch { namespace { char toLowerCh(char c) { - return static_cast<char>( std::tolower( c ) ); + return static_cast<char>( std::tolower( static_cast<unsigned char>(c) ) ); } } @@ -10797,6 +13845,18 @@ namespace Catch { return start != std::string::npos ? str.substr( start, 1+end-start ) : std::string(); } + StringRef trim(StringRef ref) { + const auto is_ws = [](char c) { + return c == ' ' || c == '\t' || c == '\n' || c == '\r'; + }; + size_t real_begin = 0; + while (real_begin < ref.size() && is_ws(ref[real_begin])) { ++real_begin; } + size_t real_end = ref.size(); + while (real_end > real_begin && is_ws(ref[real_end - 1])) { --real_end; } + + return ref.substr(real_begin, real_end - real_begin); + } + bool replaceInPlace( std::string& str, std::string const& replaceThis, std::string const& withThis ) { bool replaced = false; std::size_t i = str.find( replaceThis ); @@ -10811,6 +13871,21 @@ namespace Catch { return replaced; } + std::vector<StringRef> splitStringRef( StringRef str, char delimiter ) { + std::vector<StringRef> subStrings; + std::size_t start = 0; + for(std::size_t pos = 0; pos < str.size(); ++pos ) { + if( str[pos] == delimiter ) { + if( pos - start > 1 ) + subStrings.push_back( str.substr( start, pos-start ) ); + start = pos+1; + } + } + if( start < str.size() ) + subStrings.push_back( str.substr( start, str.size()-start ) ); + return subStrings; + } + pluralise::pluralise( std::size_t count, std::string const& label ) : m_count( count ), m_label( label ) @@ -10827,123 +13902,46 @@ namespace Catch { // end catch_string_manip.cpp // start catch_stringref.cpp -#if defined(__clang__) -# pragma clang diagnostic push -# pragma clang diagnostic ignored "-Wexit-time-destructors" -#endif - +#include <algorithm> #include <ostream> #include <cstring> #include <cstdint> -namespace { - const uint32_t byte_2_lead = 0xC0; - const uint32_t byte_3_lead = 0xE0; - const uint32_t byte_4_lead = 0xF0; -} - namespace Catch { StringRef::StringRef( char const* rawChars ) noexcept : StringRef( rawChars, static_cast<StringRef::size_type>(std::strlen(rawChars) ) ) {} - StringRef::operator std::string() const { - return std::string( m_start, m_size ); - } - - void StringRef::swap( StringRef& other ) noexcept { - std::swap( m_start, other.m_start ); - std::swap( m_size, other.m_size ); - std::swap( m_data, other.m_data ); - } - auto StringRef::c_str() const -> char const* { - if( isSubstring() ) - const_cast<StringRef*>( this )->takeOwnership(); + CATCH_ENFORCE(isNullTerminated(), "Called StringRef::c_str() on a non-null-terminated instance"); return m_start; } - auto StringRef::currentData() const noexcept -> char const* { + auto StringRef::data() const noexcept -> char const* { return m_start; } - auto StringRef::isOwned() const noexcept -> bool { - return m_data != nullptr; - } - auto StringRef::isSubstring() const noexcept -> bool { - return m_start[m_size] != '\0'; - } - - void StringRef::takeOwnership() { - if( !isOwned() ) { - m_data = new char[m_size+1]; - memcpy( m_data, m_start, m_size ); - m_data[m_size] = '\0'; - m_start = m_data; - } - } auto StringRef::substr( size_type start, size_type size ) const noexcept -> StringRef { - if( start < m_size ) - return StringRef( m_start+start, size ); - else + if (start < m_size) { + return StringRef(m_start + start, (std::min)(m_size - start, size)); + } else { return StringRef(); - } - auto StringRef::operator == ( StringRef const& other ) const noexcept -> bool { - return - size() == other.size() && - (std::strncmp( m_start, other.m_start, size() ) == 0); - } - auto StringRef::operator != ( StringRef const& other ) const noexcept -> bool { - return !operator==( other ); - } - - auto StringRef::operator[](size_type index) const noexcept -> char { - return m_start[index]; - } - - auto StringRef::numberOfCharacters() const noexcept -> size_type { - size_type noChars = m_size; - // Make adjustments for uft encodings - for( size_type i=0; i < m_size; ++i ) { - char c = m_start[i]; - if( ( c & byte_2_lead ) == byte_2_lead ) { - noChars--; - if (( c & byte_3_lead ) == byte_3_lead ) - noChars--; - if( ( c & byte_4_lead ) == byte_4_lead ) - noChars--; - } } - return noChars; - } - - auto operator + ( StringRef const& lhs, StringRef const& rhs ) -> std::string { - std::string str; - str.reserve( lhs.size() + rhs.size() ); - str += lhs; - str += rhs; - return str; } - auto operator + ( StringRef const& lhs, const char* rhs ) -> std::string { - return std::string( lhs ) + std::string( rhs ); - } - auto operator + ( char const* lhs, StringRef const& rhs ) -> std::string { - return std::string( lhs ) + std::string( rhs ); + auto StringRef::operator == ( StringRef const& other ) const noexcept -> bool { + return m_size == other.m_size + && (std::memcmp( m_start, other.m_start, m_size ) == 0); } auto operator << ( std::ostream& os, StringRef const& str ) -> std::ostream& { - return os.write(str.currentData(), str.size()); + return os.write(str.data(), str.size()); } auto operator+=( std::string& lhs, StringRef const& rhs ) -> std::string& { - lhs.append(rhs.currentData(), rhs.size()); + lhs.append(rhs.data(), rhs.size()); return lhs; } } // namespace Catch - -#if defined(__clang__) -# pragma clang diagnostic pop -#endif // end catch_stringref.cpp // start catch_tag_alias.cpp @@ -11046,7 +14044,7 @@ namespace Catch { void enforceNotReservedTag( std::string const& tag, SourceLineInfo const& _lineInfo ) { CATCH_ENFORCE( !isReservedTag(tag), "Tag name: [" << tag << "] is not allowed.\n" - << "Tag names starting with non alpha-numeric characters are reserved\n" + << "Tag names starting with non alphanumeric characters are reserved\n" << _lineInfo ); } } @@ -11062,8 +14060,7 @@ namespace Catch { std::vector<std::string> tags; std::string desc, tag; bool inTag = false; - std::string _descOrTags = nameAndTags.tags; - for (char c : _descOrTags) { + for (char c : nameAndTags.tags) { if( !inTag ) { if( c == '[' ) inTag = true; @@ -11078,6 +14075,12 @@ namespace Catch { else if( prop == TestCaseInfo::None ) enforceNotReservedTag( tag, _lineInfo ); + // Merged hide tags like `[.approvals]` should be added as + // `[.][approvals]`. The `[.]` is added at later point, so + // we only strip the prefix + if (startsWith(tag, '.') && tag.size() > 1) { + tag.erase(0, 1); + } tags.push_back( tag ); tag.clear(); inTag = false; @@ -11087,10 +14090,11 @@ namespace Catch { } } if( isHidden ) { - tags.push_back( "." ); + // Add all "hidden" tags to make them behave identically + tags.insert( tags.end(), { ".", "!hide" } ); } - TestCaseInfo info( nameAndTags.name, _className, desc, tags, _lineInfo ); + TestCaseInfo info( static_cast<std::string>(nameAndTags.name), _className, desc, tags, _lineInfo ); return TestCase( _testCase, std::move(info) ); } @@ -11182,30 +14186,89 @@ namespace Catch { // end catch_test_case_info.cpp // start catch_test_case_registry_impl.cpp +#include <algorithm> #include <sstream> namespace Catch { - std::vector<TestCase> sortTests( IConfig const& config, std::vector<TestCase> const& unsortedTestCases ) { + namespace { + struct TestHasher { + using hash_t = uint64_t; + + explicit TestHasher( hash_t hashSuffix ): + m_hashSuffix{ hashSuffix } {} + + uint32_t operator()( TestCase const& t ) const { + // FNV-1a hash with multiplication fold. + const hash_t prime = 1099511628211u; + hash_t hash = 14695981039346656037u; + for ( const char c : t.name ) { + hash ^= c; + hash *= prime; + } + hash ^= m_hashSuffix; + hash *= prime; + const uint32_t low{ static_cast<uint32_t>( hash ) }; + const uint32_t high{ static_cast<uint32_t>( hash >> 32 ) }; + return low * high; + } - std::vector<TestCase> sorted = unsortedTestCases; + private: + hash_t m_hashSuffix; + }; + } // end unnamed namespace + std::vector<TestCase> sortTests( IConfig const& config, std::vector<TestCase> const& unsortedTestCases ) { switch( config.runOrder() ) { - case RunTests::InLexicographicalOrder: - std::sort( sorted.begin(), sorted.end() ); - break; - case RunTests::InRandomOrder: - seedRng( config ); - std::shuffle( sorted.begin(), sorted.end(), rng() ); - break; case RunTests::InDeclarationOrder: // already in declaration order break; + + case RunTests::InLexicographicalOrder: { + std::vector<TestCase> sorted = unsortedTestCases; + std::sort( sorted.begin(), sorted.end() ); + return sorted; + } + + case RunTests::InRandomOrder: { + seedRng( config ); + TestHasher h{ config.rngSeed() }; + + using hashedTest = std::pair<TestHasher::hash_t, TestCase const*>; + std::vector<hashedTest> indexed_tests; + indexed_tests.reserve( unsortedTestCases.size() ); + + for (auto const& testCase : unsortedTestCases) { + indexed_tests.emplace_back(h(testCase), &testCase); + } + + std::sort(indexed_tests.begin(), indexed_tests.end(), + [](hashedTest const& lhs, hashedTest const& rhs) { + if (lhs.first == rhs.first) { + return lhs.second->name < rhs.second->name; + } + return lhs.first < rhs.first; + }); + + std::vector<TestCase> sorted; + sorted.reserve( indexed_tests.size() ); + + for (auto const& hashed : indexed_tests) { + sorted.emplace_back(*hashed.second); + } + + return sorted; + } } - return sorted; + return unsortedTestCases; + } + + bool isThrowSafe( TestCase const& testCase, IConfig const& config ) { + return !testCase.throws() || config.allowThrows(); } + bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config ) { - return testSpec.matches( testCase ) && ( config.allowThrows() || !testCase.throws() ); + return testSpec.matches( testCase ) && isThrowSafe( testCase, config ); } void enforceNoDuplicateTestCases( std::vector<TestCase> const& functions ) { @@ -11222,9 +14285,12 @@ namespace Catch { std::vector<TestCase> filterTests( std::vector<TestCase> const& testCases, TestSpec const& testSpec, IConfig const& config ) { std::vector<TestCase> filtered; filtered.reserve( testCases.size() ); - for( auto const& testCase : testCases ) - if( matchTest( testCase, testSpec, config ) ) - filtered.push_back( testCase ); + for (auto const& testCase : testCases) { + if ((!testSpec.hasFilters() && !testCase.isHidden()) || + (testSpec.hasFilters() && matchTest(testCase, testSpec, config))) { + filtered.push_back(testCase); + } + } return filtered; } std::vector<TestCase> const& getAllTestCasesSorted( IConfig const& config ) { @@ -11263,7 +14329,7 @@ namespace Catch { } std::string extractClassName( StringRef const& classOrQualifiedMethodName ) { - std::string className = classOrQualifiedMethodName; + std::string className(classOrQualifiedMethodName); if( startsWith( className, '&' ) ) { std::size_t lastColons = className.rfind( "::" ); @@ -11300,11 +14366,6 @@ namespace TestCaseTracking { ITracker::~ITracker() = default; - TrackerContext& TrackerContext::instance() { - static TrackerContext s_instance; - return s_instance; - } - ITracker& TrackerContext::startRun() { m_rootTracker = std::make_shared<SectionTracker>( NameAndLocation( "{root}", CATCH_INTERNAL_LINEINFO ), *this, nullptr ); m_currentTracker = nullptr; @@ -11336,15 +14397,12 @@ namespace TestCaseTracking { m_currentTracker = tracker; } - TrackerBase::TrackerBase( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent ) - : m_nameAndLocation( nameAndLocation ), + TrackerBase::TrackerBase( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent ): + ITracker(nameAndLocation), m_ctx( ctx ), m_parent( parent ) {} - NameAndLocation const& TrackerBase::nameAndLocation() const { - return m_nameAndLocation; - } bool TrackerBase::isComplete() const { return m_runState == CompletedSuccessfully || m_runState == Failed; } @@ -11387,7 +14445,7 @@ namespace TestCaseTracking { } bool TrackerBase::isSectionTracker() const { return false; } - bool TrackerBase::isIndexTracker() const { return false; } + bool TrackerBase::isGeneratorTracker() const { return false; } void TrackerBase::open() { m_runState = Executing; @@ -11410,7 +14468,7 @@ namespace TestCaseTracking { m_runState = CompletedSuccessfully; break; case ExecutingChildren: - if( m_children.empty() || m_children.back()->isComplete() ) + if( std::all_of(m_children.begin(), m_children.end(), [](ITrackerPtr const& t){ return t->isComplete(); }) ) m_runState = CompletedSuccessfully; break; @@ -11445,7 +14503,8 @@ namespace TestCaseTracking { } SectionTracker::SectionTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent ) - : TrackerBase( nameAndLocation, ctx, parent ) + : TrackerBase( nameAndLocation, ctx, parent ), + m_trimmed_name(trim(nameAndLocation.name)) { if( parent ) { while( !parent->isSectionTracker() ) @@ -11456,6 +14515,17 @@ namespace TestCaseTracking { } } + bool SectionTracker::isComplete() const { + bool complete = true; + + if (m_filters.empty() + || m_filters[0] == "" + || std::find(m_filters.begin(), m_filters.end(), m_trimmed_name) != m_filters.end()) { + complete = TrackerBase::isComplete(); + } + return complete; + } + bool SectionTracker::isSectionTracker() const { return true; } SectionTracker& SectionTracker::acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation ) { @@ -11477,63 +14547,29 @@ namespace TestCaseTracking { } void SectionTracker::tryOpen() { - if( !isComplete() && (m_filters.empty() || m_filters[0].empty() || m_filters[0] == m_nameAndLocation.name ) ) + if( !isComplete() ) open(); } void SectionTracker::addInitialFilters( std::vector<std::string> const& filters ) { if( !filters.empty() ) { - m_filters.push_back(""); // Root - should never be consulted - m_filters.push_back(""); // Test Case - not a section filter + m_filters.reserve( m_filters.size() + filters.size() + 2 ); + m_filters.emplace_back(""); // Root - should never be consulted + m_filters.emplace_back(""); // Test Case - not a section filter m_filters.insert( m_filters.end(), filters.begin(), filters.end() ); } } void SectionTracker::addNextFilters( std::vector<std::string> const& filters ) { if( filters.size() > 1 ) - m_filters.insert( m_filters.end(), ++filters.begin(), filters.end() ); + m_filters.insert( m_filters.end(), filters.begin()+1, filters.end() ); } - IndexTracker::IndexTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent, int size ) - : TrackerBase( nameAndLocation, ctx, parent ), - m_size( size ) - {} - - bool IndexTracker::isIndexTracker() const { return true; } - - IndexTracker& IndexTracker::acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation, int size ) { - std::shared_ptr<IndexTracker> tracker; - - ITracker& currentTracker = ctx.currentTracker(); - if( ITrackerPtr childTracker = currentTracker.findChild( nameAndLocation ) ) { - assert( childTracker ); - assert( childTracker->isIndexTracker() ); - tracker = std::static_pointer_cast<IndexTracker>( childTracker ); - } - else { - tracker = std::make_shared<IndexTracker>( nameAndLocation, ctx, ¤tTracker, size ); - currentTracker.addChild( tracker ); - } - - if( !ctx.completedCycle() && !tracker->isComplete() ) { - if( tracker->m_runState != ExecutingChildren && tracker->m_runState != NeedsAnotherRun ) - tracker->moveNext(); - tracker->open(); - } - - return *tracker; + std::vector<std::string> const& SectionTracker::getFilters() const { + return m_filters; } - int IndexTracker::index() const { return m_index; } - - void IndexTracker::moveNext() { - m_index++; - m_children.clear(); - } - - void IndexTracker::close() { - TrackerBase::close(); - if( m_runState == CompletedSuccessfully && m_index < m_size-1 ) - m_runState = Executing; + std::string const& SectionTracker::trimmedName() const { + return m_trimmed_name; } } // namespace TestCaseTracking @@ -11541,7 +14577,6 @@ namespace TestCaseTracking { using TestCaseTracking::ITracker; using TestCaseTracking::TrackerContext; using TestCaseTracking::SectionTracker; -using TestCaseTracking::IndexTracker; } // namespace Catch @@ -11586,47 +14621,81 @@ namespace Catch { namespace Catch { + TestSpec::Pattern::Pattern( std::string const& name ) + : m_name( name ) + {} + TestSpec::Pattern::~Pattern() = default; - TestSpec::NamePattern::~NamePattern() = default; - TestSpec::TagPattern::~TagPattern() = default; - TestSpec::ExcludedPattern::~ExcludedPattern() = default; - TestSpec::NamePattern::NamePattern( std::string const& name ) - : m_wildcardPattern( toLower( name ), CaseSensitive::No ) + std::string const& TestSpec::Pattern::name() const { + return m_name; + } + + TestSpec::NamePattern::NamePattern( std::string const& name, std::string const& filterString ) + : Pattern( filterString ) + , m_wildcardPattern( toLower( name ), CaseSensitive::No ) {} + bool TestSpec::NamePattern::matches( TestCaseInfo const& testCase ) const { - return m_wildcardPattern.matches( toLower( testCase.name ) ); + return m_wildcardPattern.matches( testCase.name ); } - TestSpec::TagPattern::TagPattern( std::string const& tag ) : m_tag( toLower( tag ) ) {} + TestSpec::TagPattern::TagPattern( std::string const& tag, std::string const& filterString ) + : Pattern( filterString ) + , m_tag( toLower( tag ) ) + {} + bool TestSpec::TagPattern::matches( TestCaseInfo const& testCase ) const { return std::find(begin(testCase.lcaseTags), end(testCase.lcaseTags), m_tag) != end(testCase.lcaseTags); } - TestSpec::ExcludedPattern::ExcludedPattern( PatternPtr const& underlyingPattern ) : m_underlyingPattern( underlyingPattern ) {} - bool TestSpec::ExcludedPattern::matches( TestCaseInfo const& testCase ) const { return !m_underlyingPattern->matches( testCase ); } + TestSpec::ExcludedPattern::ExcludedPattern( PatternPtr const& underlyingPattern ) + : Pattern( underlyingPattern->name() ) + , m_underlyingPattern( underlyingPattern ) + {} + + bool TestSpec::ExcludedPattern::matches( TestCaseInfo const& testCase ) const { + return !m_underlyingPattern->matches( testCase ); + } bool TestSpec::Filter::matches( TestCaseInfo const& testCase ) const { - // All patterns in a filter must match for the filter to be a match - for( auto const& pattern : m_patterns ) { - if( !pattern->matches( testCase ) ) - return false; - } - return true; + return std::all_of( m_patterns.begin(), m_patterns.end(), [&]( PatternPtr const& p ){ return p->matches( testCase ); } ); + } + + std::string TestSpec::Filter::name() const { + std::string name; + for( auto const& p : m_patterns ) + name += p->name(); + return name; } bool TestSpec::hasFilters() const { return !m_filters.empty(); } + bool TestSpec::matches( TestCaseInfo const& testCase ) const { - // A TestSpec matches if any filter matches - for( auto const& filter : m_filters ) - if( filter.matches( testCase ) ) - return true; - return false; + return std::any_of( m_filters.begin(), m_filters.end(), [&]( Filter const& f ){ return f.matches( testCase ); } ); } + + TestSpec::Matches TestSpec::matchesByFilter( std::vector<TestCase> const& testCases, IConfig const& config ) const + { + Matches matches( m_filters.size() ); + std::transform( m_filters.begin(), m_filters.end(), matches.begin(), [&]( Filter const& filter ){ + std::vector<TestCase const*> currentMatches; + for( auto const& test : testCases ) + if( isThrowSafe( test, config ) && filter.matches( test ) ) + currentMatches.emplace_back( &test ); + return FilterMatch{ filter.name(), currentMatches }; + } ); + return matches; + } + + const TestSpec::vectorStrings& TestSpec::getInvalidArgs() const{ + return (m_invalidArgs); + } + } // end catch_test_spec.cpp // start catch_test_spec_parser.cpp @@ -11638,64 +14707,136 @@ namespace Catch { TestSpecParser& TestSpecParser::parse( std::string const& arg ) { m_mode = None; m_exclusion = false; - m_start = std::string::npos; m_arg = m_tagAliases->expandAliases( arg ); m_escapeChars.clear(); + m_substring.reserve(m_arg.size()); + m_patternName.reserve(m_arg.size()); + m_realPatternPos = 0; + for( m_pos = 0; m_pos < m_arg.size(); ++m_pos ) - visitChar( m_arg[m_pos] ); - if( m_mode == Name ) - addPattern<TestSpec::NamePattern>(); + //if visitChar fails + if( !visitChar( m_arg[m_pos] ) ){ + m_testSpec.m_invalidArgs.push_back(arg); + break; + } + endMode(); return *this; } TestSpec TestSpecParser::testSpec() { addFilter(); return m_testSpec; } + bool TestSpecParser::visitChar( char c ) { + if( (m_mode != EscapedName) && (c == '\\') ) { + escape(); + addCharToPattern(c); + return true; + }else if((m_mode != EscapedName) && (c == ',') ) { + return separate(); + } - void TestSpecParser::visitChar( char c ) { - if( m_mode == None ) { - switch( c ) { - case ' ': return; - case '~': m_exclusion = true; return; - case '[': return startNewMode( Tag, ++m_pos ); - case '"': return startNewMode( QuotedName, ++m_pos ); - case '\\': return escape(); - default: startNewMode( Name, m_pos ); break; - } + switch( m_mode ) { + case None: + if( processNoneChar( c ) ) + return true; + break; + case Name: + processNameChar( c ); + break; + case EscapedName: + endMode(); + addCharToPattern(c); + return true; + default: + case Tag: + case QuotedName: + if( processOtherChar( c ) ) + return true; + break; } - if( m_mode == Name ) { - if( c == ',' ) { - addPattern<TestSpec::NamePattern>(); - addFilter(); - } - else if( c == '[' ) { - if( subString() == "exclude:" ) - m_exclusion = true; - else - addPattern<TestSpec::NamePattern>(); - startNewMode( Tag, ++m_pos ); - } - else if( c == '\\' ) - escape(); + + m_substring += c; + if( !isControlChar( c ) ) { + m_patternName += c; + m_realPatternPos++; } - else if( m_mode == EscapedName ) - m_mode = Name; - else if( m_mode == QuotedName && c == '"' ) - addPattern<TestSpec::NamePattern>(); - else if( m_mode == Tag && c == ']' ) - addPattern<TestSpec::TagPattern>(); + return true; + } + // Two of the processing methods return true to signal the caller to return + // without adding the given character to the current pattern strings + bool TestSpecParser::processNoneChar( char c ) { + switch( c ) { + case ' ': + return true; + case '~': + m_exclusion = true; + return false; + case '[': + startNewMode( Tag ); + return false; + case '"': + startNewMode( QuotedName ); + return false; + default: + startNewMode( Name ); + return false; + } + } + void TestSpecParser::processNameChar( char c ) { + if( c == '[' ) { + if( m_substring == "exclude:" ) + m_exclusion = true; + else + endMode(); + startNewMode( Tag ); + } + } + bool TestSpecParser::processOtherChar( char c ) { + if( !isControlChar( c ) ) + return false; + m_substring += c; + endMode(); + return true; } - void TestSpecParser::startNewMode( Mode mode, std::size_t start ) { + void TestSpecParser::startNewMode( Mode mode ) { m_mode = mode; - m_start = start; + } + void TestSpecParser::endMode() { + switch( m_mode ) { + case Name: + case QuotedName: + return addNamePattern(); + case Tag: + return addTagPattern(); + case EscapedName: + revertBackToLastMode(); + return; + case None: + default: + return startNewMode( None ); + } } void TestSpecParser::escape() { - if( m_mode == None ) - m_start = m_pos; + saveLastMode(); m_mode = EscapedName; - m_escapeChars.push_back( m_pos ); + m_escapeChars.push_back(m_realPatternPos); + } + bool TestSpecParser::isControlChar( char c ) const { + switch( m_mode ) { + default: + return false; + case None: + return c == '~'; + case Name: + return c == '['; + case EscapedName: + return true; + case QuotedName: + return c == '"'; + case Tag: + return c == '[' || c == ']'; + } } - std::string TestSpecParser::subString() const { return m_arg.substr( m_start, m_pos - m_start ); } void TestSpecParser::addFilter() { if( !m_currentFilter.m_patterns.empty() ) { @@ -11704,6 +14845,86 @@ namespace Catch { } } + void TestSpecParser::saveLastMode() { + lastMode = m_mode; + } + + void TestSpecParser::revertBackToLastMode() { + m_mode = lastMode; + } + + bool TestSpecParser::separate() { + if( (m_mode==QuotedName) || (m_mode==Tag) ){ + //invalid argument, signal failure to previous scope. + m_mode = None; + m_pos = m_arg.size(); + m_substring.clear(); + m_patternName.clear(); + m_realPatternPos = 0; + return false; + } + endMode(); + addFilter(); + return true; //success + } + + std::string TestSpecParser::preprocessPattern() { + std::string token = m_patternName; + for (std::size_t i = 0; i < m_escapeChars.size(); ++i) + token = token.substr(0, m_escapeChars[i] - i) + token.substr(m_escapeChars[i] - i + 1); + m_escapeChars.clear(); + if (startsWith(token, "exclude:")) { + m_exclusion = true; + token = token.substr(8); + } + + m_patternName.clear(); + m_realPatternPos = 0; + + return token; + } + + void TestSpecParser::addNamePattern() { + auto token = preprocessPattern(); + + if (!token.empty()) { + TestSpec::PatternPtr pattern = std::make_shared<TestSpec::NamePattern>(token, m_substring); + if (m_exclusion) + pattern = std::make_shared<TestSpec::ExcludedPattern>(pattern); + m_currentFilter.m_patterns.push_back(pattern); + } + m_substring.clear(); + m_exclusion = false; + m_mode = None; + } + + void TestSpecParser::addTagPattern() { + auto token = preprocessPattern(); + + if (!token.empty()) { + // If the tag pattern is the "hide and tag" shorthand (e.g. [.foo]) + // we have to create a separate hide tag and shorten the real one + if (token.size() > 1 && token[0] == '.') { + token.erase(token.begin()); + TestSpec::PatternPtr pattern = std::make_shared<TestSpec::TagPattern>(".", m_substring); + if (m_exclusion) { + pattern = std::make_shared<TestSpec::ExcludedPattern>(pattern); + } + m_currentFilter.m_patterns.push_back(pattern); + } + + TestSpec::PatternPtr pattern = std::make_shared<TestSpec::TagPattern>(token, m_substring); + + if (m_exclusion) { + pattern = std::make_shared<TestSpec::ExcludedPattern>(pattern); + } + m_currentFilter.m_patterns.push_back(pattern); + } + m_substring.clear(); + m_exclusion = false; + m_mode = None; + } + TestSpec parseTestSpec( std::string const& arg ) { return TestSpecParser( ITagAliasRegistry::get() ).parse( arg ).testSpec(); } @@ -11744,7 +14965,7 @@ namespace Catch { // is terrible and we should move on. // TBD: How to signal that the measured resolution is probably wrong? if (ticks > startTime + 3 * nanosecondsInSecond) { - return sum / i; + return sum / ( i + 1u ); } } @@ -11805,13 +15026,11 @@ namespace Detail { enum Arch { Big, Little }; static Arch which() { - union _{ - int asInt; - char asChar[sizeof (int)]; - } u; - - u.asInt = 1; - return ( u.asChar[sizeof(int)-1] == 1 ) ? Big : Little; + int one = 1; + // If the lowest byte we read is non-zero, we can assume + // that little endian format is used. + auto value = *reinterpret_cast<char*>(&one); + return value ? Little : Big; } }; } @@ -11935,6 +15154,13 @@ std::string StringMaker<wchar_t *>::convert(wchar_t * str) { } #endif +#if defined(CATCH_CONFIG_CPP17_BYTE) +#include <cstddef> +std::string StringMaker<std::byte>::convert(std::byte value) { + return ::Catch::Detail::stringify(std::to_integer<unsigned long long>(value)); +} +#endif // defined(CATCH_CONFIG_CPP17_BYTE) + std::string StringMaker<int>::convert(int value) { return ::Catch::Detail::stringify(static_cast<long long>(value)); } @@ -11997,11 +15223,16 @@ std::string StringMaker<std::nullptr_t>::convert(std::nullptr_t) { return "nullptr"; } +int StringMaker<float>::precision = 5; + std::string StringMaker<float>::convert(float value) { - return fpToString(value, 5) + 'f'; + return fpToString(value, precision) + 'f'; } + +int StringMaker<double>::precision = 10; + std::string StringMaker<double>::convert(double value) { - return fpToString(value, 10); + return fpToString(value, precision); } std::string ratio_string<std::atto>::symbol() { return "a"; } @@ -12075,11 +15306,48 @@ namespace Catch { // end catch_totals.cpp // start catch_uncaught_exceptions.cpp +// start catch_config_uncaught_exceptions.hpp + +// Copyright Catch2 Authors +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// https://www.boost.org/LICENSE_1_0.txt) + +// SPDX-License-Identifier: BSL-1.0 + +#ifndef CATCH_CONFIG_UNCAUGHT_EXCEPTIONS_HPP +#define CATCH_CONFIG_UNCAUGHT_EXCEPTIONS_HPP + +#if defined(_MSC_VER) +# if _MSC_VER >= 1900 // Visual Studio 2015 or newer +# define CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS +# endif +#endif + +#include <exception> + +#if defined(__cpp_lib_uncaught_exceptions) \ + && !defined(CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS) + +# define CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS +#endif // __cpp_lib_uncaught_exceptions + +#if defined(CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS) \ + && !defined(CATCH_CONFIG_NO_CPP17_UNCAUGHT_EXCEPTIONS) \ + && !defined(CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS) + +# define CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS +#endif + +#endif // CATCH_CONFIG_UNCAUGHT_EXCEPTIONS_HPP +// end catch_config_uncaught_exceptions.hpp #include <exception> namespace Catch { bool uncaught_exceptions() { -#if defined(CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS) +#if defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) + return false; +#elif defined(CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS) return std::uncaught_exceptions() > 0; #else return std::uncaught_exception(); @@ -12119,7 +15387,7 @@ namespace Catch { } Version const& libraryVersion() { - static Version version( 2, 5, 0, "", 0 ); + static Version version( 2, 13, 8, "", 0 ); return version; } @@ -12127,14 +15395,12 @@ namespace Catch { // end catch_version.cpp // start catch_wildcard_pattern.cpp -#include <sstream> - namespace Catch { WildcardPattern::WildcardPattern( std::string const& pattern, CaseSensitive::Choice caseSensitivity ) : m_caseSensitivity( caseSensitivity ), - m_pattern( adjustCase( pattern ) ) + m_pattern( normaliseString( pattern ) ) { if( startsWith( m_pattern, '*' ) ) { m_pattern = m_pattern.substr( 1 ); @@ -12149,28 +15415,27 @@ namespace Catch { bool WildcardPattern::matches( std::string const& str ) const { switch( m_wildcard ) { case NoWildcard: - return m_pattern == adjustCase( str ); + return m_pattern == normaliseString( str ); case WildcardAtStart: - return endsWith( adjustCase( str ), m_pattern ); + return endsWith( normaliseString( str ), m_pattern ); case WildcardAtEnd: - return startsWith( adjustCase( str ), m_pattern ); + return startsWith( normaliseString( str ), m_pattern ); case WildcardAtBothEnds: - return contains( adjustCase( str ), m_pattern ); + return contains( normaliseString( str ), m_pattern ); default: CATCH_INTERNAL_ERROR( "Unknown enum" ); } } - std::string WildcardPattern::adjustCase( std::string const& str ) const { - return m_caseSensitivity == CaseSensitive::No ? toLower( str ) : str; + std::string WildcardPattern::normaliseString( std::string const& str ) const { + return trim( m_caseSensitivity == CaseSensitive::No ? toLower( str ) : str ); } } // end catch_wildcard_pattern.cpp // start catch_xmlwriter.cpp #include <iomanip> - -using uchar = unsigned char; +#include <type_traits> namespace Catch { @@ -12203,13 +15468,37 @@ namespace { } void hexEscapeChar(std::ostream& os, unsigned char c) { + std::ios_base::fmtflags f(os.flags()); os << "\\x" << std::uppercase << std::hex << std::setfill('0') << std::setw(2) << static_cast<int>(c); + os.flags(f); + } + + bool shouldNewline(XmlFormatting fmt) { + return !!(static_cast<std::underlying_type<XmlFormatting>::type>(fmt & XmlFormatting::Newline)); + } + + bool shouldIndent(XmlFormatting fmt) { + return !!(static_cast<std::underlying_type<XmlFormatting>::type>(fmt & XmlFormatting::Indent)); } } // anonymous namespace + XmlFormatting operator | (XmlFormatting lhs, XmlFormatting rhs) { + return static_cast<XmlFormatting>( + static_cast<std::underlying_type<XmlFormatting>::type>(lhs) | + static_cast<std::underlying_type<XmlFormatting>::type>(rhs) + ); + } + + XmlFormatting operator & (XmlFormatting lhs, XmlFormatting rhs) { + return static_cast<XmlFormatting>( + static_cast<std::underlying_type<XmlFormatting>::type>(lhs) & + static_cast<std::underlying_type<XmlFormatting>::type>(rhs) + ); + } + XmlEncode::XmlEncode( std::string const& str, ForWhat forWhat ) : m_str( str ), m_forWhat( forWhat ) @@ -12220,7 +15509,7 @@ namespace { // (see: http://www.w3.org/TR/xml/#syntax) for( std::size_t idx = 0; idx < m_str.size(); ++ idx ) { - uchar c = m_str[idx]; + unsigned char c = m_str[idx]; switch (c) { case '<': os << "<"; break; case '&': os << "&"; break; @@ -12280,7 +15569,7 @@ namespace { bool valid = true; uint32_t value = headerValue(c); for (std::size_t n = 1; n < encBytes; ++n) { - uchar nc = m_str[idx + n]; + unsigned char nc = m_str[idx + n]; valid &= ((nc & 0xC0) == 0x80); value = (value << 6) | (nc & 0x3F); } @@ -12314,13 +15603,17 @@ namespace { return os; } - XmlWriter::ScopedElement::ScopedElement( XmlWriter* writer ) - : m_writer( writer ) + XmlWriter::ScopedElement::ScopedElement( XmlWriter* writer, XmlFormatting fmt ) + : m_writer( writer ), + m_fmt(fmt) {} XmlWriter::ScopedElement::ScopedElement( ScopedElement&& other ) noexcept - : m_writer( other.m_writer ){ + : m_writer( other.m_writer ), + m_fmt(other.m_fmt) + { other.m_writer = nullptr; + other.m_fmt = XmlFormatting::None; } XmlWriter::ScopedElement& XmlWriter::ScopedElement::operator=( ScopedElement&& other ) noexcept { if ( m_writer ) { @@ -12328,16 +15621,19 @@ namespace { } m_writer = other.m_writer; other.m_writer = nullptr; + m_fmt = other.m_fmt; + other.m_fmt = XmlFormatting::None; return *this; } XmlWriter::ScopedElement::~ScopedElement() { - if( m_writer ) - m_writer->endElement(); + if (m_writer) { + m_writer->endElement(m_fmt); + } } - XmlWriter::ScopedElement& XmlWriter::ScopedElement::writeText( std::string const& text, bool indent ) { - m_writer->writeText( text, indent ); + XmlWriter::ScopedElement& XmlWriter::ScopedElement::writeText( std::string const& text, XmlFormatting fmt ) { + m_writer->writeText( text, fmt ); return *this; } @@ -12347,37 +15643,47 @@ namespace { } XmlWriter::~XmlWriter() { - while( !m_tags.empty() ) + while (!m_tags.empty()) { endElement(); + } + newlineIfNecessary(); } - XmlWriter& XmlWriter::startElement( std::string const& name ) { + XmlWriter& XmlWriter::startElement( std::string const& name, XmlFormatting fmt ) { ensureTagClosed(); newlineIfNecessary(); - m_os << m_indent << '<' << name; + if (shouldIndent(fmt)) { + m_os << m_indent; + m_indent += " "; + } + m_os << '<' << name; m_tags.push_back( name ); - m_indent += " "; m_tagIsOpen = true; + applyFormatting(fmt); return *this; } - XmlWriter::ScopedElement XmlWriter::scopedElement( std::string const& name ) { - ScopedElement scoped( this ); - startElement( name ); + XmlWriter::ScopedElement XmlWriter::scopedElement( std::string const& name, XmlFormatting fmt ) { + ScopedElement scoped( this, fmt ); + startElement( name, fmt ); return scoped; } - XmlWriter& XmlWriter::endElement() { - newlineIfNecessary(); - m_indent = m_indent.substr( 0, m_indent.size()-2 ); + XmlWriter& XmlWriter::endElement(XmlFormatting fmt) { + m_indent = m_indent.substr(0, m_indent.size() - 2); + if( m_tagIsOpen ) { m_os << "/>"; m_tagIsOpen = false; + } else { + newlineIfNecessary(); + if (shouldIndent(fmt)) { + m_os << m_indent; + } + m_os << "</" << m_tags.back() << ">"; } - else { - m_os << m_indent << "</" << m_tags.back() << ">"; - } - m_os << std::endl; + m_os << std::flush; + applyFormatting(fmt); m_tags.pop_back(); return *this; } @@ -12393,22 +15699,26 @@ namespace { return *this; } - XmlWriter& XmlWriter::writeText( std::string const& text, bool indent ) { + XmlWriter& XmlWriter::writeText( std::string const& text, XmlFormatting fmt) { if( !text.empty() ){ bool tagWasOpen = m_tagIsOpen; ensureTagClosed(); - if( tagWasOpen && indent ) + if (tagWasOpen && shouldIndent(fmt)) { m_os << m_indent; + } m_os << XmlEncode( text ); - m_needsNewline = true; + applyFormatting(fmt); } return *this; } - XmlWriter& XmlWriter::writeComment( std::string const& text ) { + XmlWriter& XmlWriter::writeComment( std::string const& text, XmlFormatting fmt) { ensureTagClosed(); - m_os << m_indent << "<!--" << text << "-->"; - m_needsNewline = true; + if (shouldIndent(fmt)) { + m_os << m_indent; + } + m_os << "<!--" << text << "-->"; + applyFormatting(fmt); return *this; } @@ -12424,11 +15734,16 @@ namespace { void XmlWriter::ensureTagClosed() { if( m_tagIsOpen ) { - m_os << ">" << std::endl; + m_os << '>' << std::flush; + newlineIfNecessary(); m_tagIsOpen = false; } } + void XmlWriter::applyFormatting(XmlFormatting fmt) { + m_needsNewline = shouldNewline(fmt); + } + void XmlWriter::writeDeclaration() { m_os << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"; } @@ -12469,11 +15784,37 @@ namespace Catch { #ifdef _MSC_VER sprintf_s(buffer, "%.3f", duration); #else - sprintf(buffer, "%.3f", duration); + std::sprintf(buffer, "%.3f", duration); #endif return std::string(buffer); } + bool shouldShowDuration( IConfig const& config, double duration ) { + if ( config.showDurations() == ShowDurations::Always ) { + return true; + } + if ( config.showDurations() == ShowDurations::Never ) { + return false; + } + const double min = config.minDuration(); + return min >= 0 && duration >= min; + } + + std::string serializeFilters( std::vector<std::string> const& container ) { + ReusableStringStream oss; + bool first = true; + for (auto&& filter : container) + { + if (!first) + oss << ' '; + else + first = false; + + oss << filter; + } + return oss.str(); + } + TestEventListenerBase::TestEventListenerBase(ReporterConfig const & _config) :StreamingReporterBase(_config) {} @@ -12689,24 +16030,25 @@ private: if (itMessage == messages.end()) return; - // using messages.end() directly yields (or auto) compilation error: - std::vector<MessageInfo>::const_iterator itEnd = messages.end(); - const std::size_t N = static_cast<std::size_t>(std::distance(itMessage, itEnd)); + const auto itEnd = messages.cend(); + const auto N = static_cast<std::size_t>(std::distance(itMessage, itEnd)); { Colour colourGuard(colour); stream << " with " << pluralise(N, "message") << ':'; } - for (; itMessage != itEnd; ) { + while (itMessage != itEnd) { // If this assertion is a warning ignore any INFO messages if (printInfoMessages || itMessage->type != ResultWas::Info) { - stream << " '" << itMessage->message << '\''; - if (++itMessage != itEnd) { + printMessage(); + if (itMessage != itEnd) { Colour colourGuard(dimColour()); stream << " and"; } + continue; } + ++itMessage; } } @@ -12724,10 +16066,6 @@ private: return "Reports test results on a single line, suitable for IDEs"; } - ReporterPreferences CompactReporter::getPreferences() const { - return m_reporterPrefs; - } - void CompactReporter::noMatchingTestCases( std::string const& spec ) { stream << "No test cases matched '" << spec << '\'' << std::endl; } @@ -12754,8 +16092,9 @@ private: } void CompactReporter::sectionEnded(SectionStats const& _sectionStats) { - if (m_config->showDurations() == ShowDurations::Always) { - stream << getFormattedDuration(_sectionStats.durationInSeconds) << " s: " << _sectionStats.sectionInfo.name << std::endl; + double dur = _sectionStats.durationInSeconds; + if ( shouldShowDuration( *m_config, dur ) ) { + stream << getFormattedDuration( dur ) << " s: " << _sectionStats.sectionInfo.name << std::endl; } } @@ -12779,8 +16118,13 @@ private: #if defined(_MSC_VER) #pragma warning(push) #pragma warning(disable:4061) // Not all labels are EXPLICITLY handled in switch - // Note that 4062 (not all labels are handled - // and default is missing) is enabled + // Note that 4062 (not all labels are handled and default is missing) is enabled +#endif + +#if defined(__clang__) +# pragma clang diagnostic push +// For simplicity, benchmarking-only helpers are always enabled +# pragma clang diagnostic ignored "-Wunused-function" #endif namespace Catch { @@ -12962,11 +16306,11 @@ class Duration { static const uint64_t s_nanosecondsInASecond = 1000 * s_nanosecondsInAMillisecond; static const uint64_t s_nanosecondsInAMinute = 60 * s_nanosecondsInASecond; - uint64_t m_inNanoseconds; + double m_inNanoseconds; Unit m_units; public: - explicit Duration(uint64_t inNanoseconds, Unit units = Unit::Auto) + explicit Duration(double inNanoseconds, Unit units = Unit::Auto) : m_inNanoseconds(inNanoseconds), m_units(units) { if (m_units == Unit::Auto) { @@ -12995,7 +16339,7 @@ public: case Unit::Minutes: return m_inNanoseconds / static_cast<double>(s_nanosecondsInAMinute); default: - return static_cast<double>(m_inNanoseconds); + return m_inNanoseconds; } } auto unitsAsString() const -> std::string { @@ -13003,7 +16347,7 @@ public: case Unit::Nanoseconds: return "ns"; case Unit::Microseconds: - return "µs"; + return "us"; case Unit::Milliseconds: return "ms"; case Unit::Seconds: @@ -13016,7 +16360,7 @@ public: } friend auto operator << (std::ostream& os, Duration const& duration) -> std::ostream& { - return os << duration.value() << " " << duration.unitsAsString(); + return os << duration.value() << ' ' << duration.unitsAsString(); } }; } // end anon namespace @@ -13041,10 +16385,16 @@ public: if (!m_isOpen) { m_isOpen = true; *this << RowBreak(); - for (auto const& info : m_columnInfos) - *this << info.name << ColumnBreak(); - *this << RowBreak(); - m_os << Catch::getLineOfChars<'-'>() << "\n"; + + Columns headerCols; + Spacer spacer(2); + for (auto const& info : m_columnInfos) { + headerCols += Column(info.name).width(static_cast<std::size_t>(info.width - 2)); + headerCols += spacer; + } + m_os << headerCols << '\n'; + + m_os << Catch::getLineOfChars<'-'>() << '\n'; } } void close() { @@ -13063,30 +16413,29 @@ public: friend TablePrinter& operator << (TablePrinter& tp, ColumnBreak) { auto colStr = tp.m_oss.str(); - // This takes account of utf8 encodings - auto strSize = Catch::StringRef(colStr).numberOfCharacters(); + const auto strSize = colStr.size(); tp.m_oss.str(""); tp.open(); if (tp.m_currentColumn == static_cast<int>(tp.m_columnInfos.size() - 1)) { tp.m_currentColumn = -1; - tp.m_os << "\n"; + tp.m_os << '\n'; } tp.m_currentColumn++; auto colInfo = tp.m_columnInfos[tp.m_currentColumn]; - auto padding = (strSize + 2 < static_cast<std::size_t>(colInfo.width)) - ? std::string(colInfo.width - (strSize + 2), ' ') + auto padding = (strSize + 1 < static_cast<std::size_t>(colInfo.width)) + ? std::string(colInfo.width - (strSize + 1), ' ') : std::string(); if (colInfo.justification == ColumnInfo::Left) - tp.m_os << colStr << padding << " "; + tp.m_os << colStr << padding << ' '; else - tp.m_os << padding << colStr << " "; + tp.m_os << padding << colStr << ' '; return tp; } friend TablePrinter& operator << (TablePrinter& tp, RowBreak) { if (tp.m_currentColumn > 0) { - tp.m_os << "\n"; + tp.m_os << '\n'; tp.m_currentColumn = -1; } return tp; @@ -13096,12 +16445,26 @@ public: ConsoleReporter::ConsoleReporter(ReporterConfig const& config) : StreamingReporterBase(config), m_tablePrinter(new TablePrinter(config.stream(), - { - { "benchmark name", CATCH_CONFIG_CONSOLE_WIDTH - 32, ColumnInfo::Left }, - { "iters", 8, ColumnInfo::Right }, - { "elapsed ns", 14, ColumnInfo::Right }, - { "average", 14, ColumnInfo::Right } - })) {} + [&config]() -> std::vector<ColumnInfo> { + if (config.fullConfig()->benchmarkNoAnalysis()) + { + return{ + { "benchmark name", CATCH_CONFIG_CONSOLE_WIDTH - 43, ColumnInfo::Left }, + { " samples", 14, ColumnInfo::Right }, + { " iterations", 14, ColumnInfo::Right }, + { " mean", 14, ColumnInfo::Right } + }; + } + else + { + return{ + { "benchmark name", CATCH_CONFIG_CONSOLE_WIDTH - 43, ColumnInfo::Left }, + { "samples mean std dev", 14, ColumnInfo::Right }, + { "iterations low mean low std dev", 14, ColumnInfo::Right }, + { "estimated high mean high std dev", 14, ColumnInfo::Right } + }; + } + }())) {} ConsoleReporter::~ConsoleReporter() = default; std::string ConsoleReporter::getDescription() { @@ -13112,6 +16475,10 @@ void ConsoleReporter::noMatchingTestCases(std::string const& spec) { stream << "No test cases matched '" << spec << '\'' << std::endl; } +void ConsoleReporter::reportInvalidArguments(std::string const&arg){ + stream << "Invalid Filter: " << arg << std::endl; +} + void ConsoleReporter::assertionStarting(AssertionInfo const&) {} bool ConsoleReporter::assertionEnded(AssertionStats const& _assertionStats) { @@ -13132,6 +16499,7 @@ bool ConsoleReporter::assertionEnded(AssertionStats const& _assertionStats) { } void ConsoleReporter::sectionStarting(SectionInfo const& _sectionInfo) { + m_tablePrinter->close(); m_headerPrinted = false; StreamingReporterBase::sectionStarting(_sectionInfo); } @@ -13146,8 +16514,9 @@ void ConsoleReporter::sectionEnded(SectionStats const& _sectionStats) { stream << "\nNo assertions in test case"; stream << " '" << _sectionStats.sectionInfo.name << "'\n" << std::endl; } - if (m_config->showDurations() == ShowDurations::Always) { - stream << getFormattedDuration(_sectionStats.durationInSeconds) << " s: " << _sectionStats.sectionInfo.name << std::endl; + double dur = _sectionStats.durationInSeconds; + if (shouldShowDuration(*m_config, dur)) { + stream << getFormattedDuration(dur) << " s: " << _sectionStats.sectionInfo.name << std::endl; } if (m_headerPrinted) { m_headerPrinted = false; @@ -13155,28 +16524,53 @@ void ConsoleReporter::sectionEnded(SectionStats const& _sectionStats) { StreamingReporterBase::sectionEnded(_sectionStats); } -void ConsoleReporter::benchmarkStarting(BenchmarkInfo const& info) { - lazyPrintWithoutClosingBenchmarkTable(); +#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING) +void ConsoleReporter::benchmarkPreparing(std::string const& name) { + lazyPrintWithoutClosingBenchmarkTable(); - auto nameCol = Column( info.name ).width( static_cast<std::size_t>( m_tablePrinter->columnInfos()[0].width - 2 ) ); + auto nameCol = Column(name).width(static_cast<std::size_t>(m_tablePrinter->columnInfos()[0].width - 2)); - bool firstLine = true; - for (auto line : nameCol) { - if (!firstLine) - (*m_tablePrinter) << ColumnBreak() << ColumnBreak() << ColumnBreak(); - else - firstLine = false; + bool firstLine = true; + for (auto line : nameCol) { + if (!firstLine) + (*m_tablePrinter) << ColumnBreak() << ColumnBreak() << ColumnBreak(); + else + firstLine = false; + + (*m_tablePrinter) << line << ColumnBreak(); + } +} - (*m_tablePrinter) << line << ColumnBreak(); +void ConsoleReporter::benchmarkStarting(BenchmarkInfo const& info) { + (*m_tablePrinter) << info.samples << ColumnBreak() + << info.iterations << ColumnBreak(); + if (!m_config->benchmarkNoAnalysis()) + (*m_tablePrinter) << Duration(info.estimatedDuration) << ColumnBreak(); +} +void ConsoleReporter::benchmarkEnded(BenchmarkStats<> const& stats) { + if (m_config->benchmarkNoAnalysis()) + { + (*m_tablePrinter) << Duration(stats.mean.point.count()) << ColumnBreak(); + } + else + { + (*m_tablePrinter) << ColumnBreak() + << Duration(stats.mean.point.count()) << ColumnBreak() + << Duration(stats.mean.lower_bound.count()) << ColumnBreak() + << Duration(stats.mean.upper_bound.count()) << ColumnBreak() << ColumnBreak() + << Duration(stats.standardDeviation.point.count()) << ColumnBreak() + << Duration(stats.standardDeviation.lower_bound.count()) << ColumnBreak() + << Duration(stats.standardDeviation.upper_bound.count()) << ColumnBreak() << ColumnBreak() << ColumnBreak() << ColumnBreak() << ColumnBreak(); } } -void ConsoleReporter::benchmarkEnded(BenchmarkStats const& stats) { - Duration average(stats.elapsedTimeInNanoseconds / stats.iterations); + +void ConsoleReporter::benchmarkFailed(std::string const& error) { + Colour colour(Colour::Red); (*m_tablePrinter) - << stats.iterations << ColumnBreak() - << stats.elapsedTimeInNanoseconds << ColumnBreak() - << average << ColumnBreak(); + << "Benchmark failed (" << error << ')' + << ColumnBreak() << RowBreak(); } +#endif // CATCH_CONFIG_ENABLE_BENCHMARKING void ConsoleReporter::testCaseEnded(TestCaseStats const& _testCaseStats) { m_tablePrinter->close(); @@ -13198,6 +16592,10 @@ void ConsoleReporter::testRunEnded(TestRunStats const& _testRunStats) { stream << std::endl; StreamingReporterBase::testRunEnded(_testRunStats); } +void ConsoleReporter::testRunStarting(TestRunInfo const& _testInfo) { + StreamingReporterBase::testRunStarting(_testInfo); + printTestFilters(); +} void ConsoleReporter::lazyPrint() { @@ -13251,11 +16649,9 @@ void ConsoleReporter::printTestCaseAndSectionHeader() { SourceLineInfo lineInfo = m_sectionStack.back().lineInfo; - if (!lineInfo.empty()) { - stream << getLineOfChars<'-'>() << '\n'; - Colour colourGuard(Colour::FileName); - stream << lineInfo << '\n'; - } + stream << getLineOfChars<'-'>() << '\n'; + Colour colourGuard(Colour::FileName); + stream << lineInfo << '\n'; stream << getLineOfChars<'.'>() << '\n' << std::endl; } @@ -13379,6 +16775,13 @@ void ConsoleReporter::printSummaryDivider() { stream << getLineOfChars<'-'>() << '\n'; } +void ConsoleReporter::printTestFilters() { + if (m_config->testSpec().hasFilters()) { + Colour guard(Colour::BrightYellow); + stream << "Filters: " << serializeFilters(m_config->getTestsOrTags()) << '\n'; + } +} + CATCH_REGISTER_REPORTER("console", ConsoleReporter) } // end namespace Catch @@ -13386,6 +16789,10 @@ CATCH_REGISTER_REPORTER("console", ConsoleReporter) #if defined(_MSC_VER) #pragma warning(pop) #endif + +#if defined(__clang__) +# pragma clang diagnostic pop +#endif // end catch_reporter_console.cpp // start catch_reporter_junit.cpp @@ -13393,6 +16800,7 @@ CATCH_REGISTER_REPORTER("console", ConsoleReporter) #include <sstream> #include <ctime> #include <algorithm> +#include <iomanip> namespace Catch { @@ -13420,7 +16828,7 @@ namespace Catch { #else std::strftime(timeStamp, timeStampSize, fmt, timeInfo); #endif - return std::string(timeStamp); + return std::string(timeStamp, timeStampSize-1); } std::string fileNameTag(const std::vector<std::string> &tags) { @@ -13431,6 +16839,17 @@ namespace Catch { return it->substr(1); return std::string(); } + + // Formats the duration in seconds to 3 decimal places. + // This is done because some genius defined Maven Surefire schema + // in a way that only accepts 3 decimal places, and tools like + // Jenkins use that schema for validation JUnit reporter output. + std::string formatDuration( double seconds ) { + ReusableStringStream rss; + rss << std::fixed << std::setprecision( 3 ) << seconds; + return rss.str(); + } + } // anonymous namespace JunitReporter::JunitReporter( ReporterConfig const& _config ) @@ -13490,6 +16909,7 @@ namespace Catch { void JunitReporter::writeGroup( TestGroupNode const& groupNode, double suiteTime ) { XmlWriter::ScopedElement e = xml.scopedElement( "testsuite" ); + TestGroupStats const& stats = groupNode.value; xml.writeAttribute( "name", stats.groupInfo.name ); xml.writeAttribute( "errors", unexpectedExceptions ); @@ -13499,15 +16919,30 @@ namespace Catch { if( m_config->showDurations() == ShowDurations::Never ) xml.writeAttribute( "time", "" ); else - xml.writeAttribute( "time", suiteTime ); + xml.writeAttribute( "time", formatDuration( suiteTime ) ); xml.writeAttribute( "timestamp", getCurrentTimestamp() ); + // Write properties if there are any + if (m_config->hasTestFilters() || m_config->rngSeed() != 0) { + auto properties = xml.scopedElement("properties"); + if (m_config->hasTestFilters()) { + xml.scopedElement("property") + .writeAttribute("name", "filters") + .writeAttribute("value", serializeFilters(m_config->getTestsOrTags())); + } + if (m_config->rngSeed() != 0) { + xml.scopedElement("property") + .writeAttribute("name", "random-seed") + .writeAttribute("value", m_config->rngSeed()); + } + } + // Write test cases for( auto const& child : groupNode.children ) writeTestCase( *child ); - xml.scopedElement( "system-out" ).writeText( trim( stdOutForSuite ), false ); - xml.scopedElement( "system-err" ).writeText( trim( stdErrForSuite ), false ); + xml.scopedElement( "system-out" ).writeText( trim( stdOutForSuite ), XmlFormatting::Newline ); + xml.scopedElement( "system-err" ).writeText( trim( stdErrForSuite ), XmlFormatting::Newline ); } void JunitReporter::writeTestCase( TestCaseNode const& testCaseNode ) { @@ -13529,12 +16964,13 @@ namespace Catch { if ( !m_config->name().empty() ) className = m_config->name() + "." + className; - writeSection( className, "", rootSection ); + writeSection( className, "", rootSection, stats.testInfo.okToFail() ); } - void JunitReporter::writeSection( std::string const& className, - std::string const& rootName, - SectionNode const& sectionNode ) { + void JunitReporter::writeSection( std::string const& className, + std::string const& rootName, + SectionNode const& sectionNode, + bool testOkToFail) { std::string name = trim( sectionNode.stats.sectionInfo.name ); if( !rootName.empty() ) name = rootName + '/' + name; @@ -13551,20 +16987,30 @@ namespace Catch { xml.writeAttribute( "classname", className ); xml.writeAttribute( "name", name ); } - xml.writeAttribute( "time", ::Catch::Detail::stringify( sectionNode.stats.durationInSeconds ) ); + xml.writeAttribute( "time", formatDuration( sectionNode.stats.durationInSeconds ) ); + // This is not ideal, but it should be enough to mimic gtest's + // junit output. + // Ideally the JUnit reporter would also handle `skipTest` + // events and write those out appropriately. + xml.writeAttribute( "status", "run" ); + + if (sectionNode.stats.assertions.failedButOk) { + xml.scopedElement("skipped") + .writeAttribute("message", "TEST_CASE tagged with !mayfail"); + } writeAssertions( sectionNode ); if( !sectionNode.stdOut.empty() ) - xml.scopedElement( "system-out" ).writeText( trim( sectionNode.stdOut ), false ); + xml.scopedElement( "system-out" ).writeText( trim( sectionNode.stdOut ), XmlFormatting::Newline ); if( !sectionNode.stdErr.empty() ) - xml.scopedElement( "system-err" ).writeText( trim( sectionNode.stdErr ), false ); + xml.scopedElement( "system-err" ).writeText( trim( sectionNode.stdErr ), XmlFormatting::Newline ); } for( auto const& childNode : sectionNode.childSections ) if( className.empty() ) - writeSection( name, "", *childNode ); + writeSection( name, "", *childNode, testOkToFail ); else - writeSection( className, name, *childNode ); + writeSection( className, name, *childNode, testOkToFail ); } void JunitReporter::writeAssertions( SectionNode const& sectionNode ) { @@ -13582,11 +17028,7 @@ namespace Catch { elementName = "error"; break; case ResultWas::ExplicitFailure: - elementName = "failure"; - break; case ResultWas::ExpressionFailed: - elementName = "failure"; - break; case ResultWas::DidntThrowException: elementName = "failure"; break; @@ -13604,10 +17046,25 @@ namespace Catch { XmlWriter::ScopedElement e = xml.scopedElement( elementName ); - xml.writeAttribute( "message", result.getExpandedExpression() ); + xml.writeAttribute( "message", result.getExpression() ); xml.writeAttribute( "type", result.getTestMacroName() ); ReusableStringStream rss; + if (stats.totals.assertions.total() > 0) { + rss << "FAILED" << ":\n"; + if (result.hasExpression()) { + rss << " "; + rss << result.getExpressionInMacro(); + rss << '\n'; + } + if (result.hasExpandedExpression()) { + rss << "with expansion:\n"; + rss << Column(result.getExpandedExpression()).indent(2) << '\n'; + } + } else { + rss << '\n'; + } + if( !result.getMessage().empty() ) rss << result.getMessage() << '\n'; for( auto const& msg : stats.infoMessages ) @@ -13615,7 +17072,7 @@ namespace Catch { rss << msg.message << '\n'; rss << "at " << result.getSourceInfo(); - xml.writeText( rss.str(), false ); + xml.writeText( rss.str(), XmlFormatting::Newline ); } } @@ -13659,19 +17116,41 @@ namespace Catch { m_reporter->noMatchingTestCases( spec ); } + void ListeningReporter::reportInvalidArguments(std::string const&arg){ + for ( auto const& listener : m_listeners ) { + listener->reportInvalidArguments( arg ); + } + m_reporter->reportInvalidArguments( arg ); + } + +#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING) + void ListeningReporter::benchmarkPreparing( std::string const& name ) { + for (auto const& listener : m_listeners) { + listener->benchmarkPreparing(name); + } + m_reporter->benchmarkPreparing(name); + } void ListeningReporter::benchmarkStarting( BenchmarkInfo const& benchmarkInfo ) { for ( auto const& listener : m_listeners ) { listener->benchmarkStarting( benchmarkInfo ); } m_reporter->benchmarkStarting( benchmarkInfo ); } - void ListeningReporter::benchmarkEnded( BenchmarkStats const& benchmarkStats ) { + void ListeningReporter::benchmarkEnded( BenchmarkStats<> const& benchmarkStats ) { for ( auto const& listener : m_listeners ) { listener->benchmarkEnded( benchmarkStats ); } m_reporter->benchmarkEnded( benchmarkStats ); } + void ListeningReporter::benchmarkFailed( std::string const& error ) { + for (auto const& listener : m_listeners) { + listener->benchmarkFailed(error); + } + m_reporter->benchmarkFailed(error); + } +#endif // CATCH_CONFIG_ENABLE_BENCHMARKING + void ListeningReporter::testRunStarting( TestRunInfo const& testRunInfo ) { for ( auto const& listener : m_listeners ) { listener->testRunStarting( testRunInfo ); @@ -13802,6 +17281,8 @@ namespace Catch { m_xml.startElement( "Catch" ); if( !m_config->name().empty() ) m_xml.writeAttribute( "name", m_config->name() ); + if (m_config->testSpec().hasFilters()) + m_xml.writeAttribute( "filters", serializeFilters( m_config->getTestsOrTags() ) ); if( m_config->rngSeed() != 0 ) m_xml.scopedElement( "Randomness" ) .writeAttribute( "seed", m_config->rngSeed() ); @@ -13937,9 +17418,9 @@ namespace Catch { e.writeAttribute( "durationInSeconds", m_testCaseTimer.getElapsedSeconds() ); if( !testCaseStats.stdOut.empty() ) - m_xml.scopedElement( "StdOut" ).writeText( trim( testCaseStats.stdOut ), false ); + m_xml.scopedElement( "StdOut" ).writeText( trim( testCaseStats.stdOut ), XmlFormatting::Newline ); if( !testCaseStats.stdErr.empty() ) - m_xml.scopedElement( "StdErr" ).writeText( trim( testCaseStats.stdErr ), false ); + m_xml.scopedElement( "StdErr" ).writeText( trim( testCaseStats.stdErr ), XmlFormatting::Newline ); m_xml.endElement(); } @@ -13951,6 +17432,10 @@ namespace Catch { .writeAttribute( "successes", testGroupStats.totals.assertions.passed ) .writeAttribute( "failures", testGroupStats.totals.assertions.failed ) .writeAttribute( "expectedFailures", testGroupStats.totals.assertions.failedButOk ); + m_xml.scopedElement( "OverallResultsCases") + .writeAttribute( "successes", testGroupStats.totals.testCases.passed ) + .writeAttribute( "failures", testGroupStats.totals.testCases.failed ) + .writeAttribute( "expectedFailures", testGroupStats.totals.testCases.failedButOk ); m_xml.endElement(); } @@ -13960,9 +17445,58 @@ namespace Catch { .writeAttribute( "successes", testRunStats.totals.assertions.passed ) .writeAttribute( "failures", testRunStats.totals.assertions.failed ) .writeAttribute( "expectedFailures", testRunStats.totals.assertions.failedButOk ); + m_xml.scopedElement( "OverallResultsCases") + .writeAttribute( "successes", testRunStats.totals.testCases.passed ) + .writeAttribute( "failures", testRunStats.totals.testCases.failed ) + .writeAttribute( "expectedFailures", testRunStats.totals.testCases.failedButOk ); + m_xml.endElement(); + } + +#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING) + void XmlReporter::benchmarkPreparing(std::string const& name) { + m_xml.startElement("BenchmarkResults") + .writeAttribute("name", name); + } + + void XmlReporter::benchmarkStarting(BenchmarkInfo const &info) { + m_xml.writeAttribute("samples", info.samples) + .writeAttribute("resamples", info.resamples) + .writeAttribute("iterations", info.iterations) + .writeAttribute("clockResolution", info.clockResolution) + .writeAttribute("estimatedDuration", info.estimatedDuration) + .writeComment("All values in nano seconds"); + } + + void XmlReporter::benchmarkEnded(BenchmarkStats<> const& benchmarkStats) { + m_xml.startElement("mean") + .writeAttribute("value", benchmarkStats.mean.point.count()) + .writeAttribute("lowerBound", benchmarkStats.mean.lower_bound.count()) + .writeAttribute("upperBound", benchmarkStats.mean.upper_bound.count()) + .writeAttribute("ci", benchmarkStats.mean.confidence_interval); + m_xml.endElement(); + m_xml.startElement("standardDeviation") + .writeAttribute("value", benchmarkStats.standardDeviation.point.count()) + .writeAttribute("lowerBound", benchmarkStats.standardDeviation.lower_bound.count()) + .writeAttribute("upperBound", benchmarkStats.standardDeviation.upper_bound.count()) + .writeAttribute("ci", benchmarkStats.standardDeviation.confidence_interval); + m_xml.endElement(); + m_xml.startElement("outliers") + .writeAttribute("variance", benchmarkStats.outlierVariance) + .writeAttribute("lowMild", benchmarkStats.outliers.low_mild) + .writeAttribute("lowSevere", benchmarkStats.outliers.low_severe) + .writeAttribute("highMild", benchmarkStats.outliers.high_mild) + .writeAttribute("highSevere", benchmarkStats.outliers.high_severe); + m_xml.endElement(); m_xml.endElement(); } + void XmlReporter::benchmarkFailed(std::string const &error) { + m_xml.scopedElement("failed"). + writeAttribute("message", error); + m_xml.endElement(); + } +#endif // CATCH_CONFIG_ENABLE_BENCHMARKING + CATCH_REGISTER_REPORTER( "xml", XmlReporter ) } // end namespace Catch @@ -13988,7 +17522,7 @@ namespace Catch { #ifndef __OBJC__ -#if defined(CATCH_CONFIG_WCHAR) && defined(WIN32) && defined(_UNICODE) && !defined(DO_NOT_USE_WMAIN) +#if defined(CATCH_CONFIG_WCHAR) && defined(CATCH_PLATFORM_WINDOWS) && defined(_UNICODE) && !defined(DO_NOT_USE_WMAIN) // Standard C/C++ Win32 Unicode wmain entry point extern "C" int wmain (int argc, wchar_t * argv[], wchar_t * []) { #else @@ -14036,7 +17570,7 @@ int main (int argc, char * const argv[]) { #define CATCH_REQUIRE( ... ) INTERNAL_CATCH_TEST( "CATCH_REQUIRE", Catch::ResultDisposition::Normal, __VA_ARGS__ ) #define CATCH_REQUIRE_FALSE( ... ) INTERNAL_CATCH_TEST( "CATCH_REQUIRE_FALSE", Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, __VA_ARGS__ ) -#define CATCH_REQUIRE_THROWS( ... ) INTERNAL_CATCH_THROWS( "CATCH_REQUIRE_THROWS", Catch::ResultDisposition::Normal, "", __VA_ARGS__ ) +#define CATCH_REQUIRE_THROWS( ... ) INTERNAL_CATCH_THROWS( "CATCH_REQUIRE_THROWS", Catch::ResultDisposition::Normal, __VA_ARGS__ ) #define CATCH_REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "CATCH_REQUIRE_THROWS_AS", exceptionType, Catch::ResultDisposition::Normal, expr ) #define CATCH_REQUIRE_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS_STR_MATCHES( "CATCH_REQUIRE_THROWS_WITH", Catch::ResultDisposition::Normal, matcher, expr ) #if !defined(CATCH_CONFIG_DISABLE_MATCHERS) @@ -14050,7 +17584,7 @@ int main (int argc, char * const argv[]) { #define CATCH_CHECKED_ELSE( ... ) INTERNAL_CATCH_ELSE( "CATCH_CHECKED_ELSE", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) #define CATCH_CHECK_NOFAIL( ... ) INTERNAL_CATCH_TEST( "CATCH_CHECK_NOFAIL", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, __VA_ARGS__ ) -#define CATCH_CHECK_THROWS( ... ) INTERNAL_CATCH_THROWS( "CATCH_CHECK_THROWS", Catch::ResultDisposition::ContinueOnFailure, "", __VA_ARGS__ ) +#define CATCH_CHECK_THROWS( ... ) INTERNAL_CATCH_THROWS( "CATCH_CHECK_THROWS", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) #define CATCH_CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "CATCH_CHECK_THROWS_AS", exceptionType, Catch::ResultDisposition::ContinueOnFailure, expr ) #define CATCH_CHECK_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS_STR_MATCHES( "CATCH_CHECK_THROWS_WITH", Catch::ResultDisposition::ContinueOnFailure, matcher, expr ) #if !defined(CATCH_CONFIG_DISABLE_MATCHERS) @@ -14065,6 +17599,7 @@ int main (int argc, char * const argv[]) { #endif // CATCH_CONFIG_DISABLE_MATCHERS #define CATCH_INFO( msg ) INTERNAL_CATCH_INFO( "CATCH_INFO", msg ) +#define CATCH_UNSCOPED_INFO( msg ) INTERNAL_CATCH_UNSCOPED_INFO( "CATCH_UNSCOPED_INFO", msg ) #define CATCH_WARN( msg ) INTERNAL_CATCH_MSG( "CATCH_WARN", Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, msg ) #define CATCH_CAPTURE( ... ) INTERNAL_CATCH_CAPTURE( INTERNAL_CATCH_UNIQUE_NAME(capturer), "CATCH_CAPTURE",__VA_ARGS__ ) @@ -14082,10 +17617,22 @@ int main (int argc, char * const argv[]) { #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR #define CATCH_TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ ) +#define CATCH_TEMPLATE_TEST_CASE_SIG( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG( __VA_ARGS__ ) #define CATCH_TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ ) +#define CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( className, __VA_ARGS__ ) +#define CATCH_TEMPLATE_PRODUCT_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE( __VA_ARGS__ ) +#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG( ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG( __VA_ARGS__ ) +#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, __VA_ARGS__ ) +#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, __VA_ARGS__ ) #else #define CATCH_TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ ) ) +#define CATCH_TEMPLATE_TEST_CASE_SIG( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG( __VA_ARGS__ ) ) #define CATCH_TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ ) ) +#define CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( className, __VA_ARGS__ ) ) +#define CATCH_TEMPLATE_PRODUCT_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE( __VA_ARGS__ ) ) +#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG( __VA_ARGS__ ) ) +#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, __VA_ARGS__ ) ) +#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, __VA_ARGS__ ) ) #endif #if !defined(CATCH_CONFIG_RUNTIME_STATIC_REQUIRE) @@ -14106,6 +17653,13 @@ int main (int argc, char * const argv[]) { #define CATCH_THEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " Then: " << desc ) #define CATCH_AND_THEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " And: " << desc ) +#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING) +#define CATCH_BENCHMARK(...) \ + INTERNAL_CATCH_BENCHMARK(INTERNAL_CATCH_UNIQUE_NAME(C_A_T_C_H_B_E_N_C_H_), INTERNAL_CATCH_GET_1_ARG(__VA_ARGS__,,), INTERNAL_CATCH_GET_2_ARG(__VA_ARGS__,,)) +#define CATCH_BENCHMARK_ADVANCED(name) \ + INTERNAL_CATCH_BENCHMARK_ADVANCED(INTERNAL_CATCH_UNIQUE_NAME(C_A_T_C_H_B_E_N_C_H_), name) +#endif // CATCH_CONFIG_ENABLE_BENCHMARKING + // If CATCH_CONFIG_PREFIX_ALL is not defined then the CATCH_ prefix is not required #else @@ -14141,6 +17695,7 @@ int main (int argc, char * const argv[]) { #endif // CATCH_CONFIG_DISABLE_MATCHERS #define INFO( msg ) INTERNAL_CATCH_INFO( "INFO", msg ) +#define UNSCOPED_INFO( msg ) INTERNAL_CATCH_UNSCOPED_INFO( "UNSCOPED_INFO", msg ) #define WARN( msg ) INTERNAL_CATCH_MSG( "WARN", Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, msg ) #define CAPTURE( ... ) INTERNAL_CATCH_CAPTURE( INTERNAL_CATCH_UNIQUE_NAME(capturer), "CAPTURE",__VA_ARGS__ ) @@ -14157,10 +17712,26 @@ int main (int argc, char * const argv[]) { #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR #define TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ ) +#define TEMPLATE_TEST_CASE_SIG( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG( __VA_ARGS__ ) #define TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ ) +#define TEMPLATE_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( className, __VA_ARGS__ ) +#define TEMPLATE_PRODUCT_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE( __VA_ARGS__ ) +#define TEMPLATE_PRODUCT_TEST_CASE_SIG( ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG( __VA_ARGS__ ) +#define TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, __VA_ARGS__ ) +#define TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, __VA_ARGS__ ) +#define TEMPLATE_LIST_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE(__VA_ARGS__) +#define TEMPLATE_LIST_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_METHOD( className, __VA_ARGS__ ) #else #define TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ ) ) +#define TEMPLATE_TEST_CASE_SIG( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG( __VA_ARGS__ ) ) #define TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ ) ) +#define TEMPLATE_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( className, __VA_ARGS__ ) ) +#define TEMPLATE_PRODUCT_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE( __VA_ARGS__ ) ) +#define TEMPLATE_PRODUCT_TEST_CASE_SIG( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG( __VA_ARGS__ ) ) +#define TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, __VA_ARGS__ ) ) +#define TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, __VA_ARGS__ ) ) +#define TEMPLATE_LIST_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE( __VA_ARGS__ ) ) +#define TEMPLATE_LIST_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_METHOD( className, __VA_ARGS__ ) ) #endif #if !defined(CATCH_CONFIG_RUNTIME_STATIC_REQUIRE) @@ -14186,6 +17757,13 @@ int main (int argc, char * const argv[]) { #define THEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " Then: " << desc ) #define AND_THEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " And: " << desc ) +#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING) +#define BENCHMARK(...) \ + INTERNAL_CATCH_BENCHMARK(INTERNAL_CATCH_UNIQUE_NAME(C_A_T_C_H_B_E_N_C_H_), INTERNAL_CATCH_GET_1_ARG(__VA_ARGS__,,), INTERNAL_CATCH_GET_2_ARG(__VA_ARGS__,,)) +#define BENCHMARK_ADVANCED(name) \ + INTERNAL_CATCH_BENCHMARK_ADVANCED(INTERNAL_CATCH_UNIQUE_NAME(C_A_T_C_H_B_E_N_C_H_), name) +#endif // CATCH_CONFIG_ENABLE_BENCHMARKING + using Catch::Detail::Approx; #else // CATCH_CONFIG_DISABLE @@ -14225,12 +17803,13 @@ using Catch::Detail::Approx; #define CATCH_REQUIRE_THAT( arg, matcher ) (void)(0) #endif // CATCH_CONFIG_DISABLE_MATCHERS -#define CATCH_INFO( msg ) (void)(0) -#define CATCH_WARN( msg ) (void)(0) -#define CATCH_CAPTURE( msg ) (void)(0) +#define CATCH_INFO( msg ) (void)(0) +#define CATCH_UNSCOPED_INFO( msg ) (void)(0) +#define CATCH_WARN( msg ) (void)(0) +#define CATCH_CAPTURE( msg ) (void)(0) -#define CATCH_TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )) -#define CATCH_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )) +#define CATCH_TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_S_T_ )) +#define CATCH_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_S_T_ )) #define CATCH_METHOD_AS_TEST_CASE( method, ... ) #define CATCH_REGISTER_TEST_CASE( Function, ... ) (void)(0) #define CATCH_SECTION( ... ) @@ -14239,19 +17818,31 @@ using Catch::Detail::Approx; #define CATCH_FAIL_CHECK( ... ) (void)(0) #define CATCH_SUCCEED( ... ) (void)(0) -#define CATCH_ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )) +#define CATCH_ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_S_T_ )) #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR -#define CATCH_TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ) ) -#define CATCH_TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), className ) +#define CATCH_TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(__VA_ARGS__) +#define CATCH_TEMPLATE_TEST_CASE_SIG( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG_NO_REGISTRATION(__VA_ARGS__) +#define CATCH_TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION(className, __VA_ARGS__) +#define CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG_NO_REGISTRATION(className, __VA_ARGS__ ) +#define CATCH_TEMPLATE_PRODUCT_TEST_CASE( ... ) CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ ) +#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG( ... ) CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ ) +#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ ) +#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, ... ) CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ ) #else -#define CATCH_TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ) ) ) -#define CATCH_TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), className ) ) +#define CATCH_TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(__VA_ARGS__) ) +#define CATCH_TEMPLATE_TEST_CASE_SIG( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG_NO_REGISTRATION(__VA_ARGS__) ) +#define CATCH_TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION(className, __VA_ARGS__ ) ) +#define CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG_NO_REGISTRATION(className, __VA_ARGS__ ) ) +#define CATCH_TEMPLATE_PRODUCT_TEST_CASE( ... ) CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ ) +#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG( ... ) CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ ) +#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ ) +#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, ... ) CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ ) #endif // "BDD-style" convenience wrappers -#define CATCH_SCENARIO( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )) -#define CATCH_SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_METHOD_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), className ) +#define CATCH_SCENARIO( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_S_T_ )) +#define CATCH_SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_METHOD_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_S_T_ ), className ) #define CATCH_GIVEN( desc ) #define CATCH_AND_GIVEN( desc ) #define CATCH_WHEN( desc ) @@ -14297,11 +17888,12 @@ using Catch::Detail::Approx; #endif // CATCH_CONFIG_DISABLE_MATCHERS #define INFO( msg ) (void)(0) +#define UNSCOPED_INFO( msg ) (void)(0) #define WARN( msg ) (void)(0) #define CAPTURE( msg ) (void)(0) -#define TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )) -#define TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )) +#define TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_S_T_ )) +#define TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_S_T_ )) #define METHOD_AS_TEST_CASE( method, ... ) #define REGISTER_TEST_CASE( Function, ... ) (void)(0) #define SECTION( ... ) @@ -14309,14 +17901,26 @@ using Catch::Detail::Approx; #define FAIL( ... ) (void)(0) #define FAIL_CHECK( ... ) (void)(0) #define SUCCEED( ... ) (void)(0) -#define ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )) +#define ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_S_T_ )) #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR -#define TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ) ) -#define TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), className ) +#define TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(__VA_ARGS__) +#define TEMPLATE_TEST_CASE_SIG( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG_NO_REGISTRATION(__VA_ARGS__) +#define TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION(className, __VA_ARGS__) +#define TEMPLATE_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG_NO_REGISTRATION(className, __VA_ARGS__ ) +#define TEMPLATE_PRODUCT_TEST_CASE( ... ) TEMPLATE_TEST_CASE( __VA_ARGS__ ) +#define TEMPLATE_PRODUCT_TEST_CASE_SIG( ... ) TEMPLATE_TEST_CASE( __VA_ARGS__ ) +#define TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ ) +#define TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, ... ) TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ ) #else -#define TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ) ) ) -#define TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), className ) ) +#define TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(__VA_ARGS__) ) +#define TEMPLATE_TEST_CASE_SIG( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG_NO_REGISTRATION(__VA_ARGS__) ) +#define TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION(className, __VA_ARGS__ ) ) +#define TEMPLATE_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG_NO_REGISTRATION(className, __VA_ARGS__ ) ) +#define TEMPLATE_PRODUCT_TEST_CASE( ... ) TEMPLATE_TEST_CASE( __VA_ARGS__ ) +#define TEMPLATE_PRODUCT_TEST_CASE_SIG( ... ) TEMPLATE_TEST_CASE( __VA_ARGS__ ) +#define TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ ) +#define TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, ... ) TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ ) #endif #define STATIC_REQUIRE( ... ) (void)(0) @@ -14327,8 +17931,8 @@ using Catch::Detail::Approx; #define CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION_NO_REG( INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator ), signature ) // "BDD-style" convenience wrappers -#define SCENARIO( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ) ) -#define SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_METHOD_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), className ) +#define SCENARIO( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_S_T_ ) ) +#define SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_METHOD_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_S_T_ ), className ) #define GIVEN( desc ) #define AND_GIVEN( desc ) diff --git a/third_party/gsl-disable-gsl-suppress.patch b/third_party/gsl-disable-gsl-suppress.patch new file mode 100644 index 0000000..fb1a126 --- /dev/null +++ b/third_party/gsl-disable-gsl-suppress.patch @@ -0,0 +1,11 @@ +--- a/include/gsl/gsl-lite.hpp ++++ b/include/gsl/gsl-lite.hpp +@@ -1081,7 +1081,7 @@ namespace __cxxabiv1 { struct __cxa_eh_globals; extern "C" __cxa_eh_globals * __ + // MSVC warning suppression macros: + + #if gsl_COMPILER_MSVC_VERSION >= 140 && ! gsl_COMPILER_NVCC_VERSION +-# define gsl_SUPPRESS_MSGSL_WARNING(expr) [[gsl::suppress(expr)]] ++# define gsl_SUPPRESS_MSGSL_WARNING(expr) /* Pimm: note disabled for intel [[gsl::suppress(expr)]]*/ + # define gsl_SUPPRESS_MSVC_WARNING(code, descr) __pragma(warning(suppress: code) ) + # define gsl_DISABLE_MSVC_WARNINGS(codes) __pragma(warning(push)) __pragma(warning(disable: codes)) + # define gsl_RESTORE_MSVC_WARNINGS() __pragma(warning(pop )) diff --git a/third_party/gsl.h b/third_party/gsl.h index 0d79484..1bfa97f 100755..100644 --- a/third_party/gsl.h +++ b/third_party/gsl.h @@ -1,6 +1,6 @@ // -// gsl-lite is based on GSL: Guideline Support Library. -// For more information see https://github.com/martinmoene/gsl-lite +// gsl-lite is based on GSL: Guidelines Support Library. +// For more information see https://github.com/gsl-lite/gsl-lite // // Copyright (c) 2015 Martin Moene // Copyright (c) 2015 Microsoft Corporation. All rights reserved. @@ -17,11 +17,11 @@ // mimic MS include hierarchy -#pragma once - #ifndef GSL_GSL_H_INCLUDED #define GSL_GSL_H_INCLUDED -#include "gsl/gsl-lite.h" +#pragma message ("gsl.h is deprecated since version 0.27.0, use gsl/gsl-lite.hpp instead.") + +#include "gsl/gsl-lite.hpp" #endif // GSL_GSL_H_INCLUDED diff --git a/third_party/gsl/gsl b/third_party/gsl/gsl index 339bd31..7ef52ac 100755..100644 --- a/third_party/gsl/gsl +++ b/third_party/gsl/gsl @@ -1,5 +1,5 @@ // -// gsl-lite is based on GSL: Guideline Support Library. +// gsl-lite is based on GSL: Guidelines Support Library. // For more information see https://github.com/martinmoene/gsl-lite // // Copyright (c) 2015 Martin Moene @@ -22,6 +22,8 @@ #ifndef GSL_GSL_H_INCLUDED #define GSL_GSL_H_INCLUDED -#include "gsl-lite.h" +#pragma message ("gsl/gsl is deprecated since version 0.38.1, use gsl/gsl-lite.hpp instead.") + +#include "gsl-lite.hpp" #endif // GSL_GSL_H_INCLUDED diff --git a/third_party/gsl/gsl-lite-vc6.h b/third_party/gsl/gsl-lite-vc6.hpp index 96b1904..3579336 100755..100644 --- a/third_party/gsl/gsl-lite-vc6.h +++ b/third_party/gsl/gsl-lite-vc6.hpp @@ -1,6 +1,6 @@ // -// gsl-lite-vc6 is based on GSL: Guideline Support Library, -// For more information see https://github.com/martinmoene/gsl-lite +// gsl-lite-vc6 is based on GSL: Guidelines Support Library, +// For more information see https://github.com/gsl-lite/gsl-lite // // Copyright (c) 2015 Martin Moene // Copyright (c) 2015 Microsoft Corporation. All rights reserved. @@ -33,20 +33,20 @@ // Configuration: -#ifndef gsl_FEATURE_HAVE_IMPLICIT_MACRO -# define gsl_FEATURE_HAVE_IMPLICIT_MACRO 1 +#ifndef gsl_FEATURE_IMPLICIT_MACRO +# define gsl_FEATURE_IMPLICIT_MACRO 1 #endif -#ifndef gsl_FEATURE_HAVE_OWNER_MACRO -# define gsl_FEATURE_HAVE_OWNER_MACRO 1 +#ifndef gsl_FEATURE_OWNER_MACRO +# define gsl_FEATURE_OWNER_MACRO 1 #endif -#ifndef gsl_FEATURE_HAVE_SHARED_PTR -# define gsl_FEATURE_HAVE_SHARED_PTR 0 +#ifndef gsl_FEATURE_SHARED_PTR +# define gsl_FEATURE_SHARED_PTR 0 #endif -#ifndef gsl_FEATURE_HAVE_UNIQUE_PTR -# define gsl_FEATURE_HAVE_UNIQUE_PTR 0 +#ifndef gsl_FEATURE_UNIQUE_PTR +# define gsl_FEATURE_UNIQUE_PTR 0 #endif #ifndef gsl_CONFIG_THROWS_FOR_TESTING @@ -75,35 +75,37 @@ // Compiler detection: -#if defined(_MSC_VER) -# define gsl_COMPILER_MSVC_VERSION (_MSC_VER / 100 - 5 - (_MSC_VER < 1900)) +#if defined(_MSC_VER ) && !defined(__clang__) +# define gsl_COMPILER_MSVC_VER (_MSC_VER ) +# define gsl_COMPILER_MSVC_VERSION (_MSC_VER / 10 - 10 * ( 5 + (_MSC_VER < 1900 ) ) ) #else +# define gsl_COMPILER_MSVC_VER 0 # define gsl_COMPILER_MSVC_VERSION 0 # define gsl_COMPILER_NON_MSVC 1 #endif -#if gsl_COMPILER_MSVC_VERSION != 6 +#if gsl_COMPILER_MSVC_VERSION != 60 # error GSL Lite: this header is for Visual C++ 6 #endif // half-open range [lo..hi): -#define gsl_BETWEEN( v, lo, hi ) ( lo <= v && v < hi ) +#define gsl_BETWEEN( v, lo, hi ) ( (lo) <= (v) && (v) < (hi) ) // Presence of C++ language features: // C++ feature usage: -#if gsl_FEATURE_HAVE_IMPLICIT_MACRO +#if gsl_FEATURE_IMPLICIT_MACRO # define implicit #endif #define gsl_DIMENSION_OF( a ) ( sizeof(a) / sizeof(0[a]) ) -#if gsl_FEATURE_HAVE_SHARED_PTR +#if gsl_FEATURE_SHARED_PTR # include gsl_CONFIG_SHARED_PTR_INCLUDE #endif -#if gsl_FEATURE_HAVE_UNIQUE_PTR +#if gsl_FEATURE_UNIQUE_PTR # include gsl_CONFIG_UNIQUE_PTR_INCLUDE #endif @@ -113,10 +115,10 @@ namespace gsl { // GSL.owner: ownership pointers // // ToDo: -#if gsl_FEATURE_HAVE_SHARED_PTR +#if gsl_FEATURE_SHARED_PTR using gsl_CONFIG_SHARED_PTR_DECL; #endif -#if gsl_FEATURE_HAVE_UNIQUE_PTR +#if gsl_FEATURE_UNIQUE_PTR using gsl_CONFIG_UNIQUE_PTR_DECL; #endif @@ -124,7 +126,7 @@ template< class T > struct owner { typedef T type; }; #define gsl_HAVE_OWNER_TEMPLATE 0 -#if gsl_FEATURE_HAVE_OWNER_MACRO +#if gsl_FEATURE_OWNER_MACRO # define Owner(t) ::gsl::owner<t>::type #endif @@ -177,15 +179,15 @@ inline void fail_fast_assert( bool cond, char const * const ) // GSL.util: utilities // -class final_act +class final_action { public: typedef void (*Action)(); - final_act( Action action ) + final_action( Action action ) : action_( action ) {} - ~final_act() + ~final_action() { action_(); } @@ -195,9 +197,9 @@ private: }; template< class Fn > -final_act finally( Fn const & f ) +final_action finally( Fn const & f ) { - return final_act(( f )); + return final_action(( f )); } template< class T, class U > @@ -655,7 +657,7 @@ namespace detail { template<class T, class SizeType, const T Sentinel> struct ensure { - static span<T> sentinel( T * seq, SizeType max = std::numeric_limits<SizeType>::max() ) + static span<T> sentinel( T * seq, SizeType max = (std::numeric_limits<SizeType>::max)() ) { typedef T * pointer; typedef typename std::iterator_traits<pointer>::difference_type difference_type; @@ -679,7 +681,7 @@ struct ensure // template< typename T > -span<T> ensure_z( T * sz, size_t max = std::numeric_limits<size_t>::max() ) +span<T> ensure_z( T * sz, size_t max = (std::numeric_limits<size_t>::max)() ) { return detail::ensure<T, size_t, 0>::sentinel( sz, max ); } diff --git a/third_party/gsl/gsl-lite.h b/third_party/gsl/gsl-lite.h index aae4b3e..a738253 100755..100644 --- a/third_party/gsl/gsl-lite.h +++ b/third_party/gsl/gsl-lite.h @@ -1,2251 +1,27 @@ // -// gsl-lite is based on GSL: Guideline Support Library. -// For more information see https://github.com/martinmoene/gsl-lite +// gsl-lite is based on GSL: Guidelines Support Library. +// For more information see https://github.com/gsl-lite/gsl-lite // // Copyright (c) 2015 Martin Moene -// Copyright (c) 2015 Microsoft Corporation. All rights reserved. -// -// This code is licensed under the MIT License (MIT). -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#pragma once +// Copyright (c) 2015 Microsoft Corporation. All rights reserved. +// +// This code is licensed under the MIT License (MIT). +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +// mimic MS include hierarchy #ifndef GSL_GSL_LITE_H_INCLUDED #define GSL_GSL_LITE_H_INCLUDED -#include <exception> -#include <iterator> -#include <limits> -#include <memory> -#include <ostream> -#include <stdexcept> -#include <string> -#include <utility> -#include <vector> - -#define gsl_lite_VERSION "0.22.0" - -// gsl-lite backward compatibility: - -#ifdef gsl_CONFIG_ALLOWS_SPAN_CONTAINER_CTOR -# define gsl_CONFIG_ALLOWS_UNCONSTRAINED_SPAN_CONTAINER_CTOR gsl_CONFIG_ALLOWS_SPAN_CONTAINER_CTOR -# pragma message ("gsl_CONFIG_ALLOWS_SPAN_CONTAINER_CTOR is deprecated since gsl-lite 0.7.0; replace with gsl_CONFIG_ALLOWS_UNCONSTRAINED_SPAN_CONTAINER_CTOR, or consider span(with_container, cont).") -#endif - -// M-GSL compatibility: - -#if defined( GSL_THROW_ON_CONTRACT_VIOLATION ) -# define gsl_CONFIG_CONTRACT_VIOLATION_THROWS 1 -#endif - -#if defined( GSL_TERMINATE_ON_CONTRACT_VIOLATION ) -# define gsl_CONFIG_CONTRACT_VIOLATION_THROWS 0 -#endif - -#if defined( GSL_UNENFORCED_ON_CONTRACT_VIOLATION ) -# define gsl_CONFIG_CONTRACT_LEVEL_OFF 1 -#endif - -// Configuration: - -#ifndef gsl_FEATURE_HAVE_IMPLICIT_MACRO -# define gsl_FEATURE_HAVE_IMPLICIT_MACRO 1 -#endif - -#ifndef gsl_FEATURE_HAVE_OWNER_MACRO -# define gsl_FEATURE_HAVE_OWNER_MACRO 1 -#endif - -#ifndef gsl_FEATURE_EXPERIMENTAL_RETURN_GUARD -# define gsl_FEATURE_EXPERIMENTAL_RETURN_GUARD 0 -#endif - -#ifndef gsl_CONFIG_SPAN_INDEX_TYPE -# define gsl_CONFIG_SPAN_INDEX_TYPE size_t -#endif - -#ifndef gsl_CONFIG_CONFIRMS_COMPILATION_ERRORS -# define gsl_CONFIG_CONFIRMS_COMPILATION_ERRORS 0 -#endif - -#ifndef gsl_CONFIG_ALLOWS_NONSTRICT_SPAN_COMPARISON -# define gsl_CONFIG_ALLOWS_NONSTRICT_SPAN_COMPARISON 1 -#endif - -#ifndef gsl_CONFIG_ALLOWS_UNCONSTRAINED_SPAN_CONTAINER_CTOR -# define gsl_CONFIG_ALLOWS_UNCONSTRAINED_SPAN_CONTAINER_CTOR 0 -#endif - -#if defined( gsl_CONFIG_CONTRACT_LEVEL_ON ) -# define gsl_CONFIG_CONTRACT_LEVEL_MASK 0x11 -#elif defined( gsl_CONFIG_CONTRACT_LEVEL_OFF ) -# define gsl_CONFIG_CONTRACT_LEVEL_MASK 0x00 -#elif defined( gsl_CONFIG_CONTRACT_LEVEL_EXPECTS_ONLY ) -# define gsl_CONFIG_CONTRACT_LEVEL_MASK 0x01 -#elif defined( gsl_CONFIG_CONTRACT_LEVEL_ENSURES_ONLY ) -# define gsl_CONFIG_CONTRACT_LEVEL_MASK 0x10 -#else -# define gsl_CONFIG_CONTRACT_LEVEL_MASK 0x11 -#endif - -#if !defined( gsl_CONFIG_CONTRACT_VIOLATION_THROWS ) && \ - !defined( gsl_CONFIG_CONTRACT_VIOLATION_TERMINATES ) -# define gsl_CONFIG_CONTRACT_VIOLATION_THROWS_V 0 -#elif defined( gsl_CONFIG_CONTRACT_VIOLATION_THROWS ) && \ - !defined( gsl_CONFIG_CONTRACT_VIOLATION_TERMINATES ) -# define gsl_CONFIG_CONTRACT_VIOLATION_THROWS_V 1 -#elif !defined( gsl_CONFIG_CONTRACT_VIOLATION_THROWS ) && \ - defined( gsl_CONFIG_CONTRACT_VIOLATION_TERMINATES ) -# define gsl_CONFIG_CONTRACT_VIOLATION_THROWS_V 0 -#else -# error only one of gsl_CONFIG_CONTRACT_VIOLATION_THROWS and gsl_CONFIG_CONTRACT_VIOLATION_TERMINATES may be defined. -#endif - -// Compiler detection (C++17 is speculative): - -#define gsl_CPP11_OR_GREATER ( __cplusplus >= 201103L ) -#define gsl_CPP14_OR_GREATER ( __cplusplus >= 201402L ) -#define gsl_CPP17_OR_GREATER ( __cplusplus >= 201700L ) - -// half-open range [lo..hi): -#define gsl_BETWEEN( v, lo, hi ) ( lo <= v && v < hi ) - -#if defined(_MSC_VER) && !defined(__clang__) -# define gsl_COMPILER_MSVC_VERSION (_MSC_VER / 100 - 5 - (_MSC_VER < 1900)) -#else -# define gsl_COMPILER_MSVC_VERSION 0 -# define gsl_COMPILER_NON_MSVC 1 -#endif - -// Note: simplistic version computation; works for GCC versions on http://godbolt.org/ -#if defined(__GNUC__) && !defined(__clang__) -# define gsl_COMPILER_GCC_VERSION ( 10 * (10 *__GNUC__ + __GNUC_MINOR__) + __GNUC_PATCHLEVEL__) -#else -# define gsl_COMPILER_GCC_VERSION 0 -#endif - -// Presence of C++11 language features: - -#if gsl_CPP11_OR_GREATER || gsl_COMPILER_MSVC_VERSION >= 10 -# define gsl_HAVE_AUTO 1 -# define gsl_HAVE_NULLPTR 1 -#endif - -#if gsl_CPP11_OR_GREATER || gsl_COMPILER_MSVC_VERSION >= 12 -# define gsl_HAVE_DEFAULT_FUNCTION_TEMPLATE_ARG 1 -#endif - -#if gsl_CPP11_OR_GREATER || gsl_COMPILER_MSVC_VERSION >= 14 -# define gsl_HAVE_ALIAS_TEMPLATE 1 -# define gsl_HAVE_CONSTEXPR_11 1 -# define gsl_HAVE_ENUM_CLASS 1 -# define gsl_HAVE_EXPLICIT_CONVERSION 1 -# define gsl_HAVE_INITIALIZER_LIST 1 -# define gsl_HAVE_IS_DEFAULT 1 -# define gsl_HAVE_IS_DELETE 1 -# define gsl_HAVE_NOEXCEPT 1 -#endif - -#if gsl_CPP11_OR_GREATER -// see above -#endif - -// Presence of C++14 language features: - -#if gsl_CPP14_OR_GREATER -# define gsl_HAVE_CONSTEXPR_14 1 -#endif - -// Presence of C++17 language features: - -#if gsl_CPP17_OR_GREATER -# define gsl_HAVE_ENUM_CLASS_CONSTRUCTION_FROM_UNDERLYING_TYPE 1 -#endif - -// Presence of C++ library features: - -#if gsl_COMPILER_GCC_VERSION -# define gsl_HAVE_TR1_TYPE_TRAITS 1 -#endif - -#if gsl_CPP11_OR_GREATER || gsl_COMPILER_MSVC_VERSION >= 11 -# define gsl_HAVE_ARRAY 1 -# define gsl_HAVE_TR1_TYPE_TRAITS 1 -#endif - -#if gsl_CPP11_OR_GREATER || gsl_COMPILER_MSVC_VERSION >= 14 || (gsl_COMPILER_MSVC_VERSION >= 9 && _HAS_CPP0X) -# define gsl_HAVE_CONTAINER_DATA_METHOD 1 -#endif - -#if gsl_CPP11_OR_GREATER || gsl_COMPILER_MSVC_VERSION >= 14 -# define gsl_HAVE_SIZED_TYPES 1 -#endif - -#if gsl_CPP11_OR_GREATER || gsl_COMPILER_MSVC_VERSION >= 14 || (gsl_COMPILER_MSVC_VERSION >= 10 && _HAS_CPP0X) -# define gsl_HAVE_SHARED_PTR 1 -# define gsl_HAVE_UNIQUE_PTR 1 -#endif - -#if gsl_CPP14_OR_GREATER || gsl_COMPILER_MSVC_VERSION >= 12 -# define gsl_HAVE_MAKE_UNIQUE 1 -#endif - -#if gsl_CPP11_OR_GREATER || gsl_COMPILER_MSVC_VERSION >= 11 -# define gsl_HAVE_TYPE_TRAITS 1 -#endif - -#if gsl_HAVE_TYPE_TRAITS -# define gsl_HAVE_ADD_CONST 1 -# define gsl_HAVE_INTEGRAL_CONSTANT 1 -# define gsl_HAVE_REMOVE_REFERENCE 1 -#elif gsl_HAVE_TR1_TYPE_TRAITS -# define gsl_HAVE_TR1_ADD_CONST 1 -# define gsl_HAVE_TR1_INTEGRAL_CONSTANT 1 -# define gsl_HAVE_TR1_REMOVE_REFERENCE 1 -#endif - -// For the rest, consider VC12, VC14 as C++11 for GSL Lite: - -#if gsl_COMPILER_MSVC_VERSION >= 12 -# undef gsl_CPP11_OR_GREATER -# define gsl_CPP11_OR_GREATER 1 -#endif - -// C++ feature usage: - -#if gsl_HAVE_CONSTEXPR_11 -# define gsl_constexpr constexpr -#else -# define gsl_constexpr /*constexpr*/ -#endif - -#if gsl_HAVE_CONSTEXPR_14 -# define gsl_constexpr14 constexpr -#else -# define gsl_constexpr14 /*constexpr*/ -#endif - -#if gsl_HAVE_EXPLICIT_CONVERSION -# define gsl_explicit explicit -#else -# define gsl_explicit /*explicit*/ -#endif - -#if gsl_FEATURE_HAVE_IMPLICIT_MACRO -# define implicit /*implicit*/ -#endif - -#if !gsl_HAVE_NOEXCEPT || gsl_CONFIG_CONTRACT_VIOLATION_THROWS_V -# define gsl_noexcept /*noexcept*/ -#else -# define gsl_noexcept noexcept -#endif - -#if gsl_HAVE_NULLPTR -# define gsl_nullptr nullptr -#else -# define gsl_nullptr NULL -#endif - -#define gsl_DIMENSION_OF( a ) ( sizeof(a) / sizeof(0[a]) ) - -// Other features: - -#if gsl_HAVE_DEFAULT_FUNCTION_TEMPLATE_ARG && gsl_HAVE_CONTAINER_DATA_METHOD -# define gsl_HAVE_CONSTRAINED_SPAN_CONTAINER_CTOR 1 -#endif - -// Note: !defined(__NVCC__) doesn't work with nvcc here: -#define gsl_HAVE_UNCONSTRAINED_SPAN_CONTAINER_CTOR \ - ( gsl_CONFIG_ALLOWS_UNCONSTRAINED_SPAN_CONTAINER_CTOR && (__NVCC__== 0) ) - -// GSL API (e.g. for CUDA platform): - -#ifndef gsl_api -# ifdef __CUDACC__ -# define gsl_api __host__ __device__ -# else -# define gsl_api /*gsl_api*/ -# endif -#endif - -// additional includes: - -#if gsl_HAVE_ARRAY -# include <array> -#endif - -#if gsl_HAVE_TYPE_TRAITS -# include <type_traits> -#elif gsl_HAVE_TR1_TYPE_TRAITS -# include <tr1/type_traits> -#endif - -#if gsl_HAVE_SIZED_TYPES -# include <cstdint> -#endif - -namespace gsl { - -namespace detail { - -// C++11 emulation: - -#if gsl_HAVE_ADD_CONST - -using std::add_const; - -#elif gsl_HAVE_TR1_ADD_CONST - -using std::tr1::add_const; - -#else - -template< class T > struct add_const { typedef const T type; }; - -#endif // gsl_HAVE_ADD_CONST - -#if gsl_HAVE_REMOVE_CONST - -using std::remove_cv; -using std::remove_const; -using std::remove_volatile; - -#elif gsl_HAVE_TR1_REMOVE_CONST - -using std::tr1::remove_cv; -using std::tr1::remove_const; -using std::tr1::remove_volatile; - -#else - -template< class T > struct remove_const { typedef T type; }; -template< class T > struct remove_const<T const> { typedef T type; }; - -template< class T > struct remove_volatile { typedef T type; }; -template< class T > struct remove_volatile<T volatile> { typedef T type; }; - -template< class T > -struct remove_cv -{ - typedef typename detail::remove_volatile<typename detail::remove_const<T>::type>::type type; -}; - -#endif // gsl_HAVE_REMOVE_CONST - -#if gsl_HAVE_INTEGRAL_CONSTANT - -using std::integral_constant; -using std::true_type; -using std::false_type; - -#elif gsl_HAVE_TR1_INTEGRAL_CONSTANT - -using std::tr1::integral_constant; -using std::tr1::true_type; -using std::tr1::false_type; - -#else - -template< int v > struct integral_constant { enum { value = v }; }; -typedef integral_constant< true > true_type; -typedef integral_constant< false > false_type; - -#endif - -#if gsl_HAVE_ARRAY - -template< class T > -struct is_std_array_oracle : false_type {}; - -template< class T, std::size_t N > -struct is_std_array_oracle< std::array<T, N> > : true_type {}; - -template< class T > -struct is_std_array : is_std_array_oracle< typename remove_cv<T>::type > {}; - -#endif - -} // namespace detail - -// -// GSL.owner: ownership pointers -// -#if gsl_HAVE_SHARED_PTR - using std::unique_ptr; - using std::shared_ptr; - using std::make_shared; -# if gsl_HAVE_MAKE_UNIQUE - using std::make_unique; -# endif -#endif - -#if gsl_HAVE_ALIAS_TEMPLATE - template< class T > using owner = T; -#else - template< class T > struct owner { typedef T type; }; -#endif - -#define gsl_HAVE_OWNER_TEMPLATE gsl_HAVE_ALIAS_TEMPLATE - -#if gsl_FEATURE_HAVE_OWNER_MACRO -# if gsl_HAVE_OWNER_TEMPLATE -# define Owner(t) ::gsl::owner<t> -# else -# define Owner(t) ::gsl::owner<t>::type -# endif -#endif - -// -// GSL.assert: assertions -// - -#define gsl_ELIDE_CONTRACT_EXPECTS ( 0 == ( gsl_CONFIG_CONTRACT_LEVEL_MASK & 0x01 ) ) -#define gsl_ELIDE_CONTRACT_ENSURES ( 0 == ( gsl_CONFIG_CONTRACT_LEVEL_MASK & 0x10 ) ) - -#if gsl_ELIDE_CONTRACT_EXPECTS -# define Expects( x ) /* Expects elided */ -#elif gsl_CONFIG_CONTRACT_VIOLATION_THROWS_V -# define Expects( x ) ::gsl::fail_fast_assert( (x), "GSL: Precondition failure at " __FILE__ ": " gsl_STRINGIFY(__LINE__) ); -#else -# define Expects( x ) ::gsl::fail_fast_assert( (x) ) -#endif - -#if gsl_ELIDE_CONTRACT_ENSURES -# define Ensures( x ) /* Ensures elided */ -#elif gsl_CONFIG_CONTRACT_VIOLATION_THROWS_V -# define Ensures( x ) ::gsl::fail_fast_assert( (x), "GSL: Postcondition failure at " __FILE__ ": " gsl_STRINGIFY(__LINE__) ); -#else -# define Ensures( x ) ::gsl::fail_fast_assert( (x) ) -#endif - -#define gsl_STRINGIFY( x ) gsl_STRINGIFY_( x ) -#define gsl_STRINGIFY_( x ) #x - -struct fail_fast : public std::logic_error -{ - gsl_api explicit fail_fast( char const * const message ) - : std::logic_error( message ) {} -}; - -// workaround for gcc 5 throw/terminate constexpr bug: - -#if gsl_BETWEEN( gsl_COMPILER_GCC_VERSION, 430, 600 ) && gsl_HAVE_CONSTEXPR_14 - -# if gsl_CONFIG_CONTRACT_VIOLATION_THROWS_V - -gsl_api inline gsl_constexpr14 auto fail_fast_assert( bool cond, char const * const message ) -> void -{ - !cond ? throw fail_fast( message ) : 0; -} - -# else - -gsl_api inline gsl_constexpr14 auto fail_fast_assert( bool cond ) -> void -{ - struct F { static gsl_constexpr14 void f(){}; }; - - !cond ? std::terminate() : F::f(); -} - -# endif - -#else // workaround - -# if gsl_CONFIG_CONTRACT_VIOLATION_THROWS_V - -gsl_api inline gsl_constexpr14 void fail_fast_assert( bool cond, char const * const message ) -{ - if ( !cond ) - throw fail_fast( message ); -} - -# else - -gsl_api inline gsl_constexpr14 void fail_fast_assert( bool cond ) -{ - if ( !cond ) - std::terminate(); -} - -# endif -#endif // workaround - -// -// GSL.util: utilities -// - -#if gsl_CPP11_OR_GREATER || gsl_COMPILER_MSVC_VERSION == 11 - -template< class F > -class final_act -{ -public: - gsl_api explicit final_act( F action ) gsl_noexcept - : action_( std::move( action ) ) - , invoke_( true ) - {} - - gsl_api final_act( final_act && other ) gsl_noexcept - : action_( std::move( other.action_ ) ) - , invoke_( other.invoke_ ) - { - other.invoke_ = false; - } - -#if gsl_HAVE_IS_DELETE - gsl_api final_act( final_act const & ) = delete; - gsl_api final_act & operator=( final_act const & ) = delete; -#else -private: - gsl_api final_act( final_act const & ); - gsl_api final_act & operator=( final_act const & ); -public: -#endif - - gsl_api virtual ~final_act() gsl_noexcept - { - if ( invoke_ ) - action_(); - } - -protected: - gsl_api void dismiss() gsl_noexcept - { - invoke_ = false; - } - -#if gsl_CPP17_OR_GREATER - gsl_api int uncaught_exceptions() gsl_noexcept - { - return std::uncaught_exceptions(); - } -#else - gsl_api int uncaught_exceptions() - { - return std::uncaught_exception() ? 1 : 0; - } -#endif - -private: - F action_; - bool invoke_; -}; - -template< class F > -gsl_api inline final_act<F> finally( F const & action ) gsl_noexcept -{ - return final_act<F>( action ); -} - -template< class F > -gsl_api inline final_act<F> finally( F && action ) gsl_noexcept -{ - return final_act<F>( std::forward<F>( action ) ); -} - -#if gsl_FEATURE_EXPERIMENTAL_RETURN_GUARD - -template< class F > -class final_act_return : public final_act<F> -{ -public: - gsl_api explicit final_act_return( F && action ) gsl_noexcept - : final_act<F>( std::move( action ) ) - {} - - gsl_api final_act_return( final_act_return && other ) gsl_noexcept - : final_act<F>( std::move( other ) ) - {} - -#if gsl_HAVE_IS_DELETE - gsl_api final_act_return( final_act_return const & ) = delete; - gsl_api final_act_return & operator=( final_act_return const & ) = delete; -#else -private: - gsl_api final_act_return( final_act_return const & ); - gsl_api final_act_return & operator=( final_act_return const & ); -public: -#endif - - gsl_api ~final_act_return() override - { - if ( this->uncaught_exceptions() ) - this->dismiss(); - } -}; - -template< class F > -gsl_api inline final_act_return<F> on_return( F const & action ) gsl_noexcept -{ - return final_act_return<F>( action ); -} - -template< class F > -gsl_api inline final_act_return<F> on_return( F && action ) gsl_noexcept -{ - return final_act_return<F>( std::forward<F>( action ) ); -} - -template< class F > -class final_act_error : public final_act<F> -{ -public: - gsl_api explicit final_act_error( F && action ) gsl_noexcept - : final_act<F>( std::move( action ) ) - {} - - gsl_api final_act_error( final_act_error && other ) gsl_noexcept - : final_act<F>( std::move( other ) ) - {} - -#if gsl_HAVE_IS_DELETE - gsl_api final_act_error( final_act_error const & ) = delete; - gsl_api final_act_error & operator=( final_act_error const & ) = delete; -#else -private: - gsl_api final_act_error( final_act_error const & ); - gsl_api final_act_error & operator=( final_act_error const & ); -public: -#endif - - gsl_api ~final_act_error() override - { - if ( ! this->uncaught_exceptions() ) - this->dismiss(); - } -}; - -template< class F > -gsl_api inline final_act_error<F> on_error( F const & action ) gsl_noexcept -{ - return final_act_error<F>( action ); -} - -template< class F > -gsl_api inline final_act_error<F> on_error( F && action ) gsl_noexcept -{ - return final_act_error<F>( std::forward<F>( action ) ); -} - -#endif // gsl_FEATURE_EXPERIMENTAL_RETURN_GUARD - -#else // gsl_CPP11_OR_GREATER || gsl_COMPILER_MSVC_VERSION == 11 - -class final_act -{ -public: - typedef void (*Action)(); - - gsl_api final_act( Action action ) - : action_( action ) - , invoke_( true ) - {} - - gsl_api final_act( final_act const & other ) - : action_( other.action_ ) - , invoke_( other.invoke_ ) - { - other.invoke_ = false; - } - - gsl_api virtual ~final_act() - { - if ( invoke_ ) - action_(); - } - -protected: - gsl_api void dismiss() - { - invoke_ = false; - } - - gsl_api int uncaught_exceptions() - { - return std::uncaught_exception() ? 1 : 0; - } - -private: - gsl_api final_act & operator=( final_act const & ); - -private: - Action action_; - mutable bool invoke_; -}; - -template< class F > -gsl_api inline final_act finally( F const & f ) -{ - return final_act(( f )); -} - -#if gsl_FEATURE_EXPERIMENTAL_RETURN_GUARD - -class final_act_return : public final_act -{ -public: - gsl_api explicit final_act_return( Action action ) - : final_act( action ) - {} - - gsl_api ~final_act_return() - { - if ( this->uncaught_exceptions() ) - this->dismiss(); - } - -private: - gsl_api final_act_return & operator=( final_act_return const & ); -}; - -template< class F > -gsl_api inline final_act_return on_return( F const & action ) -{ - return final_act_return( action ); -} - -class final_act_error : public final_act -{ -public: - gsl_api explicit final_act_error( Action action ) - : final_act( action ) - {} - - gsl_api ~final_act_error() - { - if ( ! this->uncaught_exceptions() ) - this->dismiss(); - } - -private: - gsl_api final_act_error & operator=( final_act_error const & ); -}; - -template< class F > -gsl_api inline final_act_error on_error( F const & action ) -{ - return final_act_error( action ); -} - -#endif // gsl_FEATURE_EXPERIMENTAL_RETURN_GUARD - -#endif // gsl_CPP11_OR_GREATER || gsl_COMPILER_MSVC_VERSION == 11 - -#if gsl_CPP11_OR_GREATER - -template< class T, class U > -gsl_api inline gsl_constexpr T narrow_cast( U && u ) gsl_noexcept -{ - return static_cast<T>( std::forward<U>( u ) ); -} - -#else - -template< class T, class U > -gsl_api inline T narrow_cast( U u ) gsl_noexcept -{ - return static_cast<T>( u ); -} - -#endif // gsl_CPP11_OR_GREATER - -struct narrowing_error : public std::exception {}; - -#if gsl_HAVE_TYPE_TRAITS - -namespace details -{ - template< class T, class U > - struct is_same_signedness : public std::integral_constant<bool, std::is_signed<T>::value == std::is_signed<U>::value> - {}; -} -#endif - -template< class T, class U > -gsl_api inline T narrow( U u ) -{ - T t = narrow_cast<T>( u ); - - if ( static_cast<U>( t ) != u ) - { -#if gsl_CONFIG_CONTRACT_VIOLATION_THROWS_V - throw narrowing_error(); -#else - std::terminate(); -#endif - } - -#if gsl_HAVE_TYPE_TRAITS - if ( ! details::is_same_signedness<T, U>::value && ( ( t < T() ) != ( u < U() ) ) ) -#else - // Don't assume T() works: - if ( ( t < 0 ) != ( u < 0 ) ) -#endif - { -#if gsl_CONFIG_CONTRACT_VIOLATION_THROWS_V - throw narrowing_error(); -#else - std::terminate(); -#endif - } - return t; -} - -// -// at() - Bounds-checked way of accessing static arrays, std::array, std::vector. -// - -template< class T, size_t N > -gsl_api inline gsl_constexpr14 T & at( T(&arr)[N], size_t index ) -{ - Expects( index < N ); - return arr[index]; -} - -#if gsl_HAVE_ARRAY - -template< class T, size_t N > -gsl_api inline gsl_constexpr14 T & at( std::array<T, N> & arr, size_t index ) -{ - Expects( index < N ); - return arr[index]; -} -#endif - -template< class Cont > -gsl_api inline gsl_constexpr14 typename Cont::value_type & at( Cont & cont, size_t index ) -{ - Expects( index < cont.size() ); - return cont[index]; -} - -#if gsl_HAVE_INITIALIZER_LIST - -template< class T > -gsl_api inline const gsl_constexpr14 T & at( std::initializer_list<T> cont, size_t index ) -{ - Expects( index < cont.size() ); - return *( cont.begin() + index ); -} -#endif - -template< class T > -class span; - -template< class T > -gsl_api inline gsl_constexpr14 T & at( span<T> s, size_t index ) -{ - return s.at( index ); -} - -// -// GSL.views: views -// - -// -// not_null<> - Wrap any indirection and enforce non-null. -// -template< class T > -class not_null -{ -public: - gsl_api not_null( T t ) : ptr_ ( t ){ Expects( ptr_ != gsl_nullptr ); } - gsl_api not_null & operator=( T const & t ) { ptr_ = t ; Expects( ptr_ != gsl_nullptr ); return *this; } - - gsl_api not_null( not_null const & other ) : ptr_ ( other.ptr_ ) {} - gsl_api not_null & operator=( not_null const & other ) { ptr_ = other.ptr_; return *this; } - -#if gsl_HAVE_DEFAULT_FUNCTION_TEMPLATE_ARG - - template< class U, class Dummy = - typename std::enable_if<std::is_convertible<U, T>::value, void>::type > - gsl_api not_null( not_null<U> const & other ) : ptr_( other.get() ) {} - - template< class U, class Dummy = - typename std::enable_if<std::is_convertible<U, T>::value, void>::type > - gsl_api not_null & operator=( not_null<U> const & other ) - { - ptr_ = other.get(); - return *this; - } - -#else - - template< class U > - gsl_api not_null( not_null<U> const & other ) : ptr_( other.get() ) {} - - template< class U > - gsl_api not_null & operator=( not_null<U> const & other ) - { - ptr_ = other.get(); - return *this; - } -#endif - -private: - // Prevent compilation when initialized with a nullptr or literal 0: -#if gsl_HAVE_NULLPTR - gsl_api not_null( std::nullptr_t ); - gsl_api not_null & operator=( std::nullptr_t ); -#endif - gsl_api not_null( int ); - gsl_api not_null & operator=( int ); - -public: - gsl_api T get() const - { -#if gsl_HAVE_NULLPTR && gsl_COMPILER_MSVC_VERSION > 0 - // The assume() should help the optimizer: - __assume( ptr_ != nullptr ); -#endif - return ptr_; - } - - gsl_api operator T() const { return get(); } - gsl_api T operator->() const { return get(); } - - gsl_api bool operator==(T const & rhs) const { return ptr_ == rhs; } - gsl_api bool operator!=(T const & rhs) const { return !(*this == rhs); } - -private: - T ptr_; - - gsl_api not_null & operator++(); - gsl_api not_null & operator--(); - gsl_api not_null operator++( int ); - gsl_api not_null operator--( int ); - gsl_api not_null & operator+ ( size_t ); - gsl_api not_null & operator+=( size_t ); - gsl_api not_null & operator- ( size_t ); - gsl_api not_null & operator-=( size_t ); -}; - -// -// Byte-specific type. -// -#if gsl_HAVE_ENUM_CLASS_CONSTRUCTION_FROM_UNDERLYING_TYPE - enum class byte : unsigned char {}; -#else - struct byte { typedef unsigned char type; type v; }; -#endif - -#if gsl_HAVE_DEFAULT_FUNCTION_TEMPLATE_ARG -# define gsl_ENABLE_IF_INTEGRAL_T(T) \ - , class = typename std::enable_if<std::is_integral<T>::value>::type -#else -# define gsl_ENABLE_IF_INTEGRAL_T(T) -#endif - -template< class T > -gsl_api inline gsl_constexpr byte to_byte( T v ) gsl_noexcept -{ -#if gsl_HAVE_ENUM_CLASS_CONSTRUCTION_FROM_UNDERLYING_TYPE - static_assert( false, "Implement to_byte() using conversion from underlying type." ); -#elif gsl_HAVE_CONSTEXPR_11 - return { static_cast<typename byte::type>( v ) }; -#else - byte b = { static_cast<typename byte::type>( v ) }; return b; -#endif -} - -template< class IntegerType gsl_ENABLE_IF_INTEGRAL_T( IntegerType ) > -gsl_api inline gsl_constexpr IntegerType to_integer( byte b ) gsl_noexcept -{ -#if gsl_HAVE_ENUM_CLASS_CONSTRUCTION_FROM_UNDERLYING_TYPE - static_assert( false, "Implement to_integer() using conversion from underlying type." ); -#else - return b.v; -#endif -} - -gsl_api inline gsl_constexpr unsigned char to_uchar( byte b ) gsl_noexcept -{ - return to_integer<unsigned char>( b ); -} - -gsl_api inline gsl_constexpr unsigned char to_uchar( int i ) gsl_noexcept -{ - return static_cast<unsigned char>( i ); -} - -#if ! gsl_HAVE_ENUM_CLASS_CONSTRUCTION_FROM_UNDERLYING_TYPE - -gsl_api inline gsl_constexpr bool operator==( byte l, byte r ) gsl_noexcept -{ - return l.v == r.v; -} - -gsl_api inline gsl_constexpr bool operator!=( byte l, byte r ) gsl_noexcept -{ - return !( l == r ); -} - -gsl_api inline gsl_constexpr bool operator< ( byte l, byte r ) gsl_noexcept -{ - return l.v < r.v; -} - -gsl_api inline gsl_constexpr bool operator<=( byte l, byte r ) gsl_noexcept -{ - return !( r < l ); -} - -gsl_api inline gsl_constexpr bool operator> ( byte l, byte r ) gsl_noexcept -{ - return ( r < l ); -} - -gsl_api inline gsl_constexpr bool operator>=( byte l, byte r ) gsl_noexcept -{ - return !( l < r ); -} -#endif - -template< class IntegerType gsl_ENABLE_IF_INTEGRAL_T( IntegerType ) > -gsl_api inline gsl_constexpr14 byte & operator<<=( byte & b, IntegerType shift ) gsl_noexcept -{ -#if gsl_HAVE_ENUM_CLASS_CONSTRUCTION_FROM_UNDERLYING_TYPE - return b = to_byte( to_uchar( b ) << shift ); -#else - b.v = to_uchar( b.v << shift ); return b; -#endif -} - -template< class IntegerType gsl_ENABLE_IF_INTEGRAL_T( IntegerType ) > -gsl_api inline gsl_constexpr byte operator<<( byte b, IntegerType shift ) gsl_noexcept -{ - return to_byte( to_uchar( b ) << shift ); -} - -template< class IntegerType gsl_ENABLE_IF_INTEGRAL_T( IntegerType ) > -gsl_api inline gsl_constexpr14 byte & operator>>=( byte & b, IntegerType shift ) gsl_noexcept -{ -#if gsl_HAVE_ENUM_CLASS_CONSTRUCTION_FROM_UNDERLYING_TYPE - return b = to_byte( to_uchar( b ) >> shift ); -#else - b.v = to_uchar( b.v >> shift ); return b; -#endif -} - -template< class IntegerType gsl_ENABLE_IF_INTEGRAL_T( IntegerType ) > -gsl_api inline gsl_constexpr byte operator>>( byte b, IntegerType shift ) gsl_noexcept -{ - return to_byte( to_uchar( b ) >> shift ); -} - -gsl_api inline gsl_constexpr14 byte & operator|=( byte & l, byte r ) gsl_noexcept -{ -#if gsl_HAVE_ENUM_CLASS_CONSTRUCTION_FROM_UNDERLYING_TYPE - return l = to_byte( to_uchar( l ) | to_uchar( r ) ); -#else - l.v = to_uchar( l ) | to_uchar( r ); return l; -#endif -} - -gsl_api inline gsl_constexpr byte operator|( byte l, byte r ) gsl_noexcept -{ - return to_byte( to_uchar( l ) | to_uchar( r ) ); -} - -gsl_api inline gsl_constexpr14 byte & operator&=( byte & l, byte r ) gsl_noexcept -{ -#if gsl_HAVE_ENUM_CLASS_CONSTRUCTION_FROM_UNDERLYING_TYPE - return l = to_byte( to_uchar( l ) & to_uchar( r ) ); -#else - l.v = to_uchar( l ) & to_uchar( r ); return l; -#endif -} - -gsl_api inline gsl_constexpr byte operator&( byte l, byte r ) gsl_noexcept -{ - return to_byte( to_uchar( l ) & to_uchar( r ) ); -} - -gsl_api inline gsl_constexpr14 byte & operator^=( byte & l, byte r ) gsl_noexcept -{ -#if gsl_HAVE_ENUM_CLASS_CONSTRUCTION_FROM_UNDERLYING_TYPE - return l = to_byte( to_uchar( l ) ^ to_uchar (r ) ); -#else - l.v = to_uchar( l ) ^ to_uchar (r ); return l; -#endif -} - -gsl_api inline gsl_constexpr byte operator^( byte l, byte r ) gsl_noexcept -{ - return to_byte( to_uchar( l ) ^ to_uchar( r ) ); -} - -gsl_api inline gsl_constexpr byte operator~( byte b ) gsl_noexcept -{ - return to_byte( ~to_uchar( b ) ); -} - -// tag to select span constructor taking a container -struct with_container_t{ gsl_constexpr14 with_container_t(){} }; -const with_container_t with_container; - -// -// span<> - A 1D view of contiguous T's, replace (*,len). -// -template< class T > -class span -{ - template< class U > friend class span; - -public: - typedef gsl_CONFIG_SPAN_INDEX_TYPE index_type; // p0122r3 uses std::ptrdiff_t - - typedef T element_type; - typedef T & reference; - typedef T * pointer; - typedef T const * const_pointer; - typedef T const & const_reference; - - typedef pointer iterator; - typedef const_pointer const_iterator; +#pragma message ("gsl/gsl-lite.h is deprecated since version 0.27.0, use gsl/gsl-lite.hpp instead.") - typedef std::reverse_iterator< iterator > reverse_iterator; - typedef std::reverse_iterator< const_iterator > const_reverse_iterator; - - typedef typename std::iterator_traits< iterator >::difference_type difference_type; - - gsl_api gsl_constexpr14 span() gsl_noexcept - : first_( gsl_nullptr ) - , last_ ( gsl_nullptr ) - { - Expects( size() == 0 ); - } - -#if gsl_HAVE_NULLPTR - gsl_api gsl_constexpr14 span( std::nullptr_t, index_type size_in ) - : first_( nullptr ) - , last_ ( nullptr ) - { - Expects( size_in == 0 ); - } -#endif - -#if gsl_HAVE_IS_DELETE - gsl_api gsl_constexpr14 span( reference data_in ) - : span( &data_in, 1 ) - {} - - gsl_api gsl_constexpr14 span( element_type && ) = delete; -#endif - - gsl_api gsl_constexpr14 span( pointer first_in, pointer last_in ) - : first_( first_in ) - , last_ ( last_in ) - { - Expects( first_in <= last_in ); - } - - gsl_api gsl_constexpr14 span( pointer data_in, index_type size_in ) - : first_( data_in ) - , last_ ( data_in + size_in ) - { - Expects( size_in == 0 || ( size_in > 0 && data_in != gsl_nullptr ) ); - } - - template< class U > - gsl_api gsl_constexpr14 span( U * & data_in, index_type size_in ) - : first_( data_in ) - , last_ ( data_in + size_in ) - { - Expects( size_in == 0 || ( size_in > 0 && data_in != gsl_nullptr ) ); - } - - template< class U > - gsl_api gsl_constexpr14 span( U * const & data_in, index_type size_in ) - : first_( data_in ) - , last_ ( data_in + size_in ) - { - Expects( size_in == 0 || ( size_in > 0 && data_in != gsl_nullptr ) ); - } - - template< class U, size_t N > - gsl_api gsl_constexpr14 span( U (&arr)[N] ) - : first_( &arr[0] ) - , last_ ( &arr[0] + N ) - {} - -#if gsl_HAVE_ARRAY - template< class U, size_t N > - gsl_api gsl_constexpr14 span( std::array< U, N > & arr ) - : first_( arr.data() ) - , last_ ( arr.data() + N ) - {} - - template< class U, size_t N > - gsl_api gsl_constexpr14 span( std::array< U, N > const & arr ) - : first_( arr.data() ) - , last_ ( arr.data() + N ) - {} -#endif - -#if gsl_HAVE_CONSTRAINED_SPAN_CONTAINER_CTOR - // SFINAE enable only if Cont has a data() member function - template< class Cont, class = decltype(std::declval<Cont>().data()) > - gsl_api gsl_constexpr14 span( Cont & cont ) - : first_( cont.data() ) - , last_ ( cont.data() + cont.size() ) - {} -#elif gsl_HAVE_UNCONSTRAINED_SPAN_CONTAINER_CTOR - template< class Cont > - gsl_api gsl_constexpr14 span( Cont & cont ) - : first_( cont.size() == 0 ? gsl_nullptr : &cont[0] ) - , last_ ( cont.size() == 0 ? gsl_nullptr : &cont[0] + cont.size() ) - {} -#endif - - template< class Cont > - gsl_api gsl_constexpr14 span( with_container_t, Cont & cont ) - : first_( cont.size() == 0 ? gsl_nullptr : &cont[0] ) - , last_ ( cont.size() == 0 ? gsl_nullptr : &cont[0] + cont.size() ) - {} - -#if gsl_HAVE_SHARED_PTR - gsl_api gsl_constexpr14 span( shared_ptr<element_type> const & ptr ) - : first_( ptr.get() ) - , last_ ( ptr.get() ? ptr.get() + 1 : 0 ) - {} -#endif - -#if gsl_HAVE_UNIQUE_PTR -# if gsl_HAVE_DEFAULT_FUNCTION_TEMPLATE_ARG - template< class ArrayElementType = typename std::add_pointer<element_type>::type > -# else - template< class ArrayElementType > -# endif - gsl_api gsl_constexpr14 span( unique_ptr<ArrayElementType> const & ptr, index_type count ) - : first_( ptr.get() ) - , last_ ( ptr.get() + count ) - {} - - gsl_api gsl_constexpr14 span( unique_ptr<element_type> const & ptr ) - : first_( ptr.get() ) - , last_ ( ptr.get() ? ptr.get() + 1 : 0 ) - {} -#endif - -#if gsl_HAVE_IS_DEFAULT && ! gsl_BETWEEN( gsl_COMPILER_GCC_VERSION, 430, 600) - gsl_api gsl_constexpr14 span( span && ) = default; - gsl_api gsl_constexpr14 span( span const & ) = default; -#else - gsl_api gsl_constexpr14 span( span const & other ) - : first_( other.begin() ) - , last_ ( other.end() ) - {} -#endif - - template< class U > - gsl_api gsl_constexpr14 span( span<U> const & other ) - : first_( other.begin() ) - , last_ ( other.end() ) - {} - -#if gsl_HAVE_IS_DEFAULT - gsl_api span & operator=( span && ) = default; - gsl_api span & operator=( span const & ) = default; -#else - gsl_api span & operator=( span other ) - { - other.swap( *this ); - return *this; - } -#endif - -#if 0 - // Converting from other span ? - template< class U > operator=(); -#endif - - gsl_api gsl_constexpr14 span first( index_type count ) const gsl_noexcept - { - Expects( count <= this->size() ); - return span( this->data(), count ); - } - - gsl_api gsl_constexpr14 span last( index_type count ) const gsl_noexcept - { - Expects( count <= this->size() ); - return span( this->data() + this->size() - count, count ); - } - - gsl_api gsl_constexpr14 span subspan( index_type offset ) const gsl_noexcept - { - Expects( offset <= this->size() ); - return span( this->data() + offset, this->length() - offset ); - } - - gsl_api gsl_constexpr14 span subspan( index_type offset, index_type count ) const gsl_noexcept - { - Expects( offset <= this->size() && count <= this->size() - offset ); - return span( this->data() + offset, count ); - } - - gsl_api gsl_constexpr14 iterator begin() const gsl_noexcept - { - return iterator( first_ ); - } - - gsl_api gsl_constexpr14 iterator end() const gsl_noexcept - { - return iterator( last_ ); - } - - gsl_api gsl_constexpr14 const_iterator cbegin() const gsl_noexcept - { - return const_iterator( begin() ); - } - - gsl_api gsl_constexpr14 const_iterator cend() const gsl_noexcept - { - return const_iterator( end() ); - } - - gsl_api gsl_constexpr14 reverse_iterator rbegin() const gsl_noexcept - { - return reverse_iterator( end() ); - } - - gsl_api gsl_constexpr14 reverse_iterator rend() const gsl_noexcept - { - return reverse_iterator( begin() ); - } - - gsl_api gsl_constexpr14 const_reverse_iterator crbegin() const gsl_noexcept - { - return const_reverse_iterator( cend() ); - } - - gsl_api gsl_constexpr14 const_reverse_iterator crend() const gsl_noexcept - { - return const_reverse_iterator( cbegin() ); - } - - gsl_api gsl_constexpr14 reference operator[]( index_type index ) const - { - return at( index ); - } - - gsl_api gsl_constexpr14 reference operator()( index_type index ) const - { - return at( index ); - } - - gsl_api gsl_constexpr14 reference at( index_type index ) const - { - Expects( index < size() ); - return first_[ index ]; - } - - gsl_api gsl_constexpr14 pointer data() const gsl_noexcept - { - return first_; - } - - gsl_api gsl_constexpr14 bool empty() const gsl_noexcept - { - return size() == 0; - } - - gsl_api gsl_constexpr14 index_type size() const gsl_noexcept - { - return narrow_cast<index_type>( last_ - first_ ); - } - - gsl_api gsl_constexpr14 index_type length() const gsl_noexcept - { - return size(); - } - - gsl_api gsl_constexpr14 index_type size_bytes() const gsl_noexcept - { - return size() * narrow_cast<index_type>( sizeof( element_type ) ); - } - - gsl_api gsl_constexpr14 index_type length_bytes() const gsl_noexcept - { - return size_bytes(); - } - - gsl_api void swap( span & other ) gsl_noexcept - { - using std::swap; - swap( first_, other.first_ ); - swap( last_ , other.last_ ); - } - - // member as_bytes(), as_writeable_bytes deprecated since 0.17.0 - - gsl_api span< const byte > as_bytes() const gsl_noexcept - { - return span< const byte >( reinterpret_cast<const byte *>( data() ), size_bytes() ); - } - - gsl_api span< byte > as_writeable_bytes() const gsl_noexcept - { - return span< byte >( reinterpret_cast<byte *>( data() ), size_bytes() ); - } - - template< class U > - gsl_api span< U > as_span() const gsl_noexcept - { - Expects( ( this->size_bytes() % sizeof(U) ) == 0 ); - return span< U >( reinterpret_cast<U *>( this->data() ), this->size_bytes() / sizeof( U ) ); - } - -private: - pointer first_; - pointer last_; -}; - -// span comparison functions - -#if gsl_CONFIG_ALLOWS_NONSTRICT_SPAN_COMPARISON - -template< class T, class U > -gsl_api inline gsl_constexpr14 bool operator==( span<T> const & l, span<U> const & r ) -{ - return l.size() == r.size() - && (l.begin() == r.begin() || std::equal( l.begin(), l.end(), r.begin() ) ); -} - -template< class T, class U > -gsl_api inline gsl_constexpr14 bool operator< ( span<T> const & l, span<U> const & r ) -{ - return std::lexicographical_compare( l.begin(), l.end(), r.begin(), r.end() ); -} - -#else - -template< class T > -gsl_api inline gsl_constexpr14 bool operator==( span<T> const & l, span<T> const & r ) -{ - return l.size() == r.size() - && (l.begin() == r.begin() || std::equal( l.begin(), l.end(), r.begin() ) ); -} - -template< class T > -gsl_api inline gsl_constexpr14 bool operator< ( span<T> const & l, span<T> const & r ) -{ - return std::lexicographical_compare( l.begin(), l.end(), r.begin(), r.end() ); -} -#endif - -template< class T, class U > -gsl_api inline gsl_constexpr14 bool operator!=( span<T> const & l, span<U> const & r ) -{ - return !( l == r ); -} - -template< class T, class U > -gsl_api inline gsl_constexpr14 bool operator<=( span<T> const & l, span<U> const & r ) -{ - return !( r < l ); -} - -template< class T, class U > -gsl_api inline gsl_constexpr14 bool operator> ( span<T> const & l, span<U> const & r ) -{ - return ( r < l ); -} - -template< class T, class U > -gsl_api inline gsl_constexpr14 bool operator>=( span<T> const & l, span<U> const & r ) -{ - return !( l < r ); -} - -// span algorithms - -namespace detail { - -template< class II, class N, class OI > -gsl_api inline OI copy_n( II first, N count, OI result ) -{ - if ( count > 0 ) - { - *result++ = *first; - for ( N i = 1; i < count; ++i ) - { - *result++ = *++first; - } - } - return result; -} -} - -template< class T, class U > -gsl_api inline void copy( span<T> src, span<U> dest ) -{ -#if gsl_CPP14_OR_GREATER // gsl_HAVE_TYPE_TRAITS (circumvent Travis clang 3.4) - static_assert( std::is_assignable<U &, T const &>::value, "Cannot assign elements of source span to elements of destination span" ); -#endif - Expects( dest.size() >= src.size() ); - detail::copy_n( src.data(), src.size(), dest.data() ); -} - -// span creator functions (see ctors) - -template< class T > -gsl_api inline span< const byte > as_bytes( span<T> spn ) gsl_noexcept -{ - return span< const byte >( reinterpret_cast<const byte *>( spn.data() ), spn.size_bytes() ); -} - -template< class T> -gsl_api inline span< byte > as_writeable_bytes( span<T> spn ) gsl_noexcept -{ - return span< byte >( reinterpret_cast<byte *>( spn.data() ), spn.size_bytes() ); -} - -template< class T > -gsl_api inline gsl_constexpr14 span<T> make_span( T * first, T * last ) -{ - return span<T>( first, last ); -} - -template< class T > -gsl_api inline gsl_constexpr14 span<T> make_span( T * ptr, typename span<T>::index_type count ) -{ - return span<T>( ptr, count ); -} - -template< class T, size_t N > -gsl_api inline gsl_constexpr14 span<T> make_span( T (&arr)[N] ) -{ - return span<T>( &arr[0], N ); -} - -#if gsl_HAVE_ARRAY - -template< class T, size_t N > -gsl_api inline gsl_constexpr14 span<T> make_span( std::array<T,N> & arr ) -{ - return span<T>( arr ); -} - -template< class T, size_t N > -gsl_api inline gsl_constexpr14 span<const T> make_span( std::array<T,N> const & arr ) -{ - return span<const T>( arr ); -} -#endif - -#if gsl_HAVE_CONSTRAINED_SPAN_CONTAINER_CTOR && gsl_HAVE_AUTO - -template< class Cont > -gsl_api inline gsl_constexpr14 auto make_span( Cont & cont ) -> span< typename Cont::value_type > -{ - return span< typename Cont::value_type >( cont ); -} - -template< class Cont > -gsl_api inline gsl_constexpr14 auto make_span( Cont const & cont ) -> span< const typename Cont::value_type > -{ - return span< const typename Cont::value_type >( cont ); -} - -#else - -template< class T > -gsl_api inline span<T> make_span( std::vector<T> & cont ) -{ - return span<T>( with_container, cont ); -} - -template< class T > -gsl_api inline span<const T> make_span( std::vector<T> const & cont ) -{ - return span<const T>( with_container, cont ); -} -#endif - -template< class Ptr > -gsl_api inline span<typename Ptr::element_type> make_span( Ptr & ptr ) -{ - return span<typename Ptr::element_type>( ptr ); -} - -template< class Ptr > -span<typename Ptr::element_type> make_span( Ptr & ptr, typename span<typename Ptr::element_type>::index_type count ) -{ - return span<typename Ptr::element_type>( ptr, count); -} - -// -// basic_string_span: -// - -template< class T > -class basic_string_span; - -namespace detail { - -template< class T > -struct is_basic_string_span_oracle : false_type {}; - -template< class T > -struct is_basic_string_span_oracle< basic_string_span<T> > : true_type {}; - -template< class T > -struct is_basic_string_span : is_basic_string_span_oracle< typename remove_cv<T>::type > {}; - -template< class T > -gsl_api inline gsl_constexpr14 std::size_t string_length( T * ptr, std::size_t max ) -{ - if ( ptr == gsl_nullptr || max <= 0 ) - return 0; - - std::size_t len = 0; - while ( len < max && ptr[len] ) - ++len; - - return len; -} - -} // namespace detail - -// -// basic_string_span<> - A view of contiguous characters, replace (*,len). -// -template< class T > -class basic_string_span -{ -public: - typedef T element_type; - typedef span<T> span_type; - - typedef typename span_type::index_type index_type; - typedef typename span_type::difference_type difference_type; - - typedef typename span_type::pointer pointer ; - typedef typename span_type::reference reference ; - - typedef typename span_type::iterator iterator ; - typedef typename span_type::const_iterator const_iterator ; - typedef typename span_type::reverse_iterator reverse_iterator; - typedef typename span_type::const_reverse_iterator const_reverse_iterator; - - // construction: - -#if gsl_HAVE_IS_DEFAULT - gsl_api gsl_constexpr basic_string_span() gsl_noexcept = default; -#else - gsl_api gsl_constexpr basic_string_span() gsl_noexcept {} -#endif - -#if gsl_HAVE_NULLPTR - gsl_api gsl_constexpr basic_string_span( std::nullptr_t ptr ) gsl_noexcept - : span_( ptr, 0 ) - {} -#endif - - gsl_api gsl_constexpr basic_string_span( pointer ptr ) - : span_( remove_z( ptr, std::numeric_limits<index_type>::max() ) ) - {} - - gsl_api gsl_constexpr basic_string_span( pointer ptr, index_type count ) - : span_( ptr, count ) - {} - - gsl_api gsl_constexpr basic_string_span( pointer first, pointer last ) - : span_( first, last ) - {} - - template< std::size_t N > - gsl_api gsl_constexpr basic_string_span( element_type (&arr)[N] ) - : span_( remove_z( &arr[0], N ) ) - {} - -#if gsl_HAVE_ARRAY - - template< std::size_t N > - gsl_api gsl_constexpr basic_string_span( std::array< typename detail::remove_const<element_type>::type, N> & arr ) - : span_( remove_z( arr ) ) - {} - - template< std::size_t N > - gsl_api gsl_constexpr basic_string_span( std::array< typename detail::remove_const<element_type>::type, N> const & arr ) - : span_( remove_z( arr ) ) - {} - -#endif - -#if gsl_HAVE_CONSTRAINED_SPAN_CONTAINER_CTOR - - // Exclude: array, [basic_string,] basic_string_span - - template< - class Cont, - class = typename std::enable_if< - ! detail::is_std_array< Cont >::value - && ! detail::is_basic_string_span< Cont >::value - && std::is_convertible< typename Cont::pointer, pointer >::value - && std::is_convertible< typename Cont::pointer, decltype(std::declval<Cont>().data()) >::value - >::type - > - gsl_api gsl_constexpr basic_string_span( Cont & cont ) - : span_( ( cont ) ) - {} - - // Exclude: array, [basic_string,] basic_string_span - - template< - class Cont, - class = typename std::enable_if< - ! detail::is_std_array< Cont >::value - && ! detail::is_basic_string_span< Cont >::value - && std::is_convertible< typename Cont::pointer, pointer >::value - && std::is_convertible< typename Cont::pointer, decltype(std::declval<Cont>().data()) >::value - >::type - > - gsl_api gsl_constexpr basic_string_span( Cont const & cont ) - : span_( ( cont ) ) - {} - -#elif gsl_HAVE_UNCONSTRAINED_SPAN_CONTAINER_CTOR - - template< class Cont > - gsl_api gsl_constexpr basic_string_span( Cont & cont ) - : span_( cont ) - {} - - template< class Cont > - gsl_api gsl_constexpr basic_string_span( Cont const & cont ) - : span_( cont ) - {} - -#else - - template< class U > - gsl_api gsl_constexpr basic_string_span( span<U> const & rhs ) - : span_( rhs ) - {} - -#endif - - template< class Cont > - gsl_api gsl_constexpr14 basic_string_span( with_container_t, Cont & cont ) - : span_( with_container, cont ) - {} - -#if gsl_HAVE_IS_DEFAULT -# if gsl_BETWEEN( gsl_COMPILER_GCC_VERSION, 440, 600 ) - gsl_api gsl_constexpr basic_string_span( basic_string_span const & rhs ) = default; - - gsl_api gsl_constexpr basic_string_span( basic_string_span && rhs ) = default; -# else - gsl_api gsl_constexpr basic_string_span( basic_string_span const & rhs ) gsl_noexcept = default; - - gsl_api gsl_constexpr basic_string_span( basic_string_span && rhs ) gsl_noexcept = default; -# endif -#endif - - template< class U -#if gsl_HAVE_DEFAULT_FUNCTION_TEMPLATE_ARG - , class = typename std::enable_if< std::is_convertible<typename basic_string_span<U>::pointer, pointer>::value >::type -#endif - > - gsl_api gsl_constexpr basic_string_span( basic_string_span<U> const & rhs ) - : span_( reinterpret_cast<pointer>( rhs.data() ), rhs.length() ) - {} - -#if gsl_CPP11_OR_GREATER - template< class U - , class = typename std::enable_if< std::is_convertible<typename basic_string_span<U>::pointer, pointer>::value >::type - > - gsl_api gsl_constexpr basic_string_span( basic_string_span<U> && rhs ) - : span_( reinterpret_cast<pointer>( rhs.data() ), rhs.length() ) - {} -#endif - - template< class CharTraits, class Allocator > - gsl_api gsl_constexpr basic_string_span( - std::basic_string< typename detail::remove_const<element_type>::type, CharTraits, Allocator > & str ) - : span_( &str[0], str.length() ) - {} - - template< class CharTraits, class Allocator > - gsl_api gsl_constexpr basic_string_span( - std::basic_string< typename detail::remove_const<element_type>::type, CharTraits, Allocator > const & str ) - : span_( &str[0], str.length() ) - {} - - // destruction, assignment: - -#if gsl_HAVE_IS_DEFAULT - gsl_api ~basic_string_span() gsl_noexcept = default; - - gsl_api basic_string_span & operator=( basic_string_span const & rhs ) gsl_noexcept = default; - - gsl_api basic_string_span & operator=( basic_string_span && rhs ) gsl_noexcept = default; -#endif - - // sub span: - - gsl_api gsl_constexpr basic_string_span first( index_type count ) const - { - return span_.first( count ); - } - - gsl_api gsl_constexpr basic_string_span last( index_type count ) const - { - return span_.last( count ); - } - - gsl_api gsl_constexpr basic_string_span subspan( index_type offset ) const - { - return span_.subspan( offset ); - } - - gsl_api gsl_constexpr basic_string_span subspan( index_type offset, index_type count ) const - { - return span_.subspan( offset, count ); - } - - // observers: - - gsl_api gsl_constexpr index_type length() const gsl_noexcept - { - return span_.size(); - } - - gsl_api gsl_constexpr index_type size() const gsl_noexcept - { - return span_.size(); - } - - gsl_api gsl_constexpr index_type length_bytes() const gsl_noexcept - { - return span_.size_bytes(); - } - - gsl_api gsl_constexpr index_type size_bytes() const gsl_noexcept - { - return span_.size_bytes(); - } - - gsl_api gsl_constexpr bool empty() const gsl_noexcept - { - return size() == 0; - } - - gsl_api gsl_constexpr reference operator[]( index_type idx ) const - { - return span_[idx]; - } - - gsl_api gsl_constexpr reference operator()( index_type idx ) const - { - return span_[idx]; - } - - gsl_api gsl_constexpr pointer data() const gsl_noexcept - { - return span_.data(); - } - - gsl_api iterator begin() const gsl_noexcept - { - return span_.begin(); - } - - gsl_api iterator end() const gsl_noexcept - { - return span_.end(); - } - - gsl_api reverse_iterator rbegin() const gsl_noexcept - { - return span_.rbegin(); - } - - gsl_api reverse_iterator rend() const gsl_noexcept - { - return span_.rend(); - } - - // const version not in p0123r2: - - gsl_api const_iterator cbegin() const gsl_noexcept - { - return span_.cbegin(); - } - - gsl_api const_iterator cend() const gsl_noexcept - { - return span_.cend(); - } - - gsl_api const_reverse_iterator crbegin() const gsl_noexcept - { - return span_.crbegin(); - } - - gsl_api const_reverse_iterator crend() const gsl_noexcept - { - return span_.crend(); - } - -private: - gsl_api static gsl_constexpr14 span_type remove_z( pointer const & sz, std::size_t max ) - { - return span_type( sz, detail::string_length( sz, max ) ); - } - -#if gsl_HAVE_ARRAY - template< size_t N > - gsl_api static gsl_constexpr14 span_type remove_z( std::array<typename detail::remove_const<element_type>::type, N> & arr ) - { - return remove_z( &arr[0], narrow_cast< std::size_t >( N ) ); - } - - template< size_t N > - gsl_api static gsl_constexpr14 span_type remove_z( std::array<typename detail::remove_const<element_type>::type, N> const & arr ) - { - return remove_z( &arr[0], narrow_cast< std::size_t >( N ) ); - } -#endif - -private: - span_type span_; -}; - -// basic_string_span comparison functions: - -#if gsl_CONFIG_ALLOWS_NONSTRICT_SPAN_COMPARISON - -template< class T, class U > -gsl_api inline gsl_constexpr14 bool operator==( basic_string_span<T> const & l, U const & u ) gsl_noexcept -{ - basic_string_span< typename detail::add_const<T>::type > r( u ); - - return l.size() == r.size() - && std::equal( l.begin(), l.end(), r.begin() ); -} - -template< class T, class U > -gsl_api inline gsl_constexpr14 bool operator<( basic_string_span<T> const & l, U const & u ) gsl_noexcept -{ - basic_string_span< typename detail::add_const<T>::type > r( u ); - - return std::lexicographical_compare( l.begin(), l.end(), r.begin(), r.end() ); -} - -#if gsl_HAVE_DEFAULT_FUNCTION_TEMPLATE_ARG - -template< class T, class U, - class = typename std::enable_if<!detail::is_basic_string_span<U>::value >::type > -gsl_api inline gsl_constexpr14 bool operator==( U const & u, basic_string_span<T> const & r ) gsl_noexcept -{ - basic_string_span< typename detail::add_const<T>::type > l( u ); - - return l.size() == r.size() - && std::equal( l.begin(), l.end(), r.begin() ); -} - -template< class T, class U, - class = typename std::enable_if<!detail::is_basic_string_span<U>::value >::type > -gsl_api inline gsl_constexpr14 bool operator<( U const & u, basic_string_span<T> const & r ) gsl_noexcept -{ - basic_string_span< typename detail::add_const<T>::type > l( u ); - - return std::lexicographical_compare( l.begin(), l.end(), r.begin(), r.end() ); -} -#endif - -#else //gsl_CONFIG_ALLOWS_NONSTRICT_SPAN_COMPARISON - -template< class T > -gsl_api inline gsl_constexpr14 bool operator==( basic_string_span<T> const & l, basic_string_span<T> const & r ) gsl_noexcept -{ - return l.size() == r.size() - && std::equal( l.begin(), l.end(), r.begin() ); -} - -template< class T > -gsl_api inline gsl_constexpr14 bool operator<( basic_string_span<T> const & l, basic_string_span<T> const & r ) gsl_noexcept -{ - return std::lexicographical_compare( l.begin(), l.end(), r.begin(), r.end() ); -} - -#endif // gsl_CONFIG_ALLOWS_NONSTRICT_SPAN_COMPARISON - -template< class T, class U > -gsl_api inline gsl_constexpr14 bool operator!=( basic_string_span<T> const & l, U const & r ) gsl_noexcept -{ - return !( l == r ); -} - -template< class T, class U > -gsl_api inline gsl_constexpr14 bool operator<=( basic_string_span<T> const & l, U const & r ) gsl_noexcept -{ -#if gsl_HAVE_DEFAULT_FUNCTION_TEMPLATE_ARG || ! gsl_CONFIG_ALLOWS_NONSTRICT_SPAN_COMPARISON - return !( r < l ); -#else - basic_string_span< typename detail::add_const<T>::type > rr( r ); - return !( rr < l ); -#endif -} - -template< class T, class U > -gsl_api inline gsl_constexpr14 bool operator>( basic_string_span<T> const & l, U const & r ) gsl_noexcept -{ -#if gsl_HAVE_DEFAULT_FUNCTION_TEMPLATE_ARG || ! gsl_CONFIG_ALLOWS_NONSTRICT_SPAN_COMPARISON - return ( r < l ); -#else - basic_string_span< typename detail::add_const<T>::type > rr( r ); - return ( rr < l ); -#endif -} - -template< class T, class U > -gsl_api inline gsl_constexpr14 bool operator>=( basic_string_span<T> const & l, U const & r ) gsl_noexcept -{ - return !( l < r ); -} - -#if gsl_HAVE_DEFAULT_FUNCTION_TEMPLATE_ARG - -template< class T, class U, - class = typename std::enable_if<!detail::is_basic_string_span<U>::value >::type > -gsl_api inline gsl_constexpr14 bool operator!=( U const & l, basic_string_span<T> const & r ) gsl_noexcept -{ - return !( l == r ); -} - -template< class T, class U, - class = typename std::enable_if<!detail::is_basic_string_span<U>::value >::type > -gsl_api inline gsl_constexpr14 bool operator<=( U const & l, basic_string_span<T> const & r ) gsl_noexcept -{ - return !( r < l ); -} - -template< class T, class U, - class = typename std::enable_if<!detail::is_basic_string_span<U>::value >::type > -gsl_api inline gsl_constexpr14 bool operator>( U const & l, basic_string_span<T> const & r ) gsl_noexcept -{ - return ( r < l ); -} - -template< class T, class U, - class = typename std::enable_if<!detail::is_basic_string_span<U>::value >::type > -gsl_api inline gsl_constexpr14 bool operator>=( U const & l, basic_string_span<T> const & r ) gsl_noexcept -{ - return !( l < r ); -} - -#endif // gsl_HAVE_DEFAULT_FUNCTION_TEMPLATE_ARG - -// convert basic_string_span to byte span: - -template< class T > -gsl_api inline span< const byte > as_bytes( basic_string_span<T> spn ) gsl_noexcept -{ - return span< const byte >( reinterpret_cast<const byte *>( spn.data() ), spn.size_bytes() ); -} - -// -// String types: -// - -typedef char * zstring; -typedef wchar_t * zwstring; -typedef const char * czstring; -typedef const wchar_t * cwzstring; - -typedef basic_string_span< char > string_span; -typedef basic_string_span< wchar_t > wstring_span; -typedef basic_string_span< char const > cstring_span; -typedef basic_string_span< wchar_t const > cwstring_span; - -// to_string() allow (explicit) conversions from string_span to string - -#if 0 - -template< class T > -gsl_api inline std::basic_string< typename std::remove_const<T>::type > to_string( basic_string_span<T> spn ) -{ - std::string( spn.data(), spn.length() ); -} - -#else - -gsl_api inline std::string to_string( string_span const & spn ) -{ - return std::string( spn.data(), spn.length() ); -} - -gsl_api inline std::string to_string( cstring_span const & spn ) -{ - return std::string( spn.data(), spn.length() ); -} - -gsl_api inline std::wstring to_string( wstring_span const & spn ) -{ - return std::wstring( spn.data(), spn.length() ); -} - -gsl_api inline std::wstring to_string( cwstring_span const & spn ) -{ - return std::wstring( spn.data(), spn.length() ); -} - -#endif // to_string() - -// -// Stream output for string_span types -// - -namespace detail { - -template< class Stream > -gsl_api void write_padding( Stream & os, std::streamsize n ) -{ - for ( std::streamsize i = 0; i < n; ++i ) - os.rdbuf()->sputc( os.fill() ); -} - -template< class Stream, class Span > -gsl_api Stream & write_to_stream( Stream & os, Span const & spn ) -{ - typename Stream::sentry sentry( os ); - - if ( !os ) - return os; - - std::streamsize length = narrow<std::streamsize>( spn.length() ); - - // Whether, and how, to pad - bool pad = ( length < os.width() ); - bool left_pad = pad && ( os.flags() & std::ios_base::adjustfield ) == std::ios_base::left; - - if ( left_pad ) - write_padding( os, os.width() - length ); - - // Write span characters - os.rdbuf()->sputn( spn.begin(), length ); - - if ( pad && !left_pad ) - write_padding( os, os.width() - length ); - - // Reset output stream width - os.width(0); - - return os; -} - -} // namespace detail - -template< typename Traits > -gsl_api std::basic_ostream< char, Traits > & operator<<( std::basic_ostream< char, Traits > & os, string_span const & spn ) -{ - return detail::write_to_stream( os, spn ); -} - -template< typename Traits > -gsl_api std::basic_ostream< char, Traits > & operator<<( std::basic_ostream< char, Traits > & os, cstring_span const & spn ) -{ - return detail::write_to_stream( os, spn ); -} - -template< typename Traits > -gsl_api std::basic_ostream< wchar_t, Traits > & operator<<( std::basic_ostream< wchar_t, Traits > & os, wstring_span const & spn ) -{ - return detail::write_to_stream( os, spn ); -} - -template< typename Traits > -gsl_api std::basic_ostream< wchar_t, Traits > & operator<<( std::basic_ostream< wchar_t, Traits > & os, cwstring_span const & spn ) -{ - return detail::write_to_stream( os, spn ); -} - -// -// ensure_sentinel() -// -// Provides a way to obtain a span from a contiguous sequence -// that ends with a (non-inclusive) sentinel value. -// -// Will fail-fast if sentinel cannot be found before max elements are examined. -// -namespace detail { - -template< class T, class SizeType, const T Sentinel > -gsl_api static span<T> ensure_sentinel( T * seq, SizeType max = std::numeric_limits<SizeType>::max() ) -{ - typedef T * pointer; - - pointer cur = seq; - - while ( static_cast<SizeType>( cur - seq ) < max && *cur != Sentinel ) - ++cur; - - Expects( *cur == Sentinel ); - - return span<T>( seq, narrow_cast< typename span<T>::index_type >( cur - seq ) ); -} -} // namespace detail - -// -// ensure_z - creates a string_span for a czstring or cwzstring. -// Will fail fast if a null-terminator cannot be found before -// the limit of size_type. -// - -template< class T > -gsl_api inline span<T> ensure_z( T * const & sz, size_t max = std::numeric_limits<size_t>::max() ) -{ - return detail::ensure_sentinel<T, size_t, 0>( sz, max ); -} - -template< class T, size_t N > -gsl_api inline span<T> ensure_z( T (&sz)[N] ) -{ - return ensure_z( &sz[0], N ); -} - -# if gsl_HAVE_TYPE_TRAITS - -template< class Cont > -gsl_api inline span< typename std::remove_pointer<typename Cont::pointer>::type > -ensure_z( Cont & cont ) -{ - return ensure_z( cont.data(), cont.length() ); -} -# endif - -} // namespace gsl - -#if gsl_CPP11_OR_GREATER - -namespace std { - -template<> -struct hash< gsl::byte > -{ -public: - std::size_t operator()( gsl::byte v ) const gsl_noexcept - { - return gsl::to_integer<std::size_t>( v ); - } -}; - -} // namespace std - -#endif +#include "gsl-lite.hpp" #endif // GSL_GSL_LITE_H_INCLUDED - -// end of file diff --git a/third_party/gsl/gsl-lite.hpp b/third_party/gsl/gsl-lite.hpp new file mode 100644 index 0000000..21c114c --- /dev/null +++ b/third_party/gsl/gsl-lite.hpp @@ -0,0 +1,5197 @@ +// +// gsl-lite is based on GSL: Guidelines Support Library. +// For more information see https://github.com/gsl-lite/gsl-lite +// +// Copyright (c) 2015-2019 Martin Moene +// Copyright (c) 2019-2021 Moritz Beutel +// Copyright (c) 2015-2018 Microsoft Corporation. All rights reserved. +// +// This code is licensed under the MIT License (MIT). +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#ifndef GSL_GSL_LITE_HPP_INCLUDED +#define GSL_GSL_LITE_HPP_INCLUDED + +#include <exception> // for exception, terminate(), uncaught_exceptions() +#include <limits> +#include <memory> // for addressof(), unique_ptr<>, shared_ptr<> +#include <iosfwd> // for basic_ostream<> +#include <ios> // for ios_base, streamsize +#include <stdexcept> // for logic_error +#include <string> +#include <utility> // for move(), forward<>(), swap() +#include <cstddef> // for size_t, ptrdiff_t, nullptr_t + +#define gsl_lite_MAJOR 0 +#define gsl_lite_MINOR 38 +#define gsl_lite_PATCH 1 + +#define gsl_lite_VERSION gsl_STRINGIFY(gsl_lite_MAJOR) "." gsl_STRINGIFY(gsl_lite_MINOR) "." gsl_STRINGIFY(gsl_lite_PATCH) + +#define gsl_STRINGIFY( x ) gsl_STRINGIFY_( x ) +#define gsl_STRINGIFY_( x ) #x +#define gsl_CONCAT_( a, b ) gsl_CONCAT2_( a, b ) +#define gsl_CONCAT2_( a, b ) a##b +#define gsl_EVALF_( f ) f() + +// configuration argument checking: + +#define gsl_DETAIL_CFG_TOGGLE_VALUE_1 1 +#define gsl_DETAIL_CFG_TOGGLE_VALUE_0 1 +#define gsl_DETAIL_CFG_DEFAULTS_VERSION_VALUE_1 1 +#define gsl_DETAIL_CFG_DEFAULTS_VERSION_VALUE_0 1 +#define gsl_DETAIL_CFG_STD_VALUE_98 1 +#define gsl_DETAIL_CFG_STD_VALUE_3 1 +#define gsl_DETAIL_CFG_STD_VALUE_03 1 +#define gsl_DETAIL_CFG_STD_VALUE_11 1 +#define gsl_DETAIL_CFG_STD_VALUE_14 1 +#define gsl_DETAIL_CFG_STD_VALUE_17 1 +#define gsl_DETAIL_CFG_STD_VALUE_20 1 +#define gsl_DETAIL_CFG_NO_VALUE_ 1 +#define gsl_DETAIL_CFG_NO_VALUE_1 1 // many compilers treat the command-line parameter "-Dfoo" as equivalent to "-Dfoo=1", so we tolerate that +#define gsl_CHECK_CFG_TOGGLE_VALUE_( x ) gsl_CONCAT_( gsl_DETAIL_CFG_TOGGLE_VALUE_, x ) +#define gsl_CHECK_CFG_DEFAULTS_VERSION_VALUE_( x ) gsl_CONCAT_( gsl_DETAIL_CFG_DEFAULTS_VERSION_VALUE_, x ) +#define gsl_CHECK_CFG_STD_VALUE_( x ) gsl_CONCAT_( gsl_DETAIL_CFG_STD_VALUE_, x ) +#define gsl_CHECK_CFG_NO_VALUE_( x ) gsl_CONCAT_( gsl_DETAIL_CFG_NO_VALUE, gsl_CONCAT_( _, x ) ) + +// gsl-lite backward compatibility: + +#if defined( gsl_CONFIG_DEFAULTS_VERSION ) +# if ! gsl_CHECK_CFG_DEFAULTS_VERSION_VALUE_( gsl_CONFIG_DEFAULTS_VERSION ) +# pragma message ("invalid configuration value gsl_CONFIG_DEFAULTS_VERSION=" gsl_STRINGIFY(gsl_CONFIG_DEFAULTS_VERSION) ", must be 0 or 1") +# endif +#else +# define gsl_CONFIG_DEFAULTS_VERSION gsl_lite_MAJOR // default +#endif +# define gsl_CONFIG_DEFAULTS_VERSION_() gsl_CONFIG_DEFAULTS_VERSION + +#if defined( gsl_CONFIG_ALLOWS_SPAN_CONTAINER_CTOR ) +# if ! gsl_CHECK_CFG_TOGGLE_VALUE_( gsl_CONFIG_ALLOWS_SPAN_CONTAINER_CTOR ) +# pragma message ("invalid configuration value gsl_CONFIG_ALLOWS_SPAN_CONTAINER_CTOR=" gsl_STRINGIFY(gsl_CONFIG_ALLOWS_SPAN_CONTAINER_CTOR) ", must be 0 or 1") +# endif +# define gsl_CONFIG_ALLOWS_UNCONSTRAINED_SPAN_CONTAINER_CTOR gsl_CONFIG_ALLOWS_SPAN_CONTAINER_CTOR +# pragma message ("gsl_CONFIG_ALLOWS_SPAN_CONTAINER_CTOR is deprecated since gsl-lite 0.7; replace with gsl_CONFIG_ALLOWS_UNCONSTRAINED_SPAN_CONTAINER_CTOR, or consider span(with_container, cont).") +#endif + +#if defined( gsl_CONFIG_CONTRACT_LEVEL_ON ) +# if ! gsl_CHECK_CFG_NO_VALUE_( gsl_CONFIG_CONTRACT_LEVEL_ON ) +# pragma message ("invalid configuration value gsl_CONFIG_CONTRACT_LEVEL_ON=" gsl_STRINGIFY(gsl_CONFIG_CONTRACT_LEVEL_ON) "; macro must be defined without value") +# endif +# pragma message ("gsl_CONFIG_CONTRACT_LEVEL_ON is deprecated since gsl-lite 0.36; replace with gsl_CONFIG_CONTRACT_CHECKING_ON.") +# define gsl_CONFIG_CONTRACT_CHECKING_ON +#endif +#if defined( gsl_CONFIG_CONTRACT_LEVEL_OFF ) +# if ! gsl_CHECK_CFG_NO_VALUE_( gsl_CONFIG_CONTRACT_LEVEL_OFF ) +# pragma message ("invalid configuration value gsl_CONFIG_CONTRACT_LEVEL_OFF=" gsl_STRINGIFY(gsl_CONFIG_CONTRACT_LEVEL_OFF) "; macro must be defined without value") +# endif +# pragma message ("gsl_CONFIG_CONTRACT_LEVEL_OFF is deprecated since gsl-lite 0.36; replace with gsl_CONFIG_CONTRACT_CHECKING_OFF.") +# define gsl_CONFIG_CONTRACT_CHECKING_OFF +#endif +#if defined( gsl_CONFIG_CONTRACT_LEVEL_EXPECTS_ONLY ) +# if ! gsl_CHECK_CFG_NO_VALUE_( gsl_CONFIG_CONTRACT_LEVEL_EXPECTS_ONLY ) +# pragma message ("invalid configuration value gsl_CONFIG_CONTRACT_LEVEL_EXPECTS_ONLY=" gsl_STRINGIFY(gsl_CONFIG_CONTRACT_LEVEL_EXPECTS_ONLY) "; macro must be defined without value") +# endif +# pragma message ("gsl_CONFIG_CONTRACT_LEVEL_EXPECTS_ONLY is deprecated since gsl-lite 0.36; replace with gsl_CONFIG_CONTRACT_CHECKING_ENSURES_OFF and gsl_CONFIG_CONTRACT_CHECKING_ASSERT_OFF.") +# define gsl_CONFIG_CONTRACT_CHECKING_ON +# define gsl_CONFIG_CONTRACT_CHECKING_ENSURES_OFF +# define gsl_CONFIG_CONTRACT_CHECKING_ASSERT_OFF +#elif defined( gsl_CONFIG_CONTRACT_LEVEL_ENSURES_ONLY ) +# if ! gsl_CHECK_CFG_NO_VALUE_( gsl_CONFIG_CONTRACT_LEVEL_ENSURES_ONLY ) +# pragma message ("invalid configuration value gsl_CONFIG_CONTRACT_LEVEL_ENSURES_ONLY=" gsl_STRINGIFY(gsl_CONFIG_CONTRACT_LEVEL_ENSURES_ONLY) "; macro must be defined without value") +# endif +# pragma message ("gsl_CONFIG_CONTRACT_LEVEL_ENSURES_ONLY is deprecated since gsl-lite 0.36; replace with gsl_CONFIG_CONTRACT_CHECKING_EXPECTS_OFF and gsl_CONFIG_CONTRACT_CHECKING_ASSERT_OFF.") +# define gsl_CONFIG_CONTRACT_CHECKING_ON +# define gsl_CONFIG_CONTRACT_CHECKING_EXPECTS_OFF +# define gsl_CONFIG_CONTRACT_CHECKING_ASSERT_OFF +#endif + +// M-GSL compatibility: + +#if defined( GSL_THROW_ON_CONTRACT_VIOLATION ) +# if ! gsl_CHECK_CFG_NO_VALUE_( GSL_THROW_ON_CONTRACT_VIOLATION ) +# pragma message ("invalid configuration value GSL_THROW_ON_CONTRACT_VIOLATION=" gsl_STRINGIFY(GSL_THROW_ON_CONTRACT_VIOLATION) "; macro must be defined without value") +# endif +# define gsl_CONFIG_CONTRACT_VIOLATION_THROWS +#endif + +#if defined( GSL_TERMINATE_ON_CONTRACT_VIOLATION ) +# if ! gsl_CHECK_CFG_NO_VALUE_( GSL_TERMINATE_ON_CONTRACT_VIOLATION ) +# pragma message ("invalid configuration value GSL_TERMINATE_ON_CONTRACT_VIOLATION=" gsl_STRINGIFY(GSL_TERMINATE_ON_CONTRACT_VIOLATION) "; macro must be defined without value") +# endif +# define gsl_CONFIG_CONTRACT_VIOLATION_TERMINATES +#endif + +#if defined( GSL_UNENFORCED_ON_CONTRACT_VIOLATION ) +# if ! gsl_CHECK_CFG_NO_VALUE_( GSL_UNENFORCED_ON_CONTRACT_VIOLATION ) +# pragma message ("invalid configuration value GSL_UNENFORCED_ON_CONTRACT_VIOLATION=" gsl_STRINGIFY(GSL_UNENFORCED_ON_CONTRACT_VIOLATION) "; macro must be defined without value") +# endif +# define gsl_CONFIG_CONTRACT_CHECKING_OFF +#endif + +// Configuration: Features + +#if defined( gsl_FEATURE_WITH_CONTAINER_TO_STD ) +# if ! gsl_CHECK_CFG_STD_VALUE_( gsl_FEATURE_WITH_CONTAINER_TO_STD ) +# pragma message ("invalid configuration value gsl_FEATURE_WITH_CONTAINER_TO_STD=" gsl_STRINGIFY(gsl_FEATURE_WITH_CONTAINER_TO_STD) ", must be 98, 3, 11, 14, 17, or 20") +# endif +#else +# define gsl_FEATURE_WITH_CONTAINER_TO_STD 99 // default +#endif +#define gsl_FEATURE_WITH_CONTAINER_TO_STD_() gsl_FEATURE_WITH_CONTAINER_TO_STD + +#if defined( gsl_FEATURE_MAKE_SPAN_TO_STD ) +# if ! gsl_CHECK_CFG_STD_VALUE_( gsl_FEATURE_MAKE_SPAN_TO_STD ) +# pragma message ("invalid configuration value gsl_FEATURE_MAKE_SPAN_TO_STD=" gsl_STRINGIFY(gsl_FEATURE_MAKE_SPAN_TO_STD) ", must be 98, 3, 11, 14, 17, or 20") +# endif +#else +# define gsl_FEATURE_MAKE_SPAN_TO_STD 99 // default +#endif +#define gsl_FEATURE_MAKE_SPAN_TO_STD_() gsl_FEATURE_MAKE_SPAN_TO_STD + +#if defined( gsl_FEATURE_BYTE_SPAN_TO_STD ) +# if ! gsl_CHECK_CFG_STD_VALUE_( gsl_FEATURE_BYTE_SPAN_TO_STD ) +# pragma message ("invalid configuration value gsl_FEATURE_BYTE_SPAN_TO_STD=" gsl_STRINGIFY(gsl_FEATURE_BYTE_SPAN_TO_STD) ", must be 98, 3, 11, 14, 17, or 20") +# endif +#else +# define gsl_FEATURE_BYTE_SPAN_TO_STD 99 // default +#endif +#define gsl_FEATURE_BYTE_SPAN_TO_STD_() gsl_FEATURE_BYTE_SPAN_TO_STD + +#if defined( gsl_FEATURE_IMPLICIT_MACRO ) +# if ! gsl_CHECK_CFG_TOGGLE_VALUE_( gsl_FEATURE_IMPLICIT_MACRO ) +# pragma message ("invalid configuration value gsl_FEATURE_IMPLICIT_MACRO=" gsl_STRINGIFY(gsl_FEATURE_IMPLICIT_MACRO) ", must be 0 or 1") +# endif +#else +# define gsl_FEATURE_IMPLICIT_MACRO 0 // default +#endif +#define gsl_FEATURE_IMPLICIT_MACRO_() gsl_FEATURE_IMPLICIT_MACRO + +#if defined( gsl_FEATURE_OWNER_MACRO ) +# if ! gsl_CHECK_CFG_TOGGLE_VALUE_( gsl_FEATURE_OWNER_MACRO ) +# pragma message ("invalid configuration value gsl_FEATURE_OWNER_MACRO=" gsl_STRINGIFY(gsl_FEATURE_OWNER_MACRO) ", must be 0 or 1") +# endif +#else +# define gsl_FEATURE_OWNER_MACRO (gsl_CONFIG_DEFAULTS_VERSION == 0) // default +#endif +#define gsl_FEATURE_OWNER_MACRO_() gsl_FEATURE_OWNER_MACRO + +#if defined( gsl_FEATURE_EXPERIMENTAL_RETURN_GUARD ) +# if ! gsl_CHECK_CFG_TOGGLE_VALUE_( gsl_FEATURE_EXPERIMENTAL_RETURN_GUARD ) +# pragma message ("invalid configuration value gsl_FEATURE_EXPERIMENTAL_RETURN_GUARD=" gsl_STRINGIFY(gsl_FEATURE_EXPERIMENTAL_RETURN_GUARD) ", must be 0 or 1") +# endif +#else +# define gsl_FEATURE_EXPERIMENTAL_RETURN_GUARD 0 // default +#endif +# define gsl_FEATURE_EXPERIMENTAL_RETURN_GUARD_() gsl_FEATURE_EXPERIMENTAL_RETURN_GUARD + +#if defined( gsl_FEATURE_GSL_LITE_NAMESPACE ) +# if ! gsl_CHECK_CFG_TOGGLE_VALUE_( gsl_FEATURE_GSL_LITE_NAMESPACE ) +# pragma message ("invalid configuration value gsl_FEATURE_GSL_LITE_NAMESPACE=" gsl_STRINGIFY(gsl_FEATURE_GSL_LITE_NAMESPACE) ", must be 0 or 1") +# endif +#else +# define gsl_FEATURE_GSL_LITE_NAMESPACE (gsl_CONFIG_DEFAULTS_VERSION >= 1) // default +#endif +#define gsl_FEATURE_GSL_LITE_NAMESPACE_() gsl_FEATURE_GSL_LITE_NAMESPACE + +// Configuration: Other + +#if defined( gsl_CONFIG_TRANSPARENT_NOT_NULL ) +# if ! gsl_CHECK_CFG_TOGGLE_VALUE_( gsl_CONFIG_TRANSPARENT_NOT_NULL ) +# pragma message ("invalid configuration value gsl_CONFIG_TRANSPARENT_NOT_NULL=" gsl_STRINGIFY(gsl_CONFIG_TRANSPARENT_NOT_NULL) ", must be 0 or 1") +# endif +# if gsl_CONFIG_TRANSPARENT_NOT_NULL && defined( gsl_CONFIG_NOT_NULL_GET_BY_CONST_REF ) +# error configuration option gsl_CONFIG_NOT_NULL_GET_BY_CONST_REF is meaningless if gsl_CONFIG_TRANSPARENT_NOT_NULL=1 +# endif +#else +# define gsl_CONFIG_TRANSPARENT_NOT_NULL (gsl_CONFIG_DEFAULTS_VERSION >= 1) // default +#endif +# define gsl_CONFIG_TRANSPARENT_NOT_NULL_() gsl_CONFIG_TRANSPARENT_NOT_NULL + +#if ! defined( gsl_CONFIG_DEPRECATE_TO_LEVEL ) +# if gsl_CONFIG_DEFAULTS_VERSION >= 1 +# define gsl_CONFIG_DEPRECATE_TO_LEVEL 6 +# else +# define gsl_CONFIG_DEPRECATE_TO_LEVEL 0 +# endif +#endif + +#if ! defined( gsl_CONFIG_SPAN_INDEX_TYPE ) +# define gsl_CONFIG_SPAN_INDEX_TYPE std::size_t +#endif +# define gsl_CONFIG_SPAN_INDEX_TYPE_() gsl_CONFIG_SPAN_INDEX_TYPE + +#if ! defined( gsl_CONFIG_INDEX_TYPE ) +# if gsl_CONFIG_DEFAULTS_VERSION >= 1 +// p0122r3 uses std::ptrdiff_t +# define gsl_CONFIG_INDEX_TYPE std::ptrdiff_t +# else +# define gsl_CONFIG_INDEX_TYPE gsl_CONFIG_SPAN_INDEX_TYPE +# endif +#endif +# define gsl_CONFIG_INDEX_TYPE_() gsl_CONFIG_INDEX_TYPE + +#if defined( gsl_CONFIG_NOT_NULL_EXPLICIT_CTOR ) +# if ! gsl_CHECK_CFG_TOGGLE_VALUE_( gsl_CONFIG_NOT_NULL_EXPLICIT_CTOR ) +# pragma message ("invalid configuration value gsl_CONFIG_NOT_NULL_EXPLICIT_CTOR=" gsl_STRINGIFY(gsl_CONFIG_NOT_NULL_EXPLICIT_CTOR) ", must be 0 or 1") +# endif +#else +# define gsl_CONFIG_NOT_NULL_EXPLICIT_CTOR (gsl_CONFIG_DEFAULTS_VERSION >= 1) // default +#endif +#define gsl_CONFIG_NOT_NULL_EXPLICIT_CTOR_() gsl_CONFIG_NOT_NULL_EXPLICIT_CTOR + +#if defined( gsl_CONFIG_NOT_NULL_GET_BY_CONST_REF ) +# if ! gsl_CHECK_CFG_TOGGLE_VALUE_( gsl_CONFIG_NOT_NULL_GET_BY_CONST_REF ) +# pragma message ("invalid configuration value gsl_CONFIG_NOT_NULL_GET_BY_CONST_REF=" gsl_STRINGIFY(gsl_CONFIG_NOT_NULL_GET_BY_CONST_REF) ", must be 0 or 1") +# endif +#else +# define gsl_CONFIG_NOT_NULL_GET_BY_CONST_REF 0 // default +#endif +#define gsl_CONFIG_NOT_NULL_GET_BY_CONST_REF_() gsl_CONFIG_NOT_NULL_GET_BY_CONST_REF + +#if defined( gsl_CONFIG_CONFIRMS_COMPILATION_ERRORS ) +# if ! gsl_CHECK_CFG_TOGGLE_VALUE_( gsl_CONFIG_CONFIRMS_COMPILATION_ERRORS ) +# pragma message ("invalid configuration value gsl_CONFIG_CONFIRMS_COMPILATION_ERRORS=" gsl_STRINGIFY(gsl_CONFIG_CONFIRMS_COMPILATION_ERRORS) ", must be 0 or 1") +# endif +#else +# define gsl_CONFIG_CONFIRMS_COMPILATION_ERRORS 0 // default +#endif +#define gsl_CONFIG_CONFIRMS_COMPILATION_ERRORS_() gsl_CONFIG_CONFIRMS_COMPILATION_ERRORS + +#if defined( gsl_CONFIG_ALLOWS_SPAN_COMPARISON ) +# if ! gsl_CHECK_CFG_TOGGLE_VALUE_( gsl_CONFIG_ALLOWS_SPAN_COMPARISON ) +# pragma message ("invalid configuration value gsl_CONFIG_ALLOWS_SPAN_COMPARISON=" gsl_STRINGIFY(gsl_CONFIG_ALLOWS_SPAN_COMPARISON) ", must be 0 or 1") +# endif +#else +# define gsl_CONFIG_ALLOWS_SPAN_COMPARISON (gsl_CONFIG_DEFAULTS_VERSION == 0) // default +#endif +#define gsl_CONFIG_ALLOWS_SPAN_COMPARISON_() gsl_CONFIG_ALLOWS_SPAN_COMPARISON + +#if defined( gsl_CONFIG_ALLOWS_NONSTRICT_SPAN_COMPARISON ) +# if ! gsl_CHECK_CFG_TOGGLE_VALUE_( gsl_CONFIG_ALLOWS_NONSTRICT_SPAN_COMPARISON ) +# pragma message ("invalid configuration value gsl_CONFIG_ALLOWS_NONSTRICT_SPAN_COMPARISON=" gsl_STRINGIFY(gsl_CONFIG_ALLOWS_NONSTRICT_SPAN_COMPARISON) ", must be 0 or 1") +# endif +#else +# define gsl_CONFIG_ALLOWS_NONSTRICT_SPAN_COMPARISON 1 // default +#endif +#define gsl_CONFIG_ALLOWS_NONSTRICT_SPAN_COMPARISON_() gsl_CONFIG_ALLOWS_NONSTRICT_SPAN_COMPARISON + +#if defined( gsl_CONFIG_ALLOWS_UNCONSTRAINED_SPAN_CONTAINER_CTOR ) +# if ! gsl_CHECK_CFG_TOGGLE_VALUE_( gsl_CONFIG_ALLOWS_UNCONSTRAINED_SPAN_CONTAINER_CTOR ) +# pragma message ("invalid configuration value gsl_CONFIG_ALLOWS_UNCONSTRAINED_SPAN_CONTAINER_CTOR=" gsl_STRINGIFY(gsl_CONFIG_ALLOWS_UNCONSTRAINED_SPAN_CONTAINER_CTOR) ", must be 0 or 1") +# endif +#else +# define gsl_CONFIG_ALLOWS_UNCONSTRAINED_SPAN_CONTAINER_CTOR 0 // default +#endif +#define gsl_CONFIG_ALLOWS_UNCONSTRAINED_SPAN_CONTAINER_CTOR_() gsl_CONFIG_ALLOWS_UNCONSTRAINED_SPAN_CONTAINER_CTOR + +#if defined( gsl_CONFIG_NARROW_THROWS_ON_TRUNCATION ) +# if ! gsl_CHECK_CFG_TOGGLE_VALUE_( gsl_CONFIG_NARROW_THROWS_ON_TRUNCATION ) +# pragma message ("invalid configuration value gsl_CONFIG_NARROW_THROWS_ON_TRUNCATION=" gsl_STRINGIFY(gsl_CONFIG_NARROW_THROWS_ON_TRUNCATION) ", must be 0 or 1") +# endif +#else +# define gsl_CONFIG_NARROW_THROWS_ON_TRUNCATION (gsl_CONFIG_DEFAULTS_VERSION >= 1) // default +#endif +#define gsl_CONFIG_NARROW_THROWS_ON_TRUNCATION_() gsl_CONFIG_NARROW_THROWS_ON_TRUNCATION + +#if defined( gsl_CONFIG_CONTRACT_CHECKING_EXPECTS_OFF ) +# if ! gsl_CHECK_CFG_NO_VALUE_( gsl_CONFIG_CONTRACT_CHECKING_EXPECTS_OFF ) +# pragma message ("invalid configuration value gsl_CONFIG_CONTRACT_CHECKING_EXPECTS_OFF=" gsl_STRINGIFY(gsl_CONFIG_CONTRACT_CHECKING_EXPECTS_OFF) "; macro must be defined without value") +# endif +#endif +#if defined( gsl_CONFIG_CONTRACT_CHECKING_ENSURES_OFF ) +# if ! gsl_CHECK_CFG_NO_VALUE_( gsl_CONFIG_CONTRACT_CHECKING_ENSURES_OFF ) +# pragma message ("invalid configuration value gsl_CONFIG_CONTRACT_CHECKING_ENSURES_OFF=" gsl_STRINGIFY(gsl_CONFIG_CONTRACT_CHECKING_ENSURES_OFF) "; macro must be defined without value") +# endif +#endif +#if defined( gsl_CONFIG_CONTRACT_CHECKING_ASSERT_OFF ) +# if ! gsl_CHECK_CFG_NO_VALUE_( gsl_CONFIG_CONTRACT_CHECKING_ASSERT_OFF ) +# pragma message ("invalid configuration value gsl_CONFIG_CONTRACT_CHECKING_ASSERT_OFF=" gsl_STRINGIFY(gsl_CONFIG_CONTRACT_CHECKING_ASSERT_OFF) "; macro must be defined without value") +# endif +#endif +#if defined( gsl_CONFIG_CONTRACT_CHECKING_AUDIT ) +# if ! gsl_CHECK_CFG_NO_VALUE_( gsl_CONFIG_CONTRACT_CHECKING_AUDIT ) +# pragma message ("invalid configuration value gsl_CONFIG_CONTRACT_CHECKING_AUDIT=" gsl_STRINGIFY(gsl_CONFIG_CONTRACT_CHECKING_AUDIT) "; macro must be defined without value") +# endif +#endif +#if defined( gsl_CONFIG_CONTRACT_CHECKING_ON ) +# if ! gsl_CHECK_CFG_NO_VALUE_( gsl_CONFIG_CONTRACT_CHECKING_ON ) +# pragma message ("invalid configuration value gsl_CONFIG_CONTRACT_CHECKING_ON=" gsl_STRINGIFY(gsl_CONFIG_CONTRACT_CHECKING_ON) "; macro must be defined without value") +# endif +#endif +#if defined( gsl_CONFIG_CONTRACT_CHECKING_OFF ) +# if ! gsl_CHECK_CFG_NO_VALUE_( gsl_CONFIG_CONTRACT_CHECKING_OFF ) +# pragma message ("invalid configuration value gsl_CONFIG_CONTRACT_CHECKING_OFF=" gsl_STRINGIFY(gsl_CONFIG_CONTRACT_CHECKING_OFF) "; macro must be defined without value") +# endif +#endif +#if defined( gsl_CONFIG_CONTRACT_VIOLATION_THROWS ) +# if ! gsl_CHECK_CFG_NO_VALUE_( gsl_CONFIG_CONTRACT_VIOLATION_THROWS ) +# pragma message ("invalid configuration value gsl_CONFIG_CONTRACT_VIOLATION_THROWS=" gsl_STRINGIFY(gsl_CONFIG_CONTRACT_VIOLATION_THROWS) "; macro must be defined without value") +# endif +#endif +#if defined( gsl_CONFIG_CONTRACT_VIOLATION_TERMINATES ) +# if ! gsl_CHECK_CFG_NO_VALUE_( gsl_CONFIG_CONTRACT_VIOLATION_TERMINATES ) +# pragma message ("invalid configuration value gsl_CONFIG_CONTRACT_VIOLATION_TERMINATES=" gsl_STRINGIFY(gsl_CONFIG_CONTRACT_VIOLATION_TERMINATES) "; macro must be defined without value") +# endif +#endif +#if defined( gsl_CONFIG_CONTRACT_VIOLATION_ASSERTS ) +# if ! gsl_CHECK_CFG_NO_VALUE_( gsl_CONFIG_CONTRACT_VIOLATION_ASSERTS ) +# pragma message ("invalid configuration value gsl_CONFIG_CONTRACT_VIOLATION_ASSERTS=" gsl_STRINGIFY(gsl_CONFIG_CONTRACT_VIOLATION_ASSERTS) "; macro must be defined without value") +# endif +#endif +#if defined( gsl_CONFIG_CONTRACT_VIOLATION_TRAPS ) +# if ! gsl_CHECK_CFG_NO_VALUE_( gsl_CONFIG_CONTRACT_VIOLATION_TRAPS ) +# pragma message ("invalid configuration value gsl_CONFIG_CONTRACT_VIOLATION_TRAPS=" gsl_STRINGIFY(gsl_CONFIG_CONTRACT_VIOLATION_TRAPS) "; macro must be defined without value") +# endif +#endif +#if defined( gsl_CONFIG_CONTRACT_VIOLATION_CALLS_HANDLER ) +# if ! gsl_CHECK_CFG_NO_VALUE_( gsl_CONFIG_CONTRACT_VIOLATION_CALLS_HANDLER ) +# pragma message ("invalid configuration value gsl_CONFIG_CONTRACT_VIOLATION_CALLS_HANDLER=" gsl_STRINGIFY(gsl_CONFIG_CONTRACT_VIOLATION_CALLS_HANDLER) "; macro must be defined without value") +# endif +#endif +#if defined( gsl_CONFIG_UNENFORCED_CONTRACTS_ASSUME ) +# if ! gsl_CHECK_CFG_NO_VALUE_( gsl_CONFIG_UNENFORCED_CONTRACTS_ASSUME ) +# pragma message ("invalid configuration value gsl_CONFIG_UNENFORCED_CONTRACTS_ASSUME=" gsl_STRINGIFY(gsl_CONFIG_UNENFORCED_CONTRACTS_ASSUME) "; macro must be defined without value") +# endif +#endif +#if defined( gsl_CONFIG_UNENFORCED_CONTRACTS_ELIDE ) +# if ! gsl_CHECK_CFG_NO_VALUE_( gsl_CONFIG_UNENFORCED_CONTRACTS_ELIDE ) +# pragma message ("invalid configuration value gsl_CONFIG_UNENFORCED_CONTRACTS_ELIDE=" gsl_STRINGIFY(gsl_CONFIG_UNENFORCED_CONTRACTS_ELIDE) "; macro must be defined without value") +# endif +#endif + +#if 1 < defined( gsl_CONFIG_CONTRACT_CHECKING_AUDIT ) + defined( gsl_CONFIG_CONTRACT_CHECKING_ON ) + defined( gsl_CONFIG_CONTRACT_CHECKING_OFF ) +# error only one of gsl_CONFIG_CONTRACT_CHECKING_AUDIT, gsl_CONFIG_CONTRACT_CHECKING_ON, and gsl_CONFIG_CONTRACT_CHECKING_OFF may be defined +#endif +#if 1 < defined( gsl_CONFIG_CONTRACT_VIOLATION_THROWS ) + defined( gsl_CONFIG_CONTRACT_VIOLATION_TERMINATES ) + defined( gsl_CONFIG_CONTRACT_VIOLATION_ASSERTS ) + defined( gsl_CONFIG_CONTRACT_VIOLATION_TRAPS ) + defined( gsl_CONFIG_CONTRACT_VIOLATION_CALLS_HANDLER ) +# error only one of gsl_CONFIG_CONTRACT_VIOLATION_THROWS, gsl_CONFIG_CONTRACT_VIOLATION_TERMINATES, gsl_CONFIG_CONTRACT_VIOLATION_ASSERTS, gsl_CONFIG_CONTRACT_VIOLATION_TRAPS, and gsl_CONFIG_CONTRACT_VIOLATION_CALLS_HANDLER may be defined +#endif +#if 1 < defined( gsl_CONFIG_UNENFORCED_CONTRACTS_ASSUME ) + defined( gsl_CONFIG_UNENFORCED_CONTRACTS_ELIDE ) +# error only one of gsl_CONFIG_UNENFORCED_CONTRACTS_ASSUME and gsl_CONFIG_UNENFORCED_CONTRACTS_ELIDE may be defined +#endif + +#if 0 == defined( gsl_CONFIG_CONTRACT_CHECKING_AUDIT ) + defined( gsl_CONFIG_CONTRACT_CHECKING_ON ) + defined( gsl_CONFIG_CONTRACT_CHECKING_OFF ) +// select default +# define gsl_CONFIG_CONTRACT_CHECKING_ON +#endif +#if 0 == defined( gsl_CONFIG_CONTRACT_VIOLATION_THROWS ) + defined( gsl_CONFIG_CONTRACT_VIOLATION_TERMINATES ) + defined( gsl_CONFIG_CONTRACT_VIOLATION_ASSERTS ) + defined( gsl_CONFIG_CONTRACT_VIOLATION_TRAPS ) + defined( gsl_CONFIG_CONTRACT_VIOLATION_CALLS_HANDLER ) +// select default +# define gsl_CONFIG_CONTRACT_VIOLATION_TERMINATES +#endif +#if 0 == defined( gsl_CONFIG_UNENFORCED_CONTRACTS_ASSUME ) + defined( gsl_CONFIG_UNENFORCED_CONTRACTS_ELIDE ) +// select default +# define gsl_CONFIG_UNENFORCED_CONTRACTS_ELIDE +#endif + +// C++ language version detection (C++20 is speculative): +// Note: VC14.0/1900 (VS2015) lacks too much from C++14. + +#ifndef gsl_CPLUSPLUS +# if defined(_MSVC_LANG ) && !defined(__clang__) +# define gsl_CPLUSPLUS (_MSC_VER == 1900 ? 201103L : _MSVC_LANG ) +# else +# define gsl_CPLUSPLUS __cplusplus +# endif +#endif + +// C++ standard library version: + +#ifndef gsl_CPLUSPLUS_STDLIB +# define gsl_CPLUSPLUS_STDLIB gsl_CPLUSPLUS +#endif + +#define gsl_CPP98_OR_GREATER ( gsl_CPLUSPLUS >= 199711L ) +#define gsl_CPP11_OR_GREATER ( gsl_CPLUSPLUS >= 201103L ) +#define gsl_CPP14_OR_GREATER ( gsl_CPLUSPLUS >= 201402L ) +#define gsl_CPP17_OR_GREATER ( gsl_CPLUSPLUS >= 201703L ) +#define gsl_CPP20_OR_GREATER ( gsl_CPLUSPLUS >= 202000L ) + +// C++ language version (represent 98 as 3): + +#define gsl_CPLUSPLUS_V ( gsl_CPLUSPLUS / 100 - (gsl_CPLUSPLUS > 200000 ? 2000 : 1994) ) + +// half-open range [lo..hi): +#define gsl_BETWEEN( v, lo, hi ) ( (lo) <= (v) && (v) < (hi) ) + +// Compiler versions: + +// MSVC++ 6.0 _MSC_VER == 1200 gsl_COMPILER_MSVC_VERSION == 60 (Visual Studio 6.0) +// MSVC++ 7.0 _MSC_VER == 1300 gsl_COMPILER_MSVC_VERSION == 70 (Visual Studio .NET 2002) +// MSVC++ 7.1 _MSC_VER == 1310 gsl_COMPILER_MSVC_VERSION == 71 (Visual Studio .NET 2003) +// MSVC++ 8.0 _MSC_VER == 1400 gsl_COMPILER_MSVC_VERSION == 80 (Visual Studio 2005) +// MSVC++ 9.0 _MSC_VER == 1500 gsl_COMPILER_MSVC_VERSION == 90 (Visual Studio 2008) +// MSVC++ 10.0 _MSC_VER == 1600 gsl_COMPILER_MSVC_VERSION == 100 (Visual Studio 2010) +// MSVC++ 11.0 _MSC_VER == 1700 gsl_COMPILER_MSVC_VERSION == 110 (Visual Studio 2012) +// MSVC++ 12.0 _MSC_VER == 1800 gsl_COMPILER_MSVC_VERSION == 120 (Visual Studio 2013) +// MSVC++ 14.0 _MSC_VER == 1900 gsl_COMPILER_MSVC_VERSION == 140 (Visual Studio 2015) +// MSVC++ 14.1 _MSC_VER >= 1910 gsl_COMPILER_MSVC_VERSION == 141 (Visual Studio 2017) +// MSVC++ 14.2 _MSC_VER >= 1920 gsl_COMPILER_MSVC_VERSION == 142 (Visual Studio 2019) + +#if defined( _MSC_VER ) && ! defined( __clang__ ) +# define gsl_COMPILER_MSVC_VER (_MSC_VER ) +# define gsl_COMPILER_MSVC_VERSION (_MSC_VER / 10 - 10 * ( 5 + (_MSC_VER < 1900 ) ) ) +# define gsl_COMPILER_MSVC_VERSION_FULL (_MSC_VER - 100 * ( 5 + (_MSC_VER < 1900 ) ) ) +#else +# define gsl_COMPILER_MSVC_VER 0 +# define gsl_COMPILER_MSVC_VERSION 0 +# define gsl_COMPILER_MSVC_VERSION_FULL 0 +#endif + +#define gsl_COMPILER_VERSION( major, minor, patch ) ( 10 * ( 10 * (major) + (minor) ) + (patch) ) + +// AppleClang 7.0.0 __apple_build_version__ == 7000172 gsl_COMPILER_APPLECLANG_VERSION == 700 (Xcode 7.0, 7.0.1) (LLVM 3.7.0) +// AppleClang 7.0.0 __apple_build_version__ == 7000176 gsl_COMPILER_APPLECLANG_VERSION == 700 (Xcode 7.1) (LLVM 3.7.0) +// AppleClang 7.0.2 __apple_build_version__ == 7000181 gsl_COMPILER_APPLECLANG_VERSION == 702 (Xcode 7.2, 7.2.1) (LLVM 3.7.0) +// AppleClang 7.3.0 __apple_build_version__ == 7030029 gsl_COMPILER_APPLECLANG_VERSION == 730 (Xcode 7.3) (LLVM 3.8.0) +// AppleClang 7.3.0 __apple_build_version__ == 7030031 gsl_COMPILER_APPLECLANG_VERSION == 730 (Xcode 7.3.1) (LLVM 3.8.0) +// AppleClang 8.0.0 __apple_build_version__ == 8000038 gsl_COMPILER_APPLECLANG_VERSION == 800 (Xcode 8.0) (LLVM 3.9.0) +// AppleClang 8.0.0 __apple_build_version__ == 8000042 gsl_COMPILER_APPLECLANG_VERSION == 800 (Xcode 8.1, 8.2, 8.2.1) (LLVM 3.9.0) +// AppleClang 8.1.0 __apple_build_version__ == 8020038 gsl_COMPILER_APPLECLANG_VERSION == 810 (Xcode 8.3) (LLVM 3.9.0) +// AppleClang 8.1.0 __apple_build_version__ == 8020041 gsl_COMPILER_APPLECLANG_VERSION == 810 (Xcode 8.3.1) (LLVM 3.9.0) +// AppleClang 8.1.0 __apple_build_version__ == 8020042 gsl_COMPILER_APPLECLANG_VERSION == 810 (Xcode 8.3.2, 8.3.3) (LLVM 3.9.0) +// AppleClang 9.0.0 __apple_build_version__ == 9000037 gsl_COMPILER_APPLECLANG_VERSION == 900 (Xcode 9.0) (LLVM 4.0.0) +// AppleClang 9.0.0 __apple_build_version__ == 9000038 gsl_COMPILER_APPLECLANG_VERSION == 900 (Xcode 9.1) (LLVM 4.0.0) +// AppleClang 9.0.0 __apple_build_version__ == 9000039 gsl_COMPILER_APPLECLANG_VERSION == 900 (Xcode 9.2) (LLVM 4.0.0) +// AppleClang 9.1.0 __apple_build_version__ == 9020039 gsl_COMPILER_APPLECLANG_VERSION == 910 (Xcode 9.3, 9.3.1) (LLVM 5.0.2) +// AppleClang 9.1.0 __apple_build_version__ == 9020039 gsl_COMPILER_APPLECLANG_VERSION == 910 (Xcode 9.4, 9.4.1) (LLVM 5.0.2) +// AppleClang 10.0.0 __apple_build_version__ == 10001145 gsl_COMPILER_APPLECLANG_VERSION == 1000 (Xcode 10.0, 10.1) (LLVM 6.0.1) +// AppleClang 10.0.1 __apple_build_version__ == 10010046 gsl_COMPILER_APPLECLANG_VERSION == 1001 (Xcode 10.2, 10.2.1, 10.3) (LLVM 7.0.0) +// AppleClang 11.0.0 __apple_build_version__ == 11000033 gsl_COMPILER_APPLECLANG_VERSION == 1100 (Xcode 11.1, 11.2, 11.3, 11.3.1) (LLVM 8.0.0) +// AppleClang 11.0.3 __apple_build_version__ == 11030032 gsl_COMPILER_APPLECLANG_VERSION == 1103 (Xcode 11.4, 11.4.1, 11.5, 11.6) (LLVM 9.0.0) +// AppleClang 12.0.0 __apple_build_version__ == 12000032 gsl_COMPILER_APPLECLANG_VERSION == 1200 (Xcode 12.0–12.4) (LLVM 10.0.0) +// AppleClang 12.0.5 __apple_build_version__ == 12050022 gsl_COMPILER_APPLECLANG_VERSION == 1205 (Xcode 12.5) (LLVM 10.0.0) + +#if defined( __apple_build_version__ ) +# define gsl_COMPILER_APPLECLANG_VERSION gsl_COMPILER_VERSION( __clang_major__, __clang_minor__, __clang_patchlevel__ ) +# define gsl_COMPILER_CLANG_VERSION 0 +#elif defined( __clang__ ) +# define gsl_COMPILER_APPLECLANG_VERSION 0 +# define gsl_COMPILER_CLANG_VERSION gsl_COMPILER_VERSION( __clang_major__, __clang_minor__, __clang_patchlevel__ ) +#else +# define gsl_COMPILER_APPLECLANG_VERSION 0 +# define gsl_COMPILER_CLANG_VERSION 0 +#endif + +#if defined( __GNUC__ ) && ! defined( __clang__ ) +# define gsl_COMPILER_GNUC_VERSION gsl_COMPILER_VERSION( __GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__ ) +#else +# define gsl_COMPILER_GNUC_VERSION 0 +#endif + +#if defined( __NVCC__ ) +# define gsl_COMPILER_NVCC_VERSION ( __CUDACC_VER_MAJOR__ * 10 + __CUDACC_VER_MINOR__ ) +#else +# define gsl_COMPILER_NVCC_VERSION 0 +#endif + +#if defined( __ARMCC_VERSION ) +# define gsl_COMPILER_ARMCC_VERSION ( __ARMCC_VERSION / 10000 ) +# define gsl_COMPILER_ARMCC_VERSION_FULL __ARMCC_VERSION +#else +# define gsl_COMPILER_ARMCC_VERSION 0 +# define gsl_COMPILER_ARMCC_VERSION_FULL 0 +#endif + +// Compiler non-strict aliasing: + +#if defined(__clang__) || defined(__GNUC__) +# define gsl_may_alias __attribute__((__may_alias__)) +#else +# define gsl_may_alias +#endif + +// Presence of gsl, language and library features: + +#define gsl_IN_STD( v ) ( ((v) == 98 ? 3 : (v)) >= gsl_CPLUSPLUS_V ) + +#define gsl_DEPRECATE_TO_LEVEL( level ) ( level <= gsl_CONFIG_DEPRECATE_TO_LEVEL ) +#define gsl_FEATURE_TO_STD( feature ) gsl_IN_STD( gsl_FEATURE( feature##_TO_STD ) ) +#define gsl_FEATURE( feature ) gsl_EVALF_( gsl_FEATURE_##feature##_ ) +#define gsl_CONFIG( feature ) gsl_EVALF_( gsl_CONFIG_##feature##_ ) +#define gsl_HAVE( feature ) gsl_EVALF_( gsl_HAVE_##feature##_ ) + +// Presence of wide character support: + +#ifdef __DJGPP__ +# define gsl_HAVE_WCHAR 0 +#else +# define gsl_HAVE_WCHAR 1 +#endif +#define gsl_HAVE_WCHAR_() gsl_HAVE_WCHAR + +// Presence of language & library features: + +#if gsl_COMPILER_CLANG_VERSION || gsl_COMPILER_APPLECLANG_VERSION +# ifdef __OBJC__ + // There are a bunch of inconsistencies about __EXCEPTIONS and __has_feature(cxx_exceptions) in Clang 3.4/3.5/3.6. + // We're interested in C++ exceptions, which can be checked by __has_feature(cxx_exceptions) in 3.5+. + // In pre-3.5, __has_feature(cxx_exceptions) can be true if ObjC exceptions are enabled, but C++ exceptions are disabled. + // The recommended way to check is `__EXCEPTIONS && __has_feature(cxx_exceptions)`. + // See https://releases.llvm.org/3.6.0/tools/clang/docs/ReleaseNotes.html#the-exceptions-macro + // Note: this is only relevant in Objective-C++, thus the ifdef. +# if __EXCEPTIONS && __has_feature(cxx_exceptions) +# define gsl_HAVE_EXCEPTIONS 1 +# else +# define gsl_HAVE_EXCEPTIONS 0 +# endif // __EXCEPTIONS && __has_feature(cxx_exceptions) +# else + // clang-cl doesn't define __EXCEPTIONS for MSVC compatibility (see https://reviews.llvm.org/D4065). + // Neither does Clang in MS-compatiblity mode. + // Let's hope no one tries to build Objective-C++ code using MS-compatibility mode or clang-cl. +# if __has_feature(cxx_exceptions) +# define gsl_HAVE_EXCEPTIONS 1 +# else +# define gsl_HAVE_EXCEPTIONS 0 +# endif +# endif +#elif gsl_COMPILER_GNUC_VERSION +# if gsl_BETWEEN(gsl_COMPILER_GNUC_VERSION, 1, 500) +# ifdef __EXCEPTIONS +# define gsl_HAVE_EXCEPTIONS 1 +# else +# define gsl_HAVE_EXCEPTIONS 0 +# endif // __EXCEPTIONS +# else +# ifdef __cpp_exceptions +# define gsl_HAVE_EXCEPTIONS 1 +# else +# define gsl_HAVE_EXCEPTIONS 0 +# endif // __cpp_exceptions +# endif // gsl_BETWEEN(gsl_COMPILER_GNUC_VERSION, 1, 500) +#elif gsl_COMPILER_MSVC_VERSION +# ifdef _CPPUNWIND +# define gsl_HAVE_EXCEPTIONS 1 +# else +# define gsl_HAVE_EXCEPTIONS 0 +# endif // _CPPUNWIND +#else +// For all other compilers, assume exceptions are always enabled. +# define gsl_HAVE_EXCEPTIONS 1 +#endif +#define gsl_HAVE_EXCEPTIONS_() gsl_HAVE_EXCEPTIONS + +#if defined( gsl_CONFIG_CONTRACT_VIOLATION_THROWS ) && ! gsl_HAVE_EXCEPTIONS +# error Cannot use gsl_CONFIG_CONTRACT_VIOLATION_THROWS if exceptions are disabled. +#endif // defined( gsl_CONFIG_CONTRACT_VIOLATION_THROWS ) && !gsl_HAVE( EXCEPTIONS ) + +#ifdef _HAS_CPP0X +# define gsl_HAS_CPP0X _HAS_CPP0X +#else +# define gsl_HAS_CPP0X 0 +#endif + +#define gsl_CPP11_100 (gsl_CPP11_OR_GREATER || gsl_COMPILER_MSVC_VER >= 1600) +#define gsl_CPP11_110 (gsl_CPP11_OR_GREATER || gsl_COMPILER_MSVC_VER >= 1700) +#define gsl_CPP11_120 (gsl_CPP11_OR_GREATER || gsl_COMPILER_MSVC_VER >= 1800) +#define gsl_CPP11_140 (gsl_CPP11_OR_GREATER || gsl_COMPILER_MSVC_VER >= 1900) + +#define gsl_CPP14_000 (gsl_CPP14_OR_GREATER) +#define gsl_CPP14_120 (gsl_CPP14_OR_GREATER || gsl_COMPILER_MSVC_VER >= 1800) +#define gsl_CPP14_140 (gsl_CPP14_OR_GREATER || gsl_COMPILER_MSVC_VER >= 1900) + +#define gsl_CPP17_000 (gsl_CPP17_OR_GREATER) +#define gsl_CPP17_140 (gsl_CPP17_OR_GREATER || gsl_COMPILER_MSVC_VER >= 1900) + +#define gsl_CPP11_140_CPP0X_90 (gsl_CPP11_140 || (gsl_COMPILER_MSVC_VER >= 1500 && gsl_HAS_CPP0X)) +#define gsl_CPP11_140_CPP0X_100 (gsl_CPP11_140 || (gsl_COMPILER_MSVC_VER >= 1600 && gsl_HAS_CPP0X)) + +// Presence of C++11 language features: + +#define gsl_HAVE_C99_PREPROCESSOR gsl_CPP11_140 +#define gsl_HAVE_AUTO gsl_CPP11_100 +#define gsl_HAVE_RVALUE_REFERENCE gsl_CPP11_100 +#define gsl_HAVE_FUNCTION_REF_QUALIFIER ( gsl_CPP11_140 && ! gsl_BETWEEN( gsl_COMPILER_GNUC_VERSION, 1, 481 ) ) +#define gsl_HAVE_ENUM_CLASS gsl_CPP11_110 +#define gsl_HAVE_ALIAS_TEMPLATE gsl_CPP11_120 +#define gsl_HAVE_DEFAULT_FUNCTION_TEMPLATE_ARG gsl_CPP11_120 +#define gsl_HAVE_EXPLICIT gsl_CPP11_120 +#define gsl_HAVE_VARIADIC_TEMPLATE gsl_CPP11_120 +#define gsl_HAVE_IS_DELETE gsl_CPP11_120 +#define gsl_HAVE_CONSTEXPR_11 gsl_CPP11_140 +#define gsl_HAVE_IS_DEFAULT gsl_CPP11_140 +#define gsl_HAVE_NOEXCEPT gsl_CPP11_140 +#define gsl_HAVE_NORETURN ( gsl_CPP11_140 && ! gsl_BETWEEN( gsl_COMPILER_GNUC_VERSION, 1, 480 ) ) +#define gsl_HAVE_EXPRESSION_SFINAE gsl_CPP11_140 +#define gsl_HAVE_OVERRIDE_FINAL gsl_CPP11_110 + +#define gsl_HAVE_C99_PREPROCESSOR_() gsl_HAVE_C99_PREPROCESSOR +#define gsl_HAVE_AUTO_() gsl_HAVE_AUTO +#define gsl_HAVE_RVALUE_REFERENCE_() gsl_HAVE_RVALUE_REFERENCE +#define gsl_HAVE_FUNCTION_REF_QUALIFIER_() gsl_HAVE_FUNCTION_REF_QUALIFIER +#define gsl_HAVE_ENUM_CLASS_() gsl_HAVE_ENUM_CLASS +#define gsl_HAVE_ALIAS_TEMPLATE_() gsl_HAVE_ALIAS_TEMPLATE +#define gsl_HAVE_DEFAULT_FUNCTION_TEMPLATE_ARG_() gsl_HAVE_DEFAULT_FUNCTION_TEMPLATE_ARG +#define gsl_HAVE_EXPLICIT_() gsl_HAVE_EXPLICIT +#define gsl_HAVE_VARIADIC_TEMPLATE_() gsl_HAVE_VARIADIC_TEMPLATE +#define gsl_HAVE_IS_DELETE_() gsl_HAVE_IS_DELETE +#define gsl_HAVE_CONSTEXPR_11_() gsl_HAVE_CONSTEXPR_11 +#define gsl_HAVE_IS_DEFAULT_() gsl_HAVE_IS_DEFAULT +#define gsl_HAVE_NOEXCEPT_() gsl_HAVE_NOEXCEPT +#define gsl_HAVE_NORETURN_() gsl_HAVE_NORETURN +#define gsl_HAVE_EXPRESSION_SFINAE_() gsl_HAVE_EXPRESSION_SFINAE +#define gsl_HAVE_OVERRIDE_FINAL_() gsl_HAVE_OVERRIDE_FINAL + +// Presence of C++14 language features: + +#define gsl_HAVE_CONSTEXPR_14 ( gsl_CPP14_000 && ! gsl_BETWEEN( gsl_COMPILER_GNUC_VERSION, 1, 600 ) ) +#define gsl_HAVE_DECLTYPE_AUTO gsl_CPP14_140 +#define gsl_HAVE_DEPRECATED ( gsl_CPP14_140 && ! gsl_BETWEEN( gsl_COMPILER_MSVC_VERSION, 1, 142 ) ) + +#define gsl_HAVE_CONSTEXPR_14_() gsl_HAVE_CONSTEXPR_14 +#define gsl_HAVE_DECLTYPE_AUTO_() gsl_HAVE_DECLTYPE_AUTO +#define gsl_HAVE_DEPRECATED_() gsl_HAVE_DEPRECATED + +// Presence of C++17 language features: +// MSVC: template parameter deduction guides since Visual Studio 2017 v15.7 + +#define gsl_HAVE_ENUM_CLASS_CONSTRUCTION_FROM_UNDERLYING_TYPE gsl_CPP17_000 +#define gsl_HAVE_DEDUCTION_GUIDES ( gsl_CPP17_000 && ! gsl_BETWEEN( gsl_COMPILER_MSVC_VERSION_FULL, 1, 1414 ) ) +#define gsl_HAVE_NODISCARD gsl_CPP17_000 +#define gsl_HAVE_CONSTEXPR_17 gsl_CPP17_OR_GREATER + +#define gsl_HAVE_ENUM_CLASS_CONSTRUCTION_FROM_UNDERLYING_TYPE_() gsl_HAVE_ENUM_CLASS_CONSTRUCTION_FROM_UNDERLYING_TYPE +#define gsl_HAVE_DEDUCTION_GUIDES_() gsl_HAVE_DEDUCTION_GUIDES +#define gsl_HAVE_NODISCARD_() gsl_HAVE_NODISCARD +#define gsl_HAVE_CONSTEXPR_17_() gsl_HAVE_CONSTEXPR_17 + +// Presence of C++20 language features: + +#define gsl_HAVE_CONSTEXPR_20 gsl_CPP20_OR_GREATER + +#define gsl_HAVE_CONSTEXPR_20_() gsl_HAVE_CONSTEXPR_20 + +// Presence of C++ library features: + +#if gsl_BETWEEN( gsl_COMPILER_ARMCC_VERSION, 1, 600 ) +// Some versions of the ARM compiler apparently ship without a C++11 standard library despite having some C++11 support. +# define gsl_STDLIB_CPP98_OR_GREATER gsl_CPP98_OR_GREATER +# define gsl_STDLIB_CPP11_OR_GREATER 0 +# define gsl_STDLIB_CPP14_OR_GREATER 0 +# define gsl_STDLIB_CPP17_OR_GREATER 0 +# define gsl_STDLIB_CPP20_OR_GREATER 0 +#else +# define gsl_STDLIB_CPP98_OR_GREATER gsl_CPP98_OR_GREATER +# define gsl_STDLIB_CPP11_OR_GREATER gsl_CPP11_OR_GREATER +# define gsl_STDLIB_CPP14_OR_GREATER gsl_CPP14_OR_GREATER +# define gsl_STDLIB_CPP17_OR_GREATER gsl_CPP17_OR_GREATER +# define gsl_STDLIB_CPP20_OR_GREATER gsl_CPP20_OR_GREATER +#endif + +#define gsl_STDLIB_CPP11_100 (gsl_STDLIB_CPP11_OR_GREATER || gsl_COMPILER_MSVC_VER >= 1600) +#define gsl_STDLIB_CPP11_110 (gsl_STDLIB_CPP11_OR_GREATER || gsl_COMPILER_MSVC_VER >= 1700) +#define gsl_STDLIB_CPP11_120 (gsl_STDLIB_CPP11_OR_GREATER || gsl_COMPILER_MSVC_VER >= 1800) +#define gsl_STDLIB_CPP11_140 (gsl_STDLIB_CPP11_OR_GREATER || gsl_COMPILER_MSVC_VER >= 1900) + +#define gsl_STDLIB_CPP14_000 (gsl_STDLIB_CPP14_OR_GREATER) +#define gsl_STDLIB_CPP14_120 (gsl_STDLIB_CPP14_OR_GREATER || gsl_COMPILER_MSVC_VER >= 1800) +#define gsl_STDLIB_CPP14_140 (gsl_STDLIB_CPP14_OR_GREATER || gsl_COMPILER_MSVC_VER >= 1900) + +#define gsl_STDLIB_CPP17_000 (gsl_STDLIB_CPP17_OR_GREATER) +#define gsl_STDLIB_CPP17_140 (gsl_STDLIB_CPP17_OR_GREATER || gsl_COMPILER_MSVC_VER >= 1900) + +#define gsl_STDLIB_CPP11_140_CPP0X_90 (gsl_STDLIB_CPP11_140 || (gsl_COMPILER_MSVC_VER >= 1500 && gsl_HAS_CPP0X)) +#define gsl_STDLIB_CPP11_140_CPP0X_100 (gsl_STDLIB_CPP11_140 || (gsl_COMPILER_MSVC_VER >= 1600 && gsl_HAS_CPP0X)) + +#define gsl_HAVE_ADDRESSOF gsl_STDLIB_CPP17_000 +#define gsl_HAVE_ARRAY gsl_STDLIB_CPP11_110 +#define gsl_HAVE_TYPE_TRAITS gsl_STDLIB_CPP11_110 +#define gsl_HAVE_TR1_TYPE_TRAITS gsl_STDLIB_CPP11_110 +#define gsl_HAVE_CONTAINER_DATA_METHOD gsl_STDLIB_CPP11_140_CPP0X_90 +#define gsl_HAVE_STD_DATA gsl_STDLIB_CPP17_000 +#ifdef __cpp_lib_ssize +# define gsl_HAVE_STD_SSIZE 1 +#else +# define gsl_HAVE_STD_SSIZE ( gsl_COMPILER_GNUC_VERSION >= 1000 && __cplusplus > 201703L ) +#endif +#define gsl_HAVE_HASH gsl_STDLIB_CPP11_120 +#define gsl_HAVE_SIZED_TYPES gsl_STDLIB_CPP11_140 +#define gsl_HAVE_MAKE_SHARED gsl_STDLIB_CPP11_140_CPP0X_100 +#define gsl_HAVE_SHARED_PTR gsl_STDLIB_CPP11_140_CPP0X_100 +#define gsl_HAVE_UNIQUE_PTR gsl_STDLIB_CPP11_140_CPP0X_100 +#define gsl_HAVE_MAKE_UNIQUE gsl_STDLIB_CPP14_120 +#define gsl_HAVE_MOVE_FORWARD gsl_STDLIB_CPP11_100 +#define gsl_HAVE_NULLPTR gsl_STDLIB_CPP11_100 +#define gsl_HAVE_UNCAUGHT_EXCEPTIONS gsl_STDLIB_CPP17_140 +#define gsl_HAVE_ADD_CONST gsl_HAVE_TYPE_TRAITS +#define gsl_HAVE_INITIALIZER_LIST gsl_STDLIB_CPP11_120 +#define gsl_HAVE_INTEGRAL_CONSTANT gsl_HAVE_TYPE_TRAITS +#define gsl_HAVE_REMOVE_CONST gsl_HAVE_TYPE_TRAITS +#define gsl_HAVE_REMOVE_REFERENCE gsl_HAVE_TYPE_TRAITS +#define gsl_HAVE_REMOVE_CVREF gsl_STDLIB_CPP20_OR_GREATER +#define gsl_HAVE_TR1_ADD_CONST gsl_HAVE_TR1_TYPE_TRAITS +#define gsl_HAVE_TR1_INTEGRAL_CONSTANT gsl_HAVE_TR1_TYPE_TRAITS +#define gsl_HAVE_TR1_REMOVE_CONST gsl_HAVE_TR1_TYPE_TRAITS +#define gsl_HAVE_TR1_REMOVE_REFERENCE gsl_HAVE_TR1_TYPE_TRAITS + +#define gsl_HAVE_ADDRESSOF_() gsl_HAVE_ADDRESSOF +#define gsl_HAVE_ARRAY_() gsl_HAVE_ARRAY +#define gsl_HAVE_TYPE_TRAITS_() gsl_HAVE_TYPE_TRAITS +#define gsl_HAVE_TR1_TYPE_TRAITS_() gsl_HAVE_TR1_TYPE_TRAITS +#define gsl_HAVE_CONTAINER_DATA_METHOD_() gsl_HAVE_CONTAINER_DATA_METHOD +#define gsl_HAVE_HASH_() gsl_HAVE_HASH +#define gsl_HAVE_STD_DATA_() gsl_HAVE_STD_DATA +#define gsl_HAVE_STD_SSIZE_() gsl_HAVE_STD_SSIZE +#define gsl_HAVE_SIZED_TYPES_() gsl_HAVE_SIZED_TYPES +#define gsl_HAVE_MAKE_SHARED_() gsl_HAVE_MAKE_SHARED +#define gsl_HAVE_MOVE_FORWARD_() gsl_HAVE_MOVE_FORWARD +#define gsl_HAVE_NULLPTR_() gsl_HAVE_NULLPTR // It's a language feature but needs library support, so we list it as a library feature. +#define gsl_HAVE_SHARED_PTR_() gsl_HAVE_SHARED_PTR +#define gsl_HAVE_UNIQUE_PTR_() gsl_HAVE_UNIQUE_PTR +#define gsl_HAVE_MAKE_UNIQUE_() gsl_HAVE_MAKE_UNIQUE +#define gsl_HAVE_UNCAUGHT_EXCEPTIONS_() gsl_HAVE_UNCAUGHT_EXCEPTIONS +#define gsl_HAVE_ADD_CONST_() gsl_HAVE_ADD_CONST +#define gsl_HAVE_INITIALIZER_LIST_() gsl_HAVE_INITIALIZER_LIST // It's a language feature but needs library support, so we list it as a library feature. +#define gsl_HAVE_INTEGRAL_CONSTANT_() gsl_HAVE_INTEGRAL_CONSTANT +#define gsl_HAVE_REMOVE_CONST_() gsl_HAVE_REMOVE_CONST +#define gsl_HAVE_REMOVE_REFERENCE_() gsl_HAVE_REMOVE_REFERENCE +#define gsl_HAVE_REMOVE_CVREF_() gsl_HAVE_REMOVE_CVREF +#define gsl_HAVE_TR1_ADD_CONST_() gsl_HAVE_TR1_ADD_CONST +#define gsl_HAVE_TR1_INTEGRAL_CONSTANT_() gsl_HAVE_TR1_INTEGRAL_CONSTANT +#define gsl_HAVE_TR1_REMOVE_CONST_() gsl_HAVE_TR1_REMOVE_CONST +#define gsl_HAVE_TR1_REMOVE_REFERENCE_() gsl_HAVE_TR1_REMOVE_REFERENCE + +// C++ feature usage: + +#if gsl_HAVE( ADDRESSOF ) +# define gsl_ADDRESSOF(x) std::addressof(x) +#else +# define gsl_ADDRESSOF(x) (&x) +#endif + +#if gsl_HAVE( CONSTEXPR_11 ) +# define gsl_constexpr constexpr +#else +# define gsl_constexpr /*constexpr*/ +#endif + +#if gsl_HAVE( CONSTEXPR_14 ) +# define gsl_constexpr14 constexpr +#else +# define gsl_constexpr14 /*constexpr*/ +#endif + +#if gsl_HAVE( CONSTEXPR_17 ) +# define gsl_constexpr17 constexpr +#else +# define gsl_constexpr17 /*constexpr*/ +#endif + +#if gsl_HAVE( CONSTEXPR_20 ) +# define gsl_constexpr20 constexpr +#else +# define gsl_constexpr20 /*constexpr*/ +#endif + +#if gsl_HAVE( EXPLICIT ) +# define gsl_explicit explicit +#else +# define gsl_explicit /*explicit*/ +#endif + +#if gsl_FEATURE( IMPLICIT_MACRO ) +# define implicit /*implicit*/ +#endif + +#if gsl_HAVE( IS_DELETE ) +# define gsl_is_delete = delete +#else +# define gsl_is_delete +#endif + +#if gsl_HAVE( IS_DELETE ) +# define gsl_is_delete_access public +#else +# define gsl_is_delete_access private +#endif + +#if gsl_HAVE( NOEXCEPT ) +# define gsl_noexcept noexcept +# define gsl_noexcept_if( expr ) noexcept( expr ) +#else +# define gsl_noexcept throw() +# define gsl_noexcept_if( expr ) /*noexcept( expr )*/ +#endif +#if defined( gsl_TESTING_ ) +# define gsl_noexcept_not_testing +#else +# define gsl_noexcept_not_testing gsl_noexcept +#endif + +#if gsl_HAVE( NULLPTR ) +# define gsl_nullptr nullptr +#else +# define gsl_nullptr NULL +#endif + +#if gsl_HAVE( NODISCARD ) +# define gsl_NODISCARD [[nodiscard]] +#else +# define gsl_NODISCARD +#endif + +#if gsl_HAVE( NORETURN ) +# define gsl_NORETURN [[noreturn]] +#elif defined(_MSC_VER) +# define gsl_NORETURN __declspec(noreturn) +#elif gsl_COMPILER_GNUC_VERSION || gsl_COMPILER_CLANG_VERSION || gsl_COMPILER_APPLECLANG_VERSION || gsl_COMPILER_ARMCC_VERSION +# define gsl_NORETURN __attribute__((noreturn)) +#else +# define gsl_NORETURN +#endif + +#if gsl_HAVE( DEPRECATED ) && ! defined( gsl_TESTING_ ) +# define gsl_DEPRECATED [[deprecated]] +# define gsl_DEPRECATED_MSG( msg ) [[deprecated( msg )]] +#else +# define gsl_DEPRECATED +# define gsl_DEPRECATED_MSG( msg ) +#endif + +#if gsl_HAVE( C99_PREPROCESSOR ) +# if gsl_CPP20_OR_GREATER +# define gsl_CONSTRAINT(...) __VA_ARGS__ +# else +# define gsl_CONSTRAINT(...) typename +# endif +#endif + +#if gsl_HAVE( TYPE_TRAITS ) +# define gsl_STATIC_ASSERT_( cond, msg ) static_assert( cond, msg ) +#else +# define gsl_STATIC_ASSERT_( cond, msg ) ( ( void )sizeof( char[1 - 2*!!( cond ) ] ) ) +#endif + +#if gsl_HAVE( TYPE_TRAITS ) + +#define gsl_DEFINE_ENUM_BITMASK_OPERATORS_( ENUM ) \ + gsl_NODISCARD gsl_api inline gsl_constexpr ENUM \ + operator~( ENUM val ) gsl_noexcept \ + { \ + typedef typename ::gsl::std11::underlying_type<ENUM>::type U; \ + return ENUM( ~U( val ) ); \ + } \ + gsl_NODISCARD gsl_api inline gsl_constexpr ENUM \ + operator|( ENUM lhs, ENUM rhs ) gsl_noexcept \ + { \ + typedef typename ::gsl::std11::underlying_type<ENUM>::type U; \ + return ENUM( U( lhs ) | U( rhs ) ); \ + } \ + gsl_NODISCARD gsl_api inline gsl_constexpr ENUM \ + operator&( ENUM lhs, ENUM rhs ) gsl_noexcept \ + { \ + typedef typename ::gsl::std11::underlying_type<ENUM>::type U; \ + return ENUM( U( lhs ) & U( rhs ) ); \ + } \ + gsl_NODISCARD gsl_api inline gsl_constexpr ENUM \ + operator^( ENUM lhs, ENUM rhs ) gsl_noexcept \ + { \ + typedef typename ::gsl::std11::underlying_type<ENUM>::type U; \ + return ENUM( U( lhs ) ^ U( rhs ) ); \ + } \ + gsl_api inline gsl_constexpr14 ENUM & \ + operator|=( ENUM & lhs, ENUM rhs ) gsl_noexcept \ + { \ + return lhs = lhs | rhs; \ + } \ + gsl_api inline gsl_constexpr14 ENUM & \ + operator&=( ENUM & lhs, ENUM rhs ) gsl_noexcept \ + { \ + return lhs = lhs & rhs; \ + } \ + gsl_api inline gsl_constexpr14 ENUM & \ + operator^=( ENUM & lhs, ENUM rhs ) gsl_noexcept \ + { \ + return lhs = lhs ^ rhs; \ + } + +#define gsl_DEFINE_ENUM_RELATIONAL_OPERATORS_( ENUM ) \ + gsl_NODISCARD gsl_api inline gsl_constexpr bool \ + operator<( ENUM lhs, ENUM rhs ) gsl_noexcept \ + { \ + typedef typename ::gsl::std11::underlying_type<ENUM>::type U; \ + return U( lhs ) < U( rhs ); \ + } \ + gsl_NODISCARD gsl_api inline gsl_constexpr bool \ + operator>( ENUM lhs, ENUM rhs ) gsl_noexcept \ + { \ + typedef typename ::gsl::std11::underlying_type<ENUM>::type U; \ + return U( lhs ) > U( rhs ); \ + } \ + gsl_NODISCARD gsl_api inline gsl_constexpr bool \ + operator<=( ENUM lhs, ENUM rhs ) gsl_noexcept \ + { \ + typedef typename ::gsl::std11::underlying_type<ENUM>::type U; \ + return U( lhs ) <= U( rhs ); \ + } \ + gsl_NODISCARD gsl_api inline gsl_constexpr bool \ + operator>=( ENUM lhs, ENUM rhs ) gsl_noexcept \ + { \ + typedef typename ::gsl::std11::underlying_type<ENUM>::type U; \ + return U( lhs ) >= U( rhs ); \ + } + + // + // Defines bitmask operators `|`, `&`, `^`, `~`, `|=`, `&=`, and `^=` for the given enum type. + // + // enum class Vegetables { tomato = 0b001, onion = 0b010, eggplant = 0b100 }; + // gsl_DEFINE_ENUM_BITMASK_OPERATORS( Vegetables ) + // +#define gsl_DEFINE_ENUM_BITMASK_OPERATORS( ENUM ) gsl_DEFINE_ENUM_BITMASK_OPERATORS_( ENUM ) + + // + // Defines relational operators `<`, `>`, `<=`, `>=` for the given enum type. + // + // enum class OperatorPrecedence { additive = 0, multiplicative = 1, power = 2 }; + // gsl_DEFINE_ENUM_RELATIONAL_OPERATORS( OperatorPrecedence ) + // +#define gsl_DEFINE_ENUM_RELATIONAL_OPERATORS( ENUM ) gsl_DEFINE_ENUM_RELATIONAL_OPERATORS_( ENUM ) + +#endif // gsl_HAVE( TYPE_TRAITS ) + +#define gsl_DIMENSION_OF( a ) ( sizeof(a) / sizeof(0[a]) ) + + +// Method enabling (C++98, VC120 (VS2013) cannot use __VA_ARGS__) + +#if gsl_HAVE( EXPRESSION_SFINAE ) +# define gsl_TRAILING_RETURN_TYPE_(T) auto +# define gsl_RETURN_DECLTYPE_(EXPR) -> decltype( EXPR ) +#else +# define gsl_TRAILING_RETURN_TYPE_(T) T +# define gsl_RETURN_DECLTYPE_(EXPR) +#endif + +// NOTE: When using SFINAE in gsl-lite, please note that overloads of function templates must always use SFINAE with non-type default arguments +// as explained in https://en.cppreference.com/w/cpp/types/enable_if#Notes. `gsl_ENABLE_IF_()` implements graceful fallback to default +// type arguments (for compilers that don't support non-type default arguments); please verify that this is appropriate in the given +// situation, and add additional checks if necessary. +// +// Also, please note that `gsl_ENABLE_IF_()` doesn't enforce the constraint at all if no compiler/library support is available (i.e. pre-C++11). + +#if gsl_HAVE( TYPE_TRAITS ) && gsl_HAVE( DEFAULT_FUNCTION_TEMPLATE_ARG ) +# if !gsl_BETWEEN( gsl_COMPILER_MSVC_VERSION, 1, 140 ) // VS 2013 seems to have trouble with SFINAE for default non-type arguments +# define gsl_ENABLE_IF_(VA) , typename std::enable_if< ( VA ), int >::type = 0 +# else +# define gsl_ENABLE_IF_(VA) , typename = typename std::enable_if< ( VA ), ::gsl::detail::enabler >::type +# endif +#else +# define gsl_ENABLE_IF_(VA) +#endif + + +// Other features: + +#define gsl_HAVE_CONSTRAINED_SPAN_CONTAINER_CTOR ( gsl_HAVE_DEFAULT_FUNCTION_TEMPLATE_ARG && gsl_HAVE_CONTAINER_DATA_METHOD ) +#define gsl_HAVE_CONSTRAINED_SPAN_CONTAINER_CTOR_() gsl_HAVE_CONSTRAINED_SPAN_CONTAINER_CTOR + +#define gsl_HAVE_UNCONSTRAINED_SPAN_CONTAINER_CTOR ( gsl_CONFIG_ALLOWS_UNCONSTRAINED_SPAN_CONTAINER_CTOR && gsl_COMPILER_NVCC_VERSION == 0 ) +#define gsl_HAVE_UNCONSTRAINED_SPAN_CONTAINER_CTOR_() gsl_HAVE_UNCONSTRAINED_SPAN_CONTAINER_CTOR + +// GSL API (e.g. for CUDA platform): + +// Guidelines for using `gsl_api`: +// +// NVCC imposes the restriction that a function annotated `__host__ __device__` cannot call host-only or device-only functions. +// This makes `gsl_api` inappropriate for generic functions that call unknown code, e.g. the template constructors of `span<>` +// or functions like `finally()` which accept an arbitrary function object. +// It is often preferable to annotate functions only with `gsl_constexpr` or `gsl_constexpr14`. The "extended constexpr" mode +// of NVCC (currently an experimental feature) will implicitly consider constexpr functions `__host__ __device__` functions +// but tolerates calls to host-only or device-only functions. + +#ifndef gsl_api +# ifdef __CUDACC__ +# define gsl_api __host__ __device__ +# else +# define gsl_api /*gsl_api*/ +# endif +#endif + +// Additional includes: + +#if ! gsl_CPP11_OR_GREATER +# include <algorithm> // for swap() before C++11 +#endif // ! gsl_CPP11_OR_GREATER + +#if gsl_HAVE( ARRAY ) +# include <array> // indirectly includes reverse_iterator<> +#endif + +#if ! gsl_HAVE( ARRAY ) +# include <iterator> // for reverse_iterator<> +#endif + +#if ! gsl_HAVE( CONSTRAINED_SPAN_CONTAINER_CTOR ) || ! gsl_HAVE( AUTO ) +# include <vector> +#endif + +#if gsl_HAVE( INITIALIZER_LIST ) +# include <initializer_list> +#endif + +#if defined( gsl_CONFIG_CONTRACT_VIOLATION_ASSERTS ) +# include <cassert> +#endif + +#if defined( gsl_CONFIG_CONTRACT_VIOLATION_TRAPS ) && gsl_COMPILER_MSVC_VERSION >= 110 // __fastfail() supported by VS 2012 and later +# include <intrin.h> +#endif + +#if gsl_HAVE( ENUM_CLASS ) && gsl_COMPILER_ARMCC_VERSION +# include <endian.h> +#endif + +#if gsl_HAVE( TYPE_TRAITS ) +# include <type_traits> // for enable_if<>, + // add_const<>, add_pointer<>, common_type<>, make_signed<>, remove_cv<>, remove_const<>, remove_volatile<>, remove_reference<>, remove_cvref<>, remove_pointer<>, underlying_type<>, + // is_assignable<>, is_constructible<>, is_const<>, is_convertible<>, is_integral<>, is_pointer<>, is_signed<>, + // integral_constant<>, declval() +#elif gsl_HAVE( TR1_TYPE_TRAITS ) +# include <tr1/type_traits> // for add_const<>, remove_cv<>, remove_const<>, remove_volatile<>, remove_reference<>, integral_constant<> +#endif + +#if gsl_FEATURE( EXPERIMENTAL_RETURN_GUARD ) + +// Declare __cxa_get_globals() or equivalent in namespace gsl::detail for uncaught_exceptions(): + +# if ! gsl_HAVE( UNCAUGHT_EXCEPTIONS ) +# if defined( _MSC_VER ) // MS-STL with either MSVC or clang-cl +namespace gsl { namespace detail { extern "C" char * __cdecl _getptd(); } } +# elif gsl_COMPILER_CLANG_VERSION || gsl_COMPILER_GNUC_VERSION || gsl_COMPILER_APPLECLANG_VERSION +# if defined( __GLIBCXX__ ) || defined( __GLIBCPP__ ) // libstdc++: prototype from cxxabi.h +# include <cxxabi.h> +# elif ! defined( BOOST_CORE_UNCAUGHT_EXCEPTIONS_HPP_INCLUDED_ ) // libc++: prototype from Boost? +# if defined( __FreeBSD__ ) || defined( __OpenBSD__ ) +namespace __cxxabiv1 { struct __cxa_eh_globals; extern "C" __cxa_eh_globals * __cxa_get_globals(); } +# else +namespace __cxxabiv1 { struct __cxa_eh_globals; extern "C" __cxa_eh_globals * __cxa_get_globals() gsl_noexcept; } +# endif +# endif + namespace gsl { namespace detail { using ::__cxxabiv1::__cxa_get_globals; } } +# endif +# endif // ! gsl_HAVE( UNCAUGHT_EXCEPTIONS ) +#endif // gsl_FEATURE( EXPERIMENTAL_RETURN_GUARD ) + + +// MSVC warning suppression macros: + +#if gsl_COMPILER_MSVC_VERSION >= 140 && ! gsl_COMPILER_NVCC_VERSION +# define gsl_SUPPRESS_MSGSL_WARNING(expr) /* Pimm: note disabled for intel [[gsl::suppress(expr)]]*/ +# define gsl_SUPPRESS_MSVC_WARNING(code, descr) __pragma(warning(suppress: code) ) +# define gsl_DISABLE_MSVC_WARNINGS(codes) __pragma(warning(push)) __pragma(warning(disable: codes)) +# define gsl_RESTORE_MSVC_WARNINGS() __pragma(warning(pop )) +#else +// TODO: define for Clang +# define gsl_SUPPRESS_MSGSL_WARNING(expr) +# define gsl_SUPPRESS_MSVC_WARNING(code, descr) +# define gsl_DISABLE_MSVC_WARNINGS(codes) +# define gsl_RESTORE_MSVC_WARNINGS() +#endif + +// Suppress the following MSVC GSL warnings: +// - C26432: gsl::c.21 : if you define or delete any default operation in the type '...', define or delete them all +// - C26410: gsl::r.32 : the parameter 'ptr' is a reference to const unique pointer, use const T* or const T& instead +// - C26415: gsl::r.30 : smart pointer parameter 'ptr' is used only to access contained pointer. Use T* or T& instead +// - C26418: gsl::r.36 : shared pointer parameter 'ptr' is not copied or moved. Use T* or T& instead +// - C26472: gsl::t.1 : don't use a static_cast for arithmetic conversions; +// use brace initialization, gsl::narrow_cast or gsl::narrow +// - C26439: gsl::f.6 : special function 'function' can be declared 'noexcept' +// - C26440: gsl::f.6 : function 'function' can be declared 'noexcept' +// - C26455: gsl::f.6 : default constructor may not throw. Declare it 'noexcept' +// - C26473: gsl::t.1 : don't cast between pointer types where the source type and the target type are the same +// - C26481: gsl::b.1 : don't use pointer arithmetic. Use span instead +// - C26482: gsl::b.2 : only index into arrays using constant expressions +// - C26446: gdl::b.4 : prefer to use gsl::at() instead of unchecked subscript operator +// - C26490: gsl::t.1 : don't use reinterpret_cast +// - C26487: gsl::l.4 : don't return a pointer '(<some number>'s result)' that may be invalid +// - C26457: es.48 : (void) should not be used to ignore return values, use 'std::ignore =' instead + +gsl_DISABLE_MSVC_WARNINGS( 26432 26410 26415 26418 26472 26439 26440 26455 26473 26481 26482 26446 26490 26487 26457 ) + +namespace gsl { + +// forward declare span<>: + +template< class T > +class span; + +// C++98 emulation: + +namespace std98 { + +// We implement `equal()` and `lexicographical_compare()` here to avoid having to pull in the <algorithm> header. +template< class InputIt1, class InputIt2 > +bool equal( InputIt1 first1, InputIt1 last1, InputIt2 first2 ) +{ + // Implementation borrowed from https://en.cppreference.com/w/cpp/algorithm/equal. + for ( ; first1 != last1; ++first1, ++first2 ) + { + if ( ! (*first1 == *first2 ) ) return false; + } + return true; +} +template< class InputIt1, class InputIt2 > +bool lexicographical_compare( InputIt1 first1, InputIt1 last1, InputIt2 first2, InputIt2 last2 ) +{ + // Implementation borrowed from https://en.cppreference.com/w/cpp/algorithm/lexicographical_compare. + for ( ; first1 != last1 && first2 != last2; ++first1, (void) ++first2 ) + { + if ( *first1 < *first2 ) return true; + if ( *first2 < *first1 ) return false; + } + return first1 == last1 && first2 != last2; +} + +} // namespace std98 + +// C++11 emulation: + +namespace std11 { + +#if gsl_HAVE( ADD_CONST ) + +using std::add_const; + +#elif gsl_HAVE( TR1_ADD_CONST ) + +using std::tr1::add_const; + +#else + +template< class T > struct add_const { typedef const T type; }; + +#endif // gsl_HAVE( ADD_CONST ) + +#if gsl_HAVE( REMOVE_CONST ) + +using std::remove_cv; +using std::remove_const; +using std::remove_volatile; + +#elif gsl_HAVE( TR1_REMOVE_CONST ) + +using std::tr1::remove_cv; +using std::tr1::remove_const; +using std::tr1::remove_volatile; + +#else + +template< class T > struct remove_const { typedef T type; }; +template< class T > struct remove_const<T const> { typedef T type; }; + +template< class T > struct remove_volatile { typedef T type; }; +template< class T > struct remove_volatile<T volatile> { typedef T type; }; + +template< class T > +struct remove_cv +{ + typedef typename remove_volatile<typename remove_const<T>::type>::type type; +}; + +#endif // gsl_HAVE( REMOVE_CONST ) + +#if gsl_HAVE( REMOVE_REFERENCE ) + +using std::remove_reference; + +#elif gsl_HAVE( TR1_REMOVE_REFERENCE ) + +using std::tr1::remove_reference; + +#else + +template< class T > struct remove_reference { typedef T type; }; +template< class T > struct remove_reference<T&> { typedef T type; }; +# if gsl_HAVE( RVALUE_REFERENCE ) +template< class T > struct remove_reference<T&&> { typedef T type; }; +# endif + +#endif // gsl_HAVE( REMOVE_REFERENCE ) + + +#if gsl_HAVE( INTEGRAL_CONSTANT ) + +using std::integral_constant; +using std::true_type; +using std::false_type; + +#elif gsl_HAVE( TR1_INTEGRAL_CONSTANT ) + +using std::tr1::integral_constant; +using std::tr1::true_type; +using std::tr1::false_type; + +#else + +template< class T, T v > struct integral_constant { enum { value = v }; }; +typedef integral_constant< bool, true > true_type; +typedef integral_constant< bool, false > false_type; + +#endif + +#if gsl_HAVE( TYPE_TRAITS ) + +using std::underlying_type; + +#elif gsl_HAVE( TR1_TYPE_TRAITS ) + +using std::tr1::underlying_type; + +#else + +// We could try to define `underlying_type<>` for pre-C++11 here, but let's not until someone actually needs it. + +#endif + +} // namespace std11 + +// C++14 emulation: + +namespace std14 { + +#if gsl_HAVE( UNIQUE_PTR ) +# if gsl_HAVE( MAKE_UNIQUE ) + +using std::make_unique; + +# elif gsl_HAVE( VARIADIC_TEMPLATE ) + +template< class T, class... Args > +gsl_NODISCARD std::unique_ptr<T> +make_unique( Args &&... args ) +{ + return std::unique_ptr<T>( new T( std::forward<Args>( args )... ) ); +} + +# endif // gsl_HAVE( MAKE_UNIQUE ), gsl_HAVE( VARIADIC_TEMPLATE ) +#endif // gsl_HAVE( UNIQUE_PTR ) + +} // namespace std14 + +namespace detail { + +#if gsl_HAVE( VARIADIC_TEMPLATE ) + +template < bool V0, class T0, class... Ts > struct conjunction_ { using type = T0; }; +template < class T0, class T1, class... Ts > struct conjunction_<true, T0, T1, Ts...> : conjunction_<T1::value, T1, Ts...> { }; +template < bool V0, class T0, class... Ts > struct disjunction_ { using type = T0; }; +template < class T0, class T1, class... Ts > struct disjunction_<false, T0, T1, Ts...> : disjunction_<T1::value, T1, Ts...> { }; + +#endif + +template <typename> struct dependent_false : std11::integral_constant<bool, false> { }; + +} // namespace detail + +// C++17 emulation: + +namespace std17 { + +template< bool v > struct bool_constant : std11::integral_constant<bool, v>{}; + +#if gsl_CPP11_120 + +template < class... Ts > struct conjunction; +template < > struct conjunction< > : std11::true_type { }; +template < class T0, class... Ts > struct conjunction<T0, Ts...> : detail::conjunction_<T0::value, T0, Ts...>::type { }; +template < class... Ts > struct disjunction; +template < > struct disjunction< > : std11::false_type { }; +template < class T0, class... Ts > struct disjunction<T0, Ts...> : detail::disjunction_<T0::value, T0, Ts...>::type { }; +template < class T > struct negation : std11::integral_constant<bool, !T::value> { }; + +# if gsl_CPP14_OR_GREATER + +template < class... Ts > constexpr bool conjunction_v = conjunction<Ts...>::value; +template < class... Ts > constexpr bool disjunction_v = disjunction<Ts...>::value; +template < class T > constexpr bool negation_v = negation<T>::value; + +# endif // gsl_CPP14_OR_GREATER + +template< class... Ts > +struct make_void { typedef void type; }; + +template< class... Ts > +using void_t = typename make_void< Ts... >::type; + +#endif // gsl_CPP11_120 + +#if gsl_HAVE( CONSTRAINED_SPAN_CONTAINER_CTOR ) + +template< class T, size_t N > +gsl_NODISCARD gsl_api inline gsl_constexpr auto +size( T const(&)[N] ) gsl_noexcept -> size_t +{ + return N; +} + +template< class C > +gsl_NODISCARD inline gsl_constexpr auto +size( C const & cont ) -> decltype( cont.size() ) +{ + return cont.size(); +} + +template< class T, size_t N > +gsl_NODISCARD gsl_api inline gsl_constexpr auto +data( T(&arr)[N] ) gsl_noexcept -> T* +{ + return &arr[0]; +} + +template< class C > +gsl_NODISCARD inline gsl_constexpr auto +data( C & cont ) -> decltype( cont.data() ) +{ + return cont.data(); +} + +template< class C > +gsl_NODISCARD inline gsl_constexpr auto +data( C const & cont ) -> decltype( cont.data() ) +{ + return cont.data(); +} + +template< class E > +gsl_NODISCARD inline gsl_constexpr auto +data( std::initializer_list<E> il ) gsl_noexcept -> E const * +{ + return il.begin(); +} + +#endif // gsl_HAVE( CONSTRAINED_SPAN_CONTAINER_CTOR ) + +} // namespace std17 + +// C++20 emulation: + +namespace std20 { + +#if gsl_CPP11_100 + +struct identity +{ + template < class T > + gsl_constexpr T && operator ()( T && arg ) const gsl_noexcept + { + return std::forward<T>( arg ); + } +}; + +# if gsl_HAVE( ENUM_CLASS ) +enum class endian +{ +# if defined( _WIN32 ) + little = 0, + big = 1, + native = little +# elif gsl_COMPILER_GNUC_VERSION || gsl_COMPILER_CLANG_VERSION || gsl_COMPILER_APPLECLANG_VERSION + little = __ORDER_LITTLE_ENDIAN__, + big = __ORDER_BIG_ENDIAN__, + native = __BYTE_ORDER__ +# elif gsl_COMPILER_ARMCC_VERSION + // from <endian.h> header file + little = __LITTLE_ENDIAN, + big = __BIG_ENDIAN, + native = __BYTE_ORDER +# else +// Do not define any endianness constants for unknown compilers. +# endif +}; +# endif // gsl_HAVE( ENUM_CLASS ) + +#endif // gsl_CPP11_100 + +template< class T > +struct type_identity +{ + typedef T type; +}; +#if gsl_HAVE( ALIAS_TEMPLATE ) +template< class T > +using type_identity_t = typename type_identity<T>::type; +#endif // gsl_HAVE( ALIAS_TEMPLATE ) + +#if gsl_HAVE( STD_SSIZE ) + +using std::ssize; + +#elif gsl_HAVE( CONSTRAINED_SPAN_CONTAINER_CTOR ) + +template < class C > +gsl_NODISCARD gsl_constexpr auto +ssize( C const & c ) + -> typename std::common_type<std::ptrdiff_t, typename std::make_signed<decltype(c.size())>::type>::type +{ + using R = typename std::common_type<std::ptrdiff_t, typename std::make_signed<decltype(c.size())>::type>::type; + return static_cast<R>( c.size() ); +} + +template <class T, std::size_t N> +gsl_NODISCARD gsl_constexpr auto +ssize( T const(&)[N] ) gsl_noexcept -> std::ptrdiff_t +{ + return std::ptrdiff_t( N ); +} + +#endif // gsl_HAVE( STD_SSIZE ) + +#if gsl_HAVE( REMOVE_CVREF ) + +using std::remove_cvref; + +#else + +template< class T > struct remove_cvref { typedef typename std11::remove_cv< typename std11::remove_reference< T >::type >::type type; }; + +#endif // gsl_HAVE( REMOVE_CVREF ) + +} // namespace std20 + +namespace detail { + +/// for gsl_ENABLE_IF_() + +/*enum*/ class enabler{}; + +#if gsl_HAVE( TYPE_TRAITS ) + +template< class Q > +struct is_span_oracle : std::false_type{}; + +template< class T> +struct is_span_oracle< span<T> > : std::true_type{}; + +template< class Q > +struct is_span : is_span_oracle< typename std::remove_cv<Q>::type >{}; + +template< class Q > +struct is_std_array_oracle : std::false_type{}; + +# if gsl_HAVE( ARRAY ) + +template< class T, std::size_t Extent > +struct is_std_array_oracle< std::array<T, Extent> > : std::true_type{}; + +# endif + +template< class Q > +struct is_std_array : is_std_array_oracle< typename std::remove_cv<Q>::type >{}; + +template< class Q > +struct is_array : std::false_type{}; + +template< class T > +struct is_array<T[]> : std::true_type{}; + +template< class T, std::size_t N > +struct is_array<T[N]> : std::true_type{}; + +# if gsl_CPP11_140 && ! gsl_BETWEEN( gsl_COMPILER_GNUC_VERSION, 1, 500 ) + +template< class, class = void > +struct has_size_and_data : std::false_type{}; + +template< class C > +struct has_size_and_data +< + C, std17::void_t< + decltype( std17::size(std::declval<C>()) ), + decltype( std17::data(std::declval<C>()) ) > +> : std::true_type{}; + +template< class, class, class = void > +struct is_compatible_element : std::false_type {}; + +template< class C, class E > +struct is_compatible_element +< + C, E, std17::void_t< + decltype( std17::data(std::declval<C>()) ), + typename std::remove_pointer<decltype( std17::data( std::declval<C&>() ) )>::type(*)[] > +> : std::is_convertible< typename std::remove_pointer<decltype( std17::data( std::declval<C&>() ) )>::type(*)[], E(*)[] >{}; + +template< class C > +struct is_container : std17::bool_constant +< + ! is_span< C >::value + && ! is_array< C >::value + && ! is_std_array< C >::value + && has_size_and_data< C >::value +>{}; + +template< class C, class E > +struct is_compatible_container : std17::bool_constant +< + is_container<C>::value + && is_compatible_element<C,E>::value +>{}; + +# else // ^^^ gsl_CPP11_140 && ! gsl_BETWEEN( gsl_COMPILER_GNUC_VERSION, 1, 500 ) ^^^ / vvv ! gsl_CPP11_140 || gsl_BETWEEN( gsl_COMPILER_GNUC_VERSION, 1, 500 ) vvv + +template< + class C, class E + , typename = typename std::enable_if< + ! is_span< C >::value + && ! is_array< C >::value + && ! is_std_array< C >::value + && ( std::is_convertible< typename std::remove_pointer<decltype( std17::data( std::declval<C&>() ) )>::type(*)[], E(*)[] >::value) + // && has_size_and_data< C >::value + , enabler>::type + , class = decltype( std17::size(std::declval<C>()) ) + , class = decltype( std17::data(std::declval<C>()) ) +> +# if gsl_BETWEEN( gsl_COMPILER_MSVC_VERSION, 1, 140 ) +// VS2013 has insufficient support for expression SFINAE; we cannot make `is_compatible_container<>` a proper type trait here +struct is_compatible_container : std::true_type { }; +# else +struct is_compatible_container_r { is_compatible_container_r(int); }; +template< class C, class E > +std::true_type is_compatible_container_f( is_compatible_container_r<C, E> ); +template< class C, class E > +std::false_type is_compatible_container_f( ... ); + +template< class C, class E > +struct is_compatible_container : decltype( is_compatible_container_f< C, E >( 0 ) ) { }; +# endif // gsl_BETWEEN( gsl_COMPILER_MSVC_VERSION, 1, 140 ) + +# endif // gsl_CPP11_140 && ! gsl_BETWEEN( gsl_COMPILER_GNUC_VERSION, 1, 500 ) + +#endif // gsl_HAVE( TYPE_TRAITS ) + +} // namespace detail + +// +// GSL.util: utilities +// + +// Integer type for indices (e.g. in a loop). +typedef gsl_CONFIG_INDEX_TYPE index; + +// Integer type for dimensions. +typedef gsl_CONFIG_INDEX_TYPE dim; + +// Integer type for array strides. +typedef gsl_CONFIG_INDEX_TYPE stride; + +// Integer type for pointer, iterator, or index differences. +typedef gsl_CONFIG_INDEX_TYPE diff; + +// +// GSL.owner: ownership pointers +// +#if gsl_HAVE( SHARED_PTR ) + using std::unique_ptr; + using std::shared_ptr; + using std::make_shared; +# if gsl_HAVE( MAKE_UNIQUE ) || gsl_HAVE( VARIADIC_TEMPLATE ) + using std14::make_unique; +# endif +#endif + +#if gsl_HAVE( ALIAS_TEMPLATE ) + template< class T +#if gsl_HAVE( TYPE_TRAITS ) + , typename = typename std::enable_if< std::is_pointer<T>::value >::type +#endif + > + using owner = T; +#elif gsl_CONFIG( DEFAULTS_VERSION ) == 0 + // TODO vNext: remove + template< class T > struct owner { typedef T type; }; +#endif + +#define gsl_HAVE_OWNER_TEMPLATE gsl_HAVE_ALIAS_TEMPLATE +#define gsl_HAVE_OWNER_TEMPLATE_() gsl_HAVE_OWNER_TEMPLATE + +// TODO vNext: remove +#if gsl_FEATURE( OWNER_MACRO ) +# if gsl_HAVE( OWNER_TEMPLATE ) +# define Owner(t) ::gsl::owner<t> +# else +# define Owner(t) ::gsl::owner<t>::type +# endif +#endif + +// +// GSL.assert: assertions +// + +#if gsl_HAVE( TYPE_TRAITS ) +# define gsl_ELIDE_( x ) static_assert( ::std::is_constructible<bool, decltype( x )>::value, "argument of contract check must be convertible to bool" ) +#else +# define gsl_ELIDE_( x ) +#endif +#define gsl_NO_OP_() ( static_cast<void>( 0 ) ) + +#if defined( gsl_CONFIG_UNENFORCED_CONTRACTS_ASSUME ) +# if defined( __CUDACC__ ) && defined( __CUDA_ARCH__ ) +# if gsl_COMPILER_NVCC_VERSION >= 113 +# define gsl_ASSUME_( x ) ( ( x ) ? static_cast<void>(0) : __builtin_unreachable() ) +# define gsl_ASSUME_UNREACHABLE_() __builtin_unreachable() +# else +# define gsl_ASSUME_( x ) gsl_ELIDE_( x ) /* there is no assume intrinsic in CUDA device code */ +# define gsl_ASSUME_UNREACHABLE_() gsl_NO_OP_() /* there is no assume intrinsic in CUDA device code */ +# endif +# elif gsl_COMPILER_MSVC_VERSION >= 140 +# define gsl_ASSUME_( x ) __assume( x ) +# define gsl_ASSUME_UNREACHABLE_() __assume( 0 ) +# elif gsl_COMPILER_GNUC_VERSION +# define gsl_ASSUME_( x ) ( ( x ) ? static_cast<void>(0) : __builtin_unreachable() ) +# define gsl_ASSUME_UNREACHABLE_() __builtin_unreachable() +# elif defined(__has_builtin) +# if __has_builtin(__builtin_unreachable) +# define gsl_ASSUME_( x ) ( ( x ) ? static_cast<void>(0) : __builtin_unreachable() ) +# define gsl_ASSUME_UNREACHABLE_() __builtin_unreachable() +# else +# error gsl_CONFIG_UNENFORCED_CONTRACTS_ASSUME: gsl-lite does not know how to generate UB optimization hints for this compiler; use gsl_CONFIG_UNENFORCED_CONTRACTS_ELIDE instead +# endif +# else +# error gsl_CONFIG_UNENFORCED_CONTRACTS_ASSUME: gsl-lite does not know how to generate UB optimization hints for this compiler; use gsl_CONFIG_UNENFORCED_CONTRACTS_ELIDE instead +# endif +#endif // defined( gsl_CONFIG_UNENFORCED_CONTRACTS_ASSUME ) + +#if defined( gsl_CONFIG_UNENFORCED_CONTRACTS_ASSUME ) +# define gsl_CONTRACT_UNENFORCED_( x ) gsl_ASSUME_( x ) +#else // defined( gsl_CONFIG_UNENFORCED_CONTRACTS_ELIDE ) [default] +# define gsl_CONTRACT_UNENFORCED_( x ) gsl_ELIDE_( x ) +#endif + +#if defined( gsl_CONFIG_CONTRACT_VIOLATION_TRAPS ) +# if defined( __CUDACC__ ) && defined( __CUDA_ARCH__ ) +# define gsl_TRAP_() __trap() +# elif gsl_COMPILER_MSVC_VERSION >= 110 // __fastfail() supported by VS 2012 and later +# define gsl_TRAP_() __fastfail( 0 ) /* legacy failure code for buffer-overrun errors, cf. winnt.h, "Fast fail failure codes" */ +# elif gsl_COMPILER_GNUC_VERSION +# define gsl_TRAP_() __builtin_trap() +# elif defined(__has_builtin) +# if __has_builtin(__builtin_trap) +# define gsl_TRAP_() __builtin_trap() +# else +# error gsl_CONFIG_CONTRACT_VIOLATION_TRAPS: gsl-lite does not know how to generate a trap instruction for this compiler; use gsl_CONFIG_CONTRACT_VIOLATION_TERMINATES instead +# endif +# else +# error gsl_CONFIG_CONTRACT_VIOLATION_TRAPS: gsl-lite does not know how to generate a trap instruction for this compiler; use gsl_CONFIG_CONTRACT_VIOLATION_TERMINATES instead +# endif +#endif // defined( gsl_CONFIG_CONTRACT_VIOLATION_TRAPS ) + +#if defined( gsl_CONFIG_CONTRACT_VIOLATION_CALLS_HANDLER ) +# define gsl_CONTRACT_CHECK_( str, x ) ( ( x ) ? static_cast<void>(0) : ::gsl::fail_fast_assert_handler( #x, str, __FILE__, __LINE__ ) ) +# if defined( __CUDACC__ ) && defined( __CUDA_ARCH__ ) +# define gsl_FAILFAST_() ( ::gsl::fail_fast_assert_handler( "", "GSL: failure", __FILE__, __LINE__ ), gsl_TRAP_() ) /* do not let the custom assertion handler continue execution */ +# else +# define gsl_FAILFAST_() ( ::gsl::fail_fast_assert_handler( "", "GSL: failure", __FILE__, __LINE__ ), ::gsl::detail::fail_fast_terminate() ) /* do not let the custom assertion handler continue execution */ +# endif +#elif defined( __CUDACC__ ) && defined( __CUDA_ARCH__ ) +# if defined( gsl_CONFIG_CONTRACT_VIOLATION_ASSERTS ) || ! defined( NDEBUG ) +# define gsl_CONTRACT_CHECK_( str, x ) assert( str && ( x ) ) +# else +# define gsl_CONTRACT_CHECK_( str, x ) ( ( x ) ? static_cast<void>(0) : __trap() ) +#endif +# define gsl_FAILFAST_() ( __trap() ) +#elif defined( gsl_CONFIG_CONTRACT_VIOLATION_ASSERTS ) +# define gsl_CONTRACT_CHECK_( str, x ) assert( str && ( x ) ) +# if ! defined( NDEBUG ) +# define gsl_FAILFAST_() ( assert( ! "GSL: failure" ), ::gsl::detail::fail_fast_terminate() ) +# else +# define gsl_FAILFAST_() ( ::gsl::detail::fail_fast_terminate() ) +# endif +#elif defined( gsl_CONFIG_CONTRACT_VIOLATION_TRAPS ) +# define gsl_CONTRACT_CHECK_( str, x ) ( ( x ) ? static_cast<void>(0) : gsl_TRAP_() ) +# if gsl_COMPILER_MSVC_VERSION +# define gsl_FAILFAST_() ( gsl_TRAP_(), ::gsl::detail::fail_fast_terminate() ) +# else +# define gsl_FAILFAST_() ( gsl_TRAP_() ) +# endif +#elif defined( gsl_CONFIG_CONTRACT_VIOLATION_THROWS ) +# define gsl_CONTRACT_CHECK_( str, x ) ( ( x ) ? static_cast<void>(0) : ::gsl::detail::fail_fast_throw( str ": '" #x "' at " __FILE__ ":" gsl_STRINGIFY(__LINE__) ) ) +# define gsl_FAILFAST_() ( ::gsl::detail::fail_fast_throw( "GSL: failure at " __FILE__ ":" gsl_STRINGIFY(__LINE__) ) ) +#else // defined( gsl_CONFIG_CONTRACT_VIOLATION_TERMINATES ) [default] +# define gsl_CONTRACT_CHECK_( str, x ) ( ( x ) ? static_cast<void>(0) : ::gsl::detail::fail_fast_terminate() ) +# define gsl_FAILFAST_() ( ::gsl::detail::fail_fast_terminate() ) +#endif + +#if defined( gsl_CONFIG_CONTRACT_CHECKING_OFF ) || defined( gsl_CONFIG_CONTRACT_CHECKING_EXPECTS_OFF ) +# define gsl_Expects( x ) gsl_CONTRACT_UNENFORCED_( x ) +#else +# define gsl_Expects( x ) gsl_CONTRACT_CHECK_( "GSL: Precondition failure", x ) +#endif +#define Expects( x ) gsl_Expects( x ) +#if !defined( gsl_CONFIG_CONTRACT_CHECKING_AUDIT ) || defined( gsl_CONFIG_CONTRACT_CHECKING_EXPECTS_OFF ) +# define gsl_ExpectsAudit( x ) gsl_ELIDE_( x ) +#else +# define gsl_ExpectsAudit( x ) gsl_CONTRACT_CHECK_( "GSL: Precondition failure (audit)", x ) +#endif + +#if defined( gsl_CONFIG_CONTRACT_CHECKING_OFF ) || defined( gsl_CONFIG_CONTRACT_CHECKING_ENSURES_OFF ) +# define gsl_Ensures( x ) gsl_CONTRACT_UNENFORCED_( x ) +#else +# define gsl_Ensures( x ) gsl_CONTRACT_CHECK_( "GSL: Postcondition failure", x ) +#endif +#define Ensures( x ) gsl_Ensures( x ) +#if !defined( gsl_CONFIG_CONTRACT_CHECKING_AUDIT ) || defined( gsl_CONFIG_CONTRACT_CHECKING_ENSURES_OFF ) +# define gsl_EnsuresAudit( x ) gsl_ELIDE_( x ) +#else +# define gsl_EnsuresAudit( x ) gsl_CONTRACT_CHECK_( "GSL: Postcondition failure (audit)", x ) +#endif + +#if defined( gsl_CONFIG_CONTRACT_CHECKING_OFF ) || defined( gsl_CONFIG_CONTRACT_CHECKING_ASSERT_OFF ) +# define gsl_Assert( x ) gsl_CONTRACT_UNENFORCED_( x ) +#else +# define gsl_Assert( x ) gsl_CONTRACT_CHECK_( "GSL: Assertion failure", x ) +#endif +#if !defined( gsl_CONFIG_CONTRACT_CHECKING_AUDIT ) || defined( gsl_CONFIG_CONTRACT_CHECKING_ASSERT_OFF ) +# define gsl_AssertAudit( x ) gsl_ELIDE_( x ) +#else +# define gsl_AssertAudit( x ) gsl_CONTRACT_CHECK_( "GSL: Assertion failure (audit)", x ) +#endif + +#define gsl_FailFast() gsl_FAILFAST_() + + +struct fail_fast : public std::logic_error +{ + explicit fail_fast( char const * message ) + : std::logic_error( message ) {} +}; + +namespace detail { + + +#if gsl_HAVE( EXCEPTIONS ) +gsl_NORETURN inline void fail_fast_throw( char const * message ) +{ + throw fail_fast( message ); +} +#endif // gsl_HAVE( EXCEPTIONS ) +gsl_NORETURN inline void fail_fast_terminate() gsl_noexcept +{ + std::terminate(); +} + +} // namespace detail + +// Should be defined by user +gsl_api void fail_fast_assert_handler( char const * const expression, char const * const message, char const * const file, int line ); + +#if defined( gsl_CONFIG_CONTRACT_VIOLATION_THROWS ) + +# if gsl_HAVE( EXCEPTIONS ) +gsl_DEPRECATED_MSG("don't call gsl::fail_fast_assert() directly; use contract checking macros instead") +gsl_constexpr14 inline +void fail_fast_assert( bool cond, char const * const message ) +{ + if ( !cond ) + throw fail_fast( message ); +} +# endif // gsl_HAVE( EXCEPTIONS ) + +#elif defined( gsl_CONFIG_CONTRACT_VIOLATION_CALLS_HANDLER ) + +gsl_DEPRECATED_MSG("don't call gsl::fail_fast_assert() directly; use contract checking macros instead") +gsl_api gsl_constexpr14 inline +void fail_fast_assert( bool cond, char const * const expression, char const * const message, char const * const file, int line ) +{ + if ( !cond ) + ::gsl::fail_fast_assert_handler( expression, message, file, line ); +} + +#else // defined( gsl_CONFIG_CONTRACT_VIOLATION_TERMINATES ) [default] + +gsl_DEPRECATED_MSG("don't call gsl::fail_fast_assert() directly; use contract checking macros instead") +gsl_constexpr14 inline +void fail_fast_assert( bool cond ) gsl_noexcept +{ + if ( !cond ) + std::terminate(); +} + +#endif + + +// +// GSL.util: utilities +// + +#if gsl_FEATURE( EXPERIMENTAL_RETURN_GUARD ) + +// Add uncaught_exceptions for pre-2017 MSVC, GCC and Clang +// Return unsigned char to save stack space, uncaught_exceptions can only increase by 1 in a scope + +namespace std11 { + +# if gsl_HAVE( UNCAUGHT_EXCEPTIONS ) + +inline unsigned char uncaught_exceptions() gsl_noexcept +{ + return static_cast<unsigned char>( std::uncaught_exceptions() ); +} + +# else // ! gsl_HAVE( UNCAUGHT_EXCEPTIONS ) +# if defined( _MSC_VER ) // MS-STL with either MSVC or clang-cl + +inline unsigned char uncaught_exceptions() gsl_noexcept +{ + return static_cast<unsigned char>( *reinterpret_cast<unsigned const*>( detail::_getptd() + (sizeof(void *) == 8 ? 0x100 : 0x90 ) ) ); +} + +# elif gsl_COMPILER_CLANG_VERSION || gsl_COMPILER_GNUC_VERSION || gsl_COMPILER_APPLECLANG_VERSION + +inline unsigned char uncaught_exceptions() gsl_noexcept +{ + return static_cast<unsigned char>( ( *reinterpret_cast<unsigned const *>( reinterpret_cast<unsigned char const *>(detail::__cxa_get_globals()) + sizeof(void *) ) ) ); +} + +# endif +# endif + +} // namespace std11 + +#endif // gsl_FEATURE( EXPERIMENTAL_RETURN_GUARD ) + +#if gsl_STDLIB_CPP11_110 + +gsl_DISABLE_MSVC_WARNINGS( 4702 ) // unreachable code + +template< class F > +class final_action +{ +public: + explicit final_action( F action ) gsl_noexcept + : action_( std::move( action ) ) + , invoke_( true ) + {} + + final_action( final_action && other ) gsl_noexcept + : action_( std::move( other.action_ ) ) + , invoke_( other.invoke_ ) + { + other.invoke_ = false; + } + + gsl_SUPPRESS_MSGSL_WARNING(f.6) + virtual ~final_action() gsl_noexcept + { + if ( invoke_ ) + action_(); + } + +gsl_is_delete_access: + final_action( final_action const & ) gsl_is_delete; + final_action & operator=( final_action const & ) gsl_is_delete; + final_action & operator=( final_action && ) gsl_is_delete; + +protected: + void dismiss() gsl_noexcept + { + invoke_ = false; + } + +private: + F action_; + bool invoke_; +}; + +template< class F > +gsl_NODISCARD inline final_action<F> +finally( F const & action ) gsl_noexcept +{ + return final_action<F>( action ); +} + +template< class F > +gsl_NODISCARD inline final_action<F> +finally( F && action ) gsl_noexcept +{ + return final_action<F>( std::forward<F>( action ) ); +} + +# if gsl_FEATURE( EXPERIMENTAL_RETURN_GUARD ) + +template< class F > +class final_action_return : public final_action<F> +{ +public: + explicit final_action_return( F && action ) gsl_noexcept + : final_action<F>( std::move( action ) ) + , exception_count( std11::uncaught_exceptions() ) + {} + + final_action_return( final_action_return && other ) gsl_noexcept + : final_action<F>( std::move( other ) ) + , exception_count( std11::uncaught_exceptions() ) + {} + + ~final_action_return() override + { + if ( std11::uncaught_exceptions() != exception_count ) + this->dismiss(); + } + +gsl_is_delete_access: + final_action_return( final_action_return const & ) gsl_is_delete; + final_action_return & operator=( final_action_return const & ) gsl_is_delete; + +private: + unsigned char exception_count; +}; + +template< class F > +gsl_NODISCARD inline final_action_return<F> +on_return( F const & action ) gsl_noexcept +{ + return final_action_return<F>( action ); +} + +template< class F > +gsl_NODISCARD inline final_action_return<F> +on_return( F && action ) gsl_noexcept +{ + return final_action_return<F>( std::forward<F>( action ) ); +} + +template< class F > +class final_action_error : public final_action<F> +{ +public: + explicit final_action_error( F && action ) gsl_noexcept + : final_action<F>( std::move( action ) ) + , exception_count( std11::uncaught_exceptions() ) + {} + + final_action_error( final_action_error && other ) gsl_noexcept + : final_action<F>( std::move( other ) ) + , exception_count( std11::uncaught_exceptions() ) + {} + + ~final_action_error() override + { + if ( std11::uncaught_exceptions() == exception_count ) + this->dismiss(); + } + +gsl_is_delete_access: + final_action_error( final_action_error const & ) gsl_is_delete; + final_action_error & operator=( final_action_error const & ) gsl_is_delete; + +private: + unsigned char exception_count; +}; + +template< class F > +gsl_NODISCARD inline final_action_error<F> +on_error( F const & action ) gsl_noexcept +{ + return final_action_error<F>( action ); +} + +template< class F > +gsl_NODISCARD inline final_action_error<F> +on_error( F && action ) gsl_noexcept +{ + return final_action_error<F>( std::forward<F>( action ) ); +} + +# endif // gsl_FEATURE( EXPERIMENTAL_RETURN_GUARD ) + +gsl_RESTORE_MSVC_WARNINGS() + +#else // ! gsl_STDLIB_CPP11_110 + +class final_action +{ +public: + typedef void (*Action)(); + + final_action( Action action ) + : action_( action ) + , invoke_( true ) + {} + + final_action( final_action const & other ) + : action_( other.action_ ) + , invoke_( other.invoke_ ) + { + other.invoke_ = false; + } + + virtual ~final_action() + { + if ( invoke_ ) + action_(); + } + +protected: + void dismiss() + { + invoke_ = false; + } + +private: + final_action & operator=( final_action const & ); + +private: + Action action_; + mutable bool invoke_; +}; + +template< class F > +inline final_action finally( F const & f ) +{ + return final_action(( f )); +} + +#if gsl_FEATURE( EXPERIMENTAL_RETURN_GUARD ) + +class final_action_return : public final_action +{ +public: + explicit final_action_return( Action action ) + : final_action( action ) + , exception_count( std11::uncaught_exceptions() ) + {} + + ~final_action_return() + { + if ( std11::uncaught_exceptions() != exception_count ) + this->dismiss(); + } + +private: + final_action_return & operator=( final_action_return const & ); + +private: + unsigned char exception_count; +}; + +template< class F > +inline final_action_return on_return( F const & action ) +{ + return final_action_return( action ); +} + +class final_action_error : public final_action +{ +public: + explicit final_action_error( Action action ) + : final_action( action ) + , exception_count( std11::uncaught_exceptions() ) + {} + + ~final_action_error() + { + if ( std11::uncaught_exceptions() == exception_count ) + this->dismiss(); + } + +private: + final_action_error & operator=( final_action_error const & ); + +private: + unsigned char exception_count; +}; + +template< class F > +inline final_action_error on_error( F const & action ) +{ + return final_action_error( action ); +} + +# endif // gsl_FEATURE( EXPERIMENTAL_RETURN_GUARD ) + +#endif // gsl_STDLIB_CPP11_110 + +#if gsl_STDLIB_CPP11_120 + +template< class T, class U > +gsl_NODISCARD gsl_api inline gsl_constexpr T +narrow_cast( U && u ) gsl_noexcept +{ + return static_cast<T>( std::forward<U>( u ) ); +} + +#else // ! gsl_STDLIB_CPP11_120 + +template< class T, class U > +gsl_api inline T +narrow_cast( U u ) gsl_noexcept +{ + return static_cast<T>( u ); +} + +#endif // gsl_STDLIB_CPP11_120 + +struct narrowing_error : public std::exception +{ + char const * what() const gsl_noexcept +#if gsl_HAVE( OVERRIDE_FINAL ) + override +#endif + { + return "narrowing_error"; + } +}; + +#if gsl_HAVE( TYPE_TRAITS ) + +namespace detail { + + template< class T, class U > + struct is_same_signedness : public std::integral_constant<bool, std::is_signed<T>::value == std::is_signed<U>::value> {}; + +# if gsl_COMPILER_NVCC_VERSION + // We do this to circumvent NVCC warnings about pointless unsigned comparisons with 0. + template< class T > + gsl_constexpr gsl_api bool is_negative( T value, std::true_type /*isSigned*/ ) gsl_noexcept + { + return value < T(); + } + template< class T > + gsl_constexpr gsl_api bool is_negative( T /*value*/, std::false_type /*isUnsigned*/ ) gsl_noexcept + { + return false; + } + template< class T, class U > + gsl_constexpr gsl_api bool have_same_sign( T, U, std::true_type /*isSameSignedness*/ ) gsl_noexcept + { + return true; + } + template< class T, class U > + gsl_constexpr gsl_api bool have_same_sign( T t, U u, std::false_type /*isSameSignedness*/ ) gsl_noexcept + { + return detail::is_negative( t, std::is_signed<T>() ) == detail::is_negative( u, std::is_signed<U>() ); + } +# endif // gsl_COMPILER_NVCC_VERSION + +} // namespace detail + +#endif + +template< class T, class U > +gsl_NODISCARD +#if !gsl_CONFIG( NARROW_THROWS_ON_TRUNCATION ) && !defined( gsl_CONFIG_CONTRACT_VIOLATION_THROWS ) +gsl_api +#endif +inline T +narrow( U u ) +{ +#if gsl_CONFIG( NARROW_THROWS_ON_TRUNCATION ) && ! gsl_HAVE( EXCEPTIONS ) + gsl_STATIC_ASSERT_( detail::dependent_false< T >::value, + "According to the GSL specification, narrow<>() throws an exception of type narrowing_error on truncation. Therefore " + "it cannot be used if exceptions are disabled. Consider using narrow_failfast<>() instead which raises a precondition " + "violation if the given value cannot be represented in the target type." ); +#endif + + T t = static_cast<T>( u ); + + if ( static_cast<U>( t ) != u ) + { +#if gsl_HAVE( EXCEPTIONS ) && ( gsl_CONFIG( NARROW_THROWS_ON_TRUNCATION ) || defined( gsl_CONFIG_CONTRACT_VIOLATION_THROWS ) ) + throw narrowing_error(); +#else + std::terminate(); +#endif + } + +#if gsl_HAVE( TYPE_TRAITS ) +# if gsl_COMPILER_NVCC_VERSION + if ( ! detail::have_same_sign( t, u, detail::is_same_signedness<T, U>() ) ) +# else + gsl_SUPPRESS_MSVC_WARNING( 4127, "conditional expression is constant" ) + if ( ! detail::is_same_signedness<T, U>::value && ( t < T() ) != ( u < U() ) ) +# endif +#else + // Don't assume T() works: + gsl_SUPPRESS_MSVC_WARNING( 4127, "conditional expression is constant" ) + if ( ( t < 0 ) != ( u < 0 ) ) +#endif + { +#if gsl_HAVE( EXCEPTIONS ) && ( gsl_CONFIG( NARROW_THROWS_ON_TRUNCATION ) || defined( gsl_CONFIG_CONTRACT_VIOLATION_THROWS ) ) + throw narrowing_error(); +#else + std::terminate(); +#endif + } + + return t; +} + +template< class T, class U > +gsl_NODISCARD gsl_api inline T +narrow_failfast( U u ) +{ + T t = static_cast<T>( u ); + + gsl_Expects( static_cast<U>( t ) == u ); + +#if gsl_HAVE( TYPE_TRAITS ) +# if gsl_COMPILER_NVCC_VERSION + gsl_Expects( ::gsl::detail::have_same_sign( t, u, ::gsl::detail::is_same_signedness<T, U>() ) ); +# else + gsl_SUPPRESS_MSVC_WARNING( 4127, "conditional expression is constant" ) + gsl_Expects( ( ::gsl::detail::is_same_signedness<T, U>::value || ( t < T() ) == ( u < U() ) ) ); +# endif +#else + // Don't assume T() works: + gsl_SUPPRESS_MSVC_WARNING( 4127, "conditional expression is constant" ) + gsl_Expects( ( t < 0 ) == ( u < 0 ) ); +#endif + + return t; +} + + +// +// at() - Bounds-checked way of accessing static arrays, std::array, std::vector. +// + +template< class T, size_t N > +gsl_NODISCARD gsl_api inline gsl_constexpr14 T & +at( T(&arr)[N], size_t pos ) +{ + gsl_Expects( pos < N ); + return arr[pos]; +} + +template< class Container > +gsl_NODISCARD gsl_api inline gsl_constexpr14 typename Container::value_type & +at( Container & cont, size_t pos ) +{ + gsl_Expects( pos < cont.size() ); + return cont[pos]; +} + +template< class Container > +gsl_NODISCARD gsl_api inline gsl_constexpr14 typename Container::value_type const & +at( Container const & cont, size_t pos ) +{ + gsl_Expects( pos < cont.size() ); + return cont[pos]; +} + +#if gsl_HAVE( INITIALIZER_LIST ) + +template< class T > +gsl_NODISCARD gsl_api inline const gsl_constexpr14 T +at( std::initializer_list<T> cont, size_t pos ) +{ + gsl_Expects( pos < cont.size() ); + return *( cont.begin() + pos ); +} +#endif + +template< class T > +gsl_NODISCARD gsl_api inline gsl_constexpr14 T & +at( span<T> s, size_t pos ) +{ + return s[ pos ]; +} + +// +// GSL.views: views +// + +// +// not_null<> - Wrap any indirection and enforce non-null. +// + +template< class T > +class not_null; + +namespace detail { + +// helper class to figure out the pointed-to type of a pointer +#if gsl_STDLIB_CPP11_OR_GREATER +template< class T, class E = void > +struct element_type_helper +{ + // For types without a member element_type (this will handle raw pointers) + typedef typename std::remove_reference< decltype( *std::declval<T>() ) >::type type; +}; + +template< class T > +struct element_type_helper< T, std17::void_t< typename T::element_type > > +{ + // For types with a member element_type + typedef typename T::element_type type; +}; +#else // ! gsl_STDLIB_CPP11_OR_GREATER +// Pre-C++11, we cannot have decltype, so we cannot handle types without a member element_type +template< class T, class E = void > +struct element_type_helper +{ + typedef typename T::element_type type; +}; + +template< class T > +struct element_type_helper< T* > +{ + typedef T type; +}; +#endif // gsl_STDLIB_CPP11_OR_GREATER + +template< class T > +struct is_not_null_or_bool_oracle : std11::false_type { }; +template< class T > +struct is_not_null_or_bool_oracle< not_null<T> > : std11::true_type { }; +template<> +struct is_not_null_or_bool_oracle< bool > : std11::true_type { }; + + +template< class T, bool IsCopyable = true > +struct not_null_data; +#if gsl_HAVE( MOVE_FORWARD ) +template< class T > +struct not_null_data< T, false > +{ + T ptr_; + + gsl_api gsl_constexpr14 not_null_data( T && _ptr ) gsl_noexcept + : ptr_( std::move( _ptr ) ) + { + } + + gsl_api gsl_constexpr14 not_null_data( not_null_data && other ) gsl_noexcept + : ptr_( std::move( other.ptr_ ) ) + { + } + gsl_api gsl_constexpr14 not_null_data & operator=( not_null_data && other ) gsl_noexcept + { + ptr_ = std::move( other.ptr_ ); + return *this; + } + +gsl_is_delete_access: + not_null_data( not_null_data const & ) gsl_is_delete; + not_null_data & operator=( not_null_data const & ) gsl_is_delete; +}; +# if gsl_CONFIG_DEFAULTS_VERSION >= 1 +# endif // gsl_CONFIG_DEFAULTS_VERSION >= 1 +#endif // gsl_HAVE( MOVE_FORWARD ) +template< class T > +struct not_null_data< T, true > +{ + T ptr_; + + gsl_api gsl_constexpr14 not_null_data( T const & _ptr ) gsl_noexcept + : ptr_( _ptr ) + { + } + +#if gsl_HAVE( MOVE_FORWARD ) + gsl_api gsl_constexpr14 not_null_data( T && _ptr ) gsl_noexcept + : ptr_( std::move( _ptr ) ) + { + } + + gsl_api gsl_constexpr14 not_null_data( not_null_data && other ) gsl_noexcept + : ptr_( std::move( other.ptr_ ) ) + { + } + gsl_api gsl_constexpr14 not_null_data & operator=( not_null_data && other ) gsl_noexcept + { + ptr_ = std::move( other.ptr_ ); + return *this; + } +#endif // gsl_HAVE( MOVE_FORWARD ) + + gsl_api gsl_constexpr14 not_null_data( not_null_data const & other ) + : ptr_( other.ptr_ ) + { + gsl_Expects( ptr_ != gsl_nullptr ); + } + gsl_api gsl_constexpr14 not_null_data & operator=( not_null_data const & other ) + { + gsl_Expects( other.ptr_ != gsl_nullptr ); + ptr_ = other.ptr_; + return *this; + } +}; +#if gsl_CONFIG_DEFAULTS_VERSION >= 1 +template< class T > +struct not_null_data< T *, true > +{ + T * ptr_; + + gsl_api gsl_constexpr14 not_null_data( T * _ptr ) gsl_noexcept + : ptr_( _ptr ) + { + } +}; +#endif // gsl_CONFIG_DEFAULTS_VERSION >= 1 +template< class T > +struct is_copyable +#if gsl_HAVE( TYPE_TRAITS ) +: std11::integral_constant< bool, std::is_copy_constructible<T>::value && std::is_copy_assignable<T>::value > +#else +: std11::true_type +#endif +{ +}; +#if gsl_HAVE( TYPE_TRAITS ) && gsl_HAVE( UNIQUE_PTR ) && gsl_BETWEEN( gsl_COMPILER_MSVC_VERSION, 1, 140 ) +// Type traits are buggy in VC++ 2013, so we explicitly declare `unique_ptr<>` non-copyable. +template< class T, class Deleter > +struct is_copyable< std::unique_ptr< T, Deleter > > : std11::false_type +{ +}; +#endif + +template< class T > +struct not_null_accessor; + +} // namespace detail + +template< class T > +class not_null +{ +private: + detail::not_null_data< T, detail::is_copyable< T >::value > data_; + + // need to access `not_null<U>::data_` + template< class U > + friend class not_null; + + template< class U > + friend struct detail::not_null_accessor; + +public: + typedef typename detail::element_type_helper<T>::type element_type; + +#if gsl_HAVE( TYPE_TRAITS ) + static_assert( std::is_assignable<typename std::remove_const<typename std::remove_reference<T>::type>::type&, std::nullptr_t>::value, "T cannot be assigned nullptr." ); +#endif + +#if gsl_CONFIG( NOT_NULL_EXPLICIT_CTOR ) +# if gsl_HAVE( MOVE_FORWARD ) + template< class U + // In Clang 3.x, `is_constructible<not_null<unique_ptr<X>>, unique_ptr<X>>` tries to instantiate the copy constructor of `unique_ptr<>`, triggering an error. + // Note that Apple Clang's `__clang_major__` etc. are different from regular Clang. +# if gsl_HAVE( TYPE_TRAITS ) && gsl_HAVE( DEFAULT_FUNCTION_TEMPLATE_ARG ) && ! gsl_BETWEEN( gsl_COMPILER_CLANG_VERSION, 1, 400 ) && ! gsl_BETWEEN( gsl_COMPILER_APPLECLANG_VERSION, 1, 1001 ) + // We *have* to use SFINAE with an NTTP arg here, otherwise the overload is ambiguous. + , typename std::enable_if< ( std::is_constructible<T, U>::value ), int >::type = 0 +# endif + > + gsl_api gsl_constexpr14 explicit not_null( U other ) + : data_( T( std::move( other ) ) ) + { + gsl_Expects( data_.ptr_ != gsl_nullptr ); + } +# else // a.k.a. ! gsl_HAVE( MOVE_FORWARD ) + template< class U > + gsl_api gsl_constexpr14 explicit not_null( U const& other ) + : data_( T( other ) ) + { + gsl_Expects( data_.ptr_ != gsl_nullptr ); + } +# endif // gsl_HAVE( MOVE_FORWARD ) +#else // a.k.a. !gsl_CONFIG( NOT_NULL_EXPLICIT_CTOR ) +# if gsl_HAVE( MOVE_FORWARD ) + // In Clang 3.x, `is_constructible<not_null<unique_ptr<X>>, unique_ptr<X>>` tries to instantiate the copy constructor of `unique_ptr<>`, triggering an error. + // Note that Apple Clang's `__clang_major__` etc. are different from regular Clang. +# if gsl_HAVE( TYPE_TRAITS ) && gsl_HAVE( DEFAULT_FUNCTION_TEMPLATE_ARG ) && ! gsl_BETWEEN( gsl_COMPILER_CLANG_VERSION, 1, 400 ) && ! gsl_BETWEEN( gsl_COMPILER_APPLECLANG_VERSION, 1, 1001 ) + template< class U + // We *have* to use SFINAE with an NTTP arg here, otherwise the overload is ambiguous. + , typename std::enable_if< ( std::is_constructible<T, U>::value && !std::is_convertible<U, T>::value ), int >::type = 0 + > + gsl_api gsl_constexpr14 explicit not_null( U other ) + : data_( T( std::move( other ) ) ) + { + gsl_Expects( data_.ptr_ != gsl_nullptr ); + } + + template< class U + // We *have* to use SFINAE with an NTTP arg here, otherwise the overload is ambiguous. + , typename std::enable_if< ( std::is_convertible<U, T>::value ), int >::type = 0 + > + gsl_api gsl_constexpr14 not_null( U other ) + : data_( std::move( other ) ) + { + gsl_Expects( data_.ptr_ != gsl_nullptr ); + } +# else // a.k.a. !( gsl_HAVE( TYPE_TRAITS ) && gsl_HAVE( DEFAULT_FUNCTION_TEMPLATE_ARG ) && ! gsl_BETWEEN( gsl_COMPILER_CLANG_VERSION, 1, 400 ) && ! gsl_BETWEEN( gsl_COMPILER_APPLECLANG_VERSION, 1, 1001 ) + // If type_traits are not available, then we can't distinguish `is_convertible<>` and `is_constructible<>`, so we unconditionally permit implicit construction. + template< class U > + gsl_api gsl_constexpr14 not_null( U other ) + : data_( T( std::move( other ) ) ) + { + gsl_Expects( data_.ptr_ != gsl_nullptr ); + } +# endif // gsl_HAVE( TYPE_TRAITS ) && gsl_HAVE( DEFAULT_FUNCTION_TEMPLATE_ARG ) && ! gsl_BETWEEN( gsl_COMPILER_CLANG_VERSION, 1, 400 ) && ! gsl_BETWEEN( gsl_COMPILER_APPLECLANG_VERSION, 1, 1001 ) +# else // a.k.a. ! gsl_HAVE( MOVE_FORWARD ) + template< class U > + gsl_api gsl_constexpr14 not_null( U const& other ) + : data_( T( other ) ) + { + gsl_Expects( data_.ptr_ != gsl_nullptr ); + } +# endif // gsl_HAVE( MOVE_FORWARD ) +#endif // gsl_CONFIG( NOT_NULL_EXPLICIT_CTOR ) + +public: +#if gsl_HAVE( MOVE_FORWARD ) + // In Clang 3.x, `is_constructible<not_null<unique_ptr<X>>, unique_ptr<X>>` tries to instantiate the copy constructor of `unique_ptr<>`, triggering an error. + // Note that Apple Clang's `__clang_major__` etc. are different from regular Clang. +# if gsl_HAVE( TYPE_TRAITS ) && gsl_HAVE( DEFAULT_FUNCTION_TEMPLATE_ARG ) && ! gsl_BETWEEN( gsl_COMPILER_CLANG_VERSION, 1, 400 ) && ! gsl_BETWEEN( gsl_COMPILER_APPLECLANG_VERSION, 1, 1001 ) + template< class U + // We *have* to use SFINAE with an NTTP arg here, otherwise the overload is ambiguous. + , typename std::enable_if< ( std::is_constructible<T, U>::value && !std::is_convertible<U, T>::value ), int >::type = 0 + > + gsl_api gsl_constexpr14 explicit not_null( not_null<U> other ) + : data_( T( std::move( other.data_.ptr_ ) ) ) + { + gsl_Expects( data_.ptr_ != gsl_nullptr ); + } + + template< class U + // We *have* to use SFINAE with an NTTP arg here, otherwise the overload is ambiguous. + , typename std::enable_if< ( std::is_convertible<U, T>::value ), int >::type = 0 + > + gsl_api gsl_constexpr14 not_null( not_null<U> other ) + : data_( T( std::move( other.data_.ptr_ ) ) ) + { + gsl_Expects( data_.ptr_ != gsl_nullptr ); + } +# else // a.k.a. ! ( gsl_HAVE( TYPE_TRAITS ) && gsl_HAVE( DEFAULT_FUNCTION_TEMPLATE_ARG ) && ! gsl_BETWEEN( gsl_COMPILER_CLANG_VERSION, 1, 400 ) && ! gsl_BETWEEN( gsl_COMPILER_APPLECLANG_VERSION, 1, 1001 ) + // If type_traits are not available, then we can't distinguish `is_convertible<>` and `is_constructible<>`, so we unconditionally permit implicit construction. + template< class U > + gsl_api gsl_constexpr14 not_null( not_null<U> other ) + : data_( T( std::move( other.data_.ptr_ ) ) ) + { + gsl_Expects( data_.ptr_ != gsl_nullptr ); + } + template< class U > + gsl_api gsl_constexpr14 not_null<T>& operator=( not_null<U> other ) + { + gsl_Expects( other.data_.ptr_ != gsl_nullptr ); + data_.ptr_ = std::move( other.data_.ptr_ ); + return *this; + } +# endif // gsl_HAVE( TYPE_TRAITS ) && gsl_HAVE( DEFAULT_FUNCTION_TEMPLATE_ARG ) && ! gsl_BETWEEN( gsl_COMPILER_CLANG_VERSION, 1, 400 ) && ! gsl_BETWEEN( gsl_COMPILER_APPLECLANG_VERSION, 1, 1001 ) +#else // a.k.a. ! gsl_HAVE( MOVE_FORWARD ) + template< class U > + gsl_api gsl_constexpr14 not_null( not_null<U> const& other ) + : data_( T( other.data_.ptr_ ) ) + { + gsl_Expects( data_.ptr_ != gsl_nullptr ); + } + template< class U > + gsl_api gsl_constexpr14 not_null<T>& operator=( not_null<U> const & other ) + { + gsl_Expects( other.data_.ptr_ != gsl_nullptr ); + data_.ptr_ = other.data_.ptr_; + return *this; + } +#endif // gsl_HAVE( MOVE_FORWARD ) + +#if gsl_CONFIG( TRANSPARENT_NOT_NULL ) + gsl_NODISCARD gsl_api gsl_constexpr14 element_type * + get() const + { + element_type * result = data_.ptr_.get(); + gsl_Ensures( result != gsl_nullptr ); + return result; + } +#else +# if gsl_CONFIG( NOT_NULL_GET_BY_CONST_REF ) + gsl_NODISCARD gsl_api gsl_constexpr14 T const & + get() const + { + T const & result = data_.ptr_; + gsl_Ensures( result != gsl_nullptr ); + return result; + } +# else + gsl_NODISCARD gsl_api gsl_constexpr14 T + get() const + { + T result = data_.ptr_; + gsl_Ensures( result != gsl_nullptr ); + return result; + } +# endif +#endif + + // We want an implicit conversion operator that can be used to convert from both lvalues (by + // const reference or by copy) and rvalues (by move). So it seems like we could define + // + // template< class U > + // operator U const &() const & { ... } + // template< class U > + // operator U &&() && { ... } + // + // However, having two conversion operators with different return types renders the assignment + // operator of the result type ambiguous: + // + // not_null<std::unique_ptr<T>> p( ... ); + // std::unique_ptr<U> q; + // q = std::move( p ); // ambiguous + // + // To avoid this ambiguity, we have both overloads of the conversion operator return `U` + // rather than `U const &` or `U &&`. This implies that converting an lvalue always induces + // a copy, which can cause unnecessary copies or even fail to compile in some situations: + // + // not_null<std::shared_ptr<T>> sp( ... ); + // std::shared_ptr<U> const & rs = sp; // unnecessary copy + // std::unique_ptr<U> const & ru = p; // error: cannot copy `unique_ptr<T>` + // + // However, these situations are rather unusual, and the following, more frequent situations + // remain unimpaired: + // + // std::shared_ptr<U> vs = sp; // no extra copy + // std::unique_ptr<U> vu = std::move( p ); + +#if gsl_HAVE( MOVE_FORWARD ) && gsl_HAVE( TYPE_TRAITS ) && gsl_HAVE( DEFAULT_FUNCTION_TEMPLATE_ARG ) && gsl_HAVE( EXPLICIT ) + // explicit conversion operator + + template< class U + // We *have* to use SFINAE with an NTTP arg here, otherwise the overload is ambiguous. + , typename std::enable_if< ( std::is_constructible<U, T const &>::value && !std::is_convertible<T, U>::value && !detail::is_not_null_or_bool_oracle<U>::value ), int >::type = 0 + > + gsl_NODISCARD gsl_api gsl_constexpr14 explicit + operator U() const +# if gsl_HAVE( FUNCTION_REF_QUALIFIER ) + & +# endif + { + U result( data_.ptr_ ); + gsl_Ensures( result != gsl_nullptr ); + return result; + } +# if gsl_HAVE( FUNCTION_REF_QUALIFIER ) + template< class U + // We *have* to use SFINAE with an NTTP arg here, otherwise the overload is ambiguous. + , typename std::enable_if< ( std::is_constructible<U, T>::value && !std::is_convertible<T, U>::value && !detail::is_not_null_or_bool_oracle<U>::value ), int >::type = 0 + > + gsl_NODISCARD gsl_api gsl_constexpr14 explicit + operator U() && + { + U result( std::move( data_.ptr_ ) ); + gsl_Ensures( result != gsl_nullptr ); + return result; + } +# endif + + // implicit conversion operator + template< class U + // We *have* to use SFINAE with an NTTP arg here, otherwise the overload is ambiguous. + , typename std::enable_if< ( std::is_constructible<U, T const &>::value && std::is_convertible<T, U>::value && !detail::is_not_null_or_bool_oracle<U>::value ), int >::type = 0 + > + gsl_NODISCARD gsl_api gsl_constexpr14 + operator U() const +# if gsl_HAVE( FUNCTION_REF_QUALIFIER ) + & +# endif + { + U result( data_.ptr_ ); + gsl_Ensures( result != gsl_nullptr ); + return result; + } +# if gsl_HAVE( FUNCTION_REF_QUALIFIER ) + template< class U + // We *have* to use SFINAE with an NTTP arg here, otherwise the overload is ambiguous. + , typename std::enable_if< ( std::is_convertible<T, U>::value && !detail::is_not_null_or_bool_oracle<U>::value ), int >::type = 0 + > + gsl_NODISCARD gsl_api gsl_constexpr14 + operator U() && + { + U result( std::move( data_.ptr_ ) ); + gsl_Ensures( result != gsl_nullptr ); + return result; + } +# endif +#else // a.k.a. #if !( gsl_HAVE( MOVE_FORWARD ) && gsl_HAVE( TYPE_TRAITS ) && gsl_HAVE( DEFAULT_FUNCTION_TEMPLATE_ARG ) && gsl_HAVE( EXPLICIT ) ) + template< class U > + gsl_NODISCARD gsl_api gsl_constexpr14 + operator U() const + { + U result( data_.ptr_ ); + gsl_Ensures( result != gsl_nullptr ); + return result; + } +#endif // gsl_HAVE( MOVE_FORWARD ) && gsl_HAVE( TYPE_TRAITS ) && gsl_HAVE( DEFAULT_FUNCTION_TEMPLATE_ARG ) && gsl_HAVE( EXPLICIT ) + + gsl_NODISCARD gsl_api gsl_constexpr14 T const & + operator->() const + { + T const & result( data_.ptr_ ); + gsl_Ensures( result != gsl_nullptr ); + return result; + } + + gsl_NODISCARD gsl_api gsl_constexpr14 element_type & + operator*() const + { + gsl_Expects( data_.ptr_ != gsl_nullptr ); + return *data_.ptr_; + } + +#if gsl_HAVE( MOVE_FORWARD ) + // Visual C++ 2013 doesn't generate default move constructors, so we declare them explicitly. + gsl_api gsl_constexpr14 not_null( not_null && other ) + gsl_noexcept_not_testing // we want to be nothrow-movable despite the precondition check + : data_( std::move( other.data_ ) ) + { + gsl_Expects( data_.ptr_ != gsl_nullptr ); + } + gsl_api gsl_constexpr14 not_null & operator=( not_null && other ) + gsl_noexcept_not_testing // we want to be nothrow-movable despite the precondition check + { + gsl_Expects( other.data_.ptr_ != gsl_nullptr || &other == this ); + data_ = std::move( other.data_ ); + return *this; + } +#endif // gsl_HAVE( MOVE_FORWARD ) + +#if gsl_HAVE( IS_DEFAULT ) + gsl_constexpr14 not_null( not_null const & ) = default; + gsl_constexpr14 not_null & operator=( not_null const & ) = default; +#endif + + gsl_api gsl_constexpr20 friend void swap( not_null & lhs, not_null & rhs ) + gsl_noexcept_not_testing // we want to be nothrow-swappable despite the precondition check + { + gsl_Expects( lhs.data_.ptr_ != gsl_nullptr && rhs.data_.ptr_ != gsl_nullptr ); + using std::swap; + swap( lhs.data_.ptr_, rhs.data_.ptr_ ); + } + +gsl_is_delete_access: + not_null() gsl_is_delete; + // prevent compilation when initialized with a nullptr or literal 0: +#if gsl_HAVE( NULLPTR ) + not_null( std::nullptr_t ) gsl_is_delete; + not_null & operator=( std::nullptr_t ) gsl_is_delete; +#else + not_null( int ) gsl_is_delete; + not_null & operator=( int ) gsl_is_delete; +#endif + + // unwanted operators...pointers only point to single objects! + not_null & operator++() gsl_is_delete; + not_null & operator--() gsl_is_delete; + not_null operator++( int ) gsl_is_delete; + not_null operator--( int ) gsl_is_delete; + not_null & operator+ ( size_t ) gsl_is_delete; + not_null & operator+=( size_t ) gsl_is_delete; + not_null & operator- ( size_t ) gsl_is_delete; + not_null & operator-=( size_t ) gsl_is_delete; + not_null & operator+=( std::ptrdiff_t ) gsl_is_delete; + not_null & operator-=( std::ptrdiff_t ) gsl_is_delete; + void operator[]( std::ptrdiff_t ) const gsl_is_delete; +}; +#if gsl_CONFIG_DEFAULTS_VERSION >= 1 +template< class T > +class not_null< T * > +{ +private: + detail::not_null_data<T *, true> data_; + + // need to access `not_null<U>::data_` + template< class U > + friend class not_null; + + template< class U > + friend struct detail::not_null_accessor; + +public: + typedef T element_type; + + gsl_api gsl_constexpr14 +#if gsl_CONFIG( NOT_NULL_EXPLICIT_CTOR ) + explicit +#endif // gsl_CONFIG( NOT_NULL_EXPLICIT_CTOR ) + not_null( T * other ) + : data_( other ) + { + gsl_Expects( data_.ptr_ != gsl_nullptr ); + } + +#if gsl_HAVE( MOVE_FORWARD ) + // In Clang 3.x, `is_constructible<not_null<unique_ptr<X>>, unique_ptr<X>>` tries to instantiate the copy constructor of `unique_ptr<>`, triggering an error. + // Note that Apple Clang's `__clang_major__` etc. are different from regular Clang. +# if gsl_HAVE( TYPE_TRAITS ) && gsl_HAVE( DEFAULT_FUNCTION_TEMPLATE_ARG ) && ! gsl_BETWEEN( gsl_COMPILER_CLANG_VERSION, 1, 400 ) && ! gsl_BETWEEN( gsl_COMPILER_APPLECLANG_VERSION, 1, 1001 ) + template< class U + // We *have* to use SFINAE with an NTTP arg here, otherwise the overload is ambiguous. + , typename std::enable_if< ( std::is_constructible<T*, U>::value && !std::is_convertible<U, T*>::value ), int >::type = 0 + > + gsl_api gsl_constexpr14 explicit not_null( not_null<U> other ) + : data_( static_cast<T*>( std::move( other.data_.ptr_ ) ) ) + { + gsl_Expects( data_.ptr_ != gsl_nullptr ); + } + + template< class U + // We *have* to use SFINAE with an NTTP arg here, otherwise the overload is ambiguous. + , typename std::enable_if< ( std::is_convertible<U, T*>::value ), int >::type = 0 + > + gsl_api gsl_constexpr14 not_null( not_null<U> other ) + : data_( std::move( other.data_.ptr_ ) ) + { + gsl_Expects( data_.ptr_ != gsl_nullptr ); + } +# else // a.k.a. ! ( gsl_HAVE( TYPE_TRAITS ) && gsl_HAVE( DEFAULT_FUNCTION_TEMPLATE_ARG ) && ! gsl_BETWEEN( gsl_COMPILER_CLANG_VERSION, 1, 400 ) && ! gsl_BETWEEN( gsl_COMPILER_APPLECLANG_VERSION, 1, 1001 ) + // If type_traits are not available, then we can't distinguish `is_convertible<>` and `is_constructible<>`, so we unconditionally permit implicit construction. + template< class U > + gsl_api gsl_constexpr14 not_null( not_null<U> other ) + : data_( std::move( other.data_.ptr_ ) ) + { + gsl_Expects( data_.ptr_ != gsl_nullptr ); + } + template< class U > + gsl_api gsl_constexpr14 not_null<T*>& operator=( not_null<U> other ) + { + gsl_Expects( other.data_.ptr_ != gsl_nullptr ); + data_.ptr_ = std::move( other.data_.ptr_ ); + return *this; + } +# endif // gsl_HAVE( TYPE_TRAITS ) && gsl_HAVE( DEFAULT_FUNCTION_TEMPLATE_ARG ) && ! gsl_BETWEEN( gsl_COMPILER_CLANG_VERSION, 1, 400 ) && ! gsl_BETWEEN( gsl_COMPILER_APPLECLANG_VERSION, 1, 1001 ) +#else // a.k.a. ! gsl_HAVE( MOVE_FORWARD ) + template< class U > + gsl_api gsl_constexpr14 not_null( not_null<U> const& other ) + : data_( other.data_.ptr_ ) + { + gsl_Expects( data_.ptr_ != gsl_nullptr ); + } + template< class U > + gsl_api gsl_constexpr14 not_null<T*>& operator=( not_null<U> const & other ) + { + gsl_Expects( other.data_.ptr_ != gsl_nullptr ); + data_.ptr_ = other.data_.ptr_; + return *this; + } +#endif // gsl_HAVE( MOVE_FORWARD ) + +#if ! gsl_CONFIG( TRANSPARENT_NOT_NULL ) + gsl_NODISCARD gsl_api gsl_constexpr14 T* + get() const + { + return data_.ptr_; + } +#endif + +#if gsl_HAVE( TYPE_TRAITS ) && gsl_HAVE( DEFAULT_FUNCTION_TEMPLATE_ARG ) && gsl_HAVE( EXPLICIT ) + // explicit conversion operator + template< class U + // We *have* to use SFINAE with an NTTP arg here, otherwise the overload is ambiguous. + , typename std::enable_if< ( std::is_constructible<U, T*>::value && !std::is_convertible<T*, U>::value && !detail::is_not_null_or_bool_oracle<U>::value ), int >::type = 0 + > + gsl_NODISCARD gsl_api gsl_constexpr14 explicit + operator U() const + { + return U( data_.ptr_ ); + } + + // implicit conversion operator + template< class U + // We *have* to use SFINAE with an NTTP arg here, otherwise the overload is ambiguous. + , typename std::enable_if< ( std::is_constructible<U, T*>::value && std::is_convertible<T*, U>::value && !detail::is_not_null_or_bool_oracle<U>::value ), int >::type = 0 + > + gsl_NODISCARD gsl_api gsl_constexpr14 + operator U() const + { + return data_.ptr_; + } +#else // a.k.a. #if !( gsl_HAVE( MOVE_FORWARD ) && gsl_HAVE( TYPE_TRAITS ) && gsl_HAVE( DEFAULT_FUNCTION_TEMPLATE_ARG ) && gsl_HAVE( EXPLICIT ) ) + template< class U > + gsl_NODISCARD gsl_api gsl_constexpr14 + operator U() const + { + return data_.ptr_; + } +#endif // gsl_HAVE( MOVE_FORWARD ) && gsl_HAVE( TYPE_TRAITS ) && gsl_HAVE( DEFAULT_FUNCTION_TEMPLATE_ARG ) && gsl_HAVE( EXPLICIT ) + + gsl_NODISCARD gsl_api gsl_constexpr14 T* + operator->() const + { + return data_.ptr_; + } + + gsl_NODISCARD gsl_api gsl_constexpr14 element_type & + operator*() const + { + return *data_.ptr_; + } + +#if gsl_HAVE( IS_DEFAULT ) + gsl_constexpr14 not_null( not_null const & ) = default; + gsl_constexpr14 not_null & operator=( not_null const & ) = default; +#endif + + gsl_api gsl_constexpr20 friend void swap( not_null & lhs, not_null & rhs ) gsl_noexcept + { + using std::swap; + swap( lhs.data_.ptr_, rhs.data_.ptr_ ); + } + +gsl_is_delete_access: + not_null() gsl_is_delete; + // prevent compilation when initialized with a nullptr or literal 0: +#if gsl_HAVE( NULLPTR ) + not_null( std::nullptr_t ) gsl_is_delete; + not_null & operator=( std::nullptr_t ) gsl_is_delete; +#else + not_null( int ) gsl_is_delete; + not_null & operator=( int ) gsl_is_delete; +#endif + + // unwanted operators...pointers only point to single objects! + not_null & operator++() gsl_is_delete; + not_null & operator--() gsl_is_delete; + not_null operator++( int ) gsl_is_delete; + not_null operator--( int ) gsl_is_delete; + not_null & operator+ ( size_t ) gsl_is_delete; + not_null & operator+=( size_t ) gsl_is_delete; + not_null & operator- ( size_t ) gsl_is_delete; + not_null & operator-=( size_t ) gsl_is_delete; + not_null & operator+=( std::ptrdiff_t ) gsl_is_delete; + not_null & operator-=( std::ptrdiff_t ) gsl_is_delete; + void operator[]( std::ptrdiff_t ) const gsl_is_delete; +}; +#endif // gsl_CONFIG_DEFAULTS_VERSION >= 1 +#if gsl_HAVE( DEDUCTION_GUIDES ) +template< class U > +not_null( U ) -> not_null<U>; +template< class U > +not_null( not_null<U> ) -> not_null<U>; +#endif + +#if gsl_HAVE( NULLPTR ) +void make_not_null( std::nullptr_t ) gsl_is_delete; +#endif // gsl_HAVE( NULLPTR ) +#if gsl_HAVE( MOVE_FORWARD ) +template< class U > +gsl_NODISCARD gsl_api gsl_constexpr14 not_null<U> +make_not_null( U u ) +{ + return not_null<U>( std::move( u ) ); +} +template< class U > +gsl_NODISCARD gsl_api gsl_constexpr14 not_null<U> +make_not_null( not_null<U> u ) +{ + return std::move( u ); +} +#else // a.k.a. ! gsl_HAVE( MOVE_FORWARD ) +template< class U > +gsl_NODISCARD gsl_api not_null<U> +make_not_null( U const & u ) +{ + return not_null<U>( u ); +} +template< class U > +gsl_NODISCARD gsl_api not_null<U> +make_not_null( not_null<U> const & u ) +{ + return u; +} +#endif // gsl_HAVE( MOVE_FORWARD ) + +namespace detail { + +template< class T > +struct as_nullable_helper +{ + typedef T type; +}; +template< class T > +struct as_nullable_helper< not_null<T> > +{ +}; + +template< class T > +struct not_null_accessor +{ +#if gsl_HAVE( MOVE_FORWARD ) + static gsl_api T get( not_null<T>&& p ) gsl_noexcept + { + return std::move( p.data_.ptr_ ); + } +#endif + static gsl_api T const & get( not_null<T> const & p ) gsl_noexcept + { + return p.data_.ptr_; + } +}; + +namespace no_adl { + +#if gsl_HAVE( MOVE_FORWARD ) +template< class T > +gsl_NODISCARD gsl_api gsl_constexpr auto as_nullable( T && p ) +gsl_noexcept_if( std::is_nothrow_move_constructible<T>::value ) +-> typename detail::as_nullable_helper<typename std20::remove_cvref<T>::type>::type +{ + return std::move( p ); +} +template< class T > +gsl_NODISCARD gsl_api gsl_constexpr14 T as_nullable( not_null<T> && p ) +{ + T result = detail::not_null_accessor<T>::get( std::move( p ) ); + gsl_Expects( result != gsl_nullptr ); + return result; +} +#else // ! gsl_HAVE( MOVE_FORWARD ) +template< class T > +gsl_NODISCARD gsl_api gsl_constexpr T const & as_nullable( T const & p ) gsl_noexcept +{ + return p; +} +#endif // gsl_HAVE( MOVE_FORWARD ) +template< class T > +gsl_NODISCARD gsl_api gsl_constexpr14 T const & as_nullable( not_null<T> const & p ) +{ + T const & result = detail::not_null_accessor<T>::get( p ); + gsl_Expects( result != gsl_nullptr ); + return result; +} +template< class T > +gsl_NODISCARD gsl_api gsl_constexpr T* as_nullable( not_null<T*> p ) gsl_noexcept +{ + return detail::not_null_accessor<T*>::get( p ); +} + +} // namespace no_adl +} // namespace detail + +using namespace detail::no_adl; + +// not_null with implicit constructor, allowing copy-initialization: + +template< class T > +class not_null_ic : public not_null<T> +{ +public: + template< class U + gsl_ENABLE_IF_(( std::is_constructible<T, U>::value )) + > + gsl_api gsl_constexpr14 +#if gsl_HAVE( MOVE_FORWARD ) + not_null_ic( U && u ) + : not_null<T>( std::forward<U>( u ) ) +#else // ! gsl_HAVE( MOVE_FORWARD ) + not_null_ic( U const & u ) + : not_null<T>( u ) +#endif // gsl_HAVE( MOVE_FORWARD ) + {} +}; + +// more not_null unwanted operators + +template< class T, class U > +std::ptrdiff_t operator-( not_null<T> const &, not_null<U> const & ) gsl_is_delete; + +template< class T > +not_null<T> operator-( not_null<T> const &, std::ptrdiff_t ) gsl_is_delete; + +template< class T > +not_null<T> operator+( not_null<T> const &, std::ptrdiff_t ) gsl_is_delete; + +template< class T > +not_null<T> operator+( std::ptrdiff_t, not_null<T> const & ) gsl_is_delete; + +// not_null comparisons + +#if gsl_HAVE( NULLPTR ) && gsl_HAVE( IS_DELETE ) +template< class T > +gsl_constexpr bool +operator==( not_null<T> const &, std::nullptr_t ) = delete; +template< class T > +gsl_constexpr bool +operator==( std::nullptr_t , not_null<T> const & ) = delete; +template< class T > +gsl_constexpr bool +operator!=( not_null<T> const &, std::nullptr_t ) = delete; +template< class T > +gsl_constexpr bool +operator!=( std::nullptr_t , not_null<T> const & ) = delete; +#endif // gsl_HAVE( NULLPTR ) && gsl_HAVE( IS_DELETE ) + +template< class T, class U > +gsl_NODISCARD inline gsl_api gsl_constexpr gsl_TRAILING_RETURN_TYPE_( bool ) +operator==( not_null<T> const & l, not_null<U> const & r ) +gsl_RETURN_DECLTYPE_( l.operator->() == r.operator->() ) +{ + return l.operator->() == r.operator->(); +} +template< class T, class U > +gsl_NODISCARD inline gsl_api gsl_constexpr gsl_TRAILING_RETURN_TYPE_( bool ) +operator==( not_null<T> const & l, U const & r ) +gsl_RETURN_DECLTYPE_(l.operator->() == r ) +{ + return l.operator->() == r; +} +template< class T, class U > +gsl_NODISCARD inline gsl_api gsl_constexpr gsl_TRAILING_RETURN_TYPE_( bool ) +operator==( T const & l, not_null<U> const & r ) +gsl_RETURN_DECLTYPE_( l == r.operator->() ) +{ + return l == r.operator->(); +} + +template< class T, class U > +gsl_NODISCARD inline gsl_api gsl_constexpr gsl_TRAILING_RETURN_TYPE_( bool ) +operator<( not_null<T> const & l, not_null<U> const & r ) +gsl_RETURN_DECLTYPE_( l.operator->() < r.operator->() ) +{ + return l.operator->() < r.operator->(); +} +template< class T, class U > +gsl_NODISCARD inline gsl_api gsl_constexpr gsl_TRAILING_RETURN_TYPE_( bool ) +operator<( not_null<T> const & l, U const & r ) +gsl_RETURN_DECLTYPE_( l.operator->() < r ) +{ + return l.operator->() < r; +} +template< class T, class U > +gsl_NODISCARD inline gsl_api gsl_constexpr gsl_TRAILING_RETURN_TYPE_( bool ) +operator<( T const & l, not_null<U> const & r ) +gsl_RETURN_DECLTYPE_( l < r.operator->() ) +{ + return l < r.operator->(); +} + +template< class T, class U > +gsl_NODISCARD inline gsl_api gsl_constexpr gsl_TRAILING_RETURN_TYPE_( bool ) +operator!=( not_null<T> const & l, not_null<U> const & r ) +gsl_RETURN_DECLTYPE_( !( l == r ) ) +{ + return !( l == r ); +} +template< class T, class U > +gsl_NODISCARD inline gsl_api gsl_constexpr gsl_TRAILING_RETURN_TYPE_( bool ) +operator!=( not_null<T> const & l, U const & r ) +gsl_RETURN_DECLTYPE_( !( l == r ) ) +{ + return !( l == r ); +} +template< class T, class U > +gsl_NODISCARD inline gsl_api gsl_constexpr gsl_TRAILING_RETURN_TYPE_( bool ) +operator!=( T const & l, not_null<U> const & r ) +gsl_RETURN_DECLTYPE_( !( l == r ) ) +{ + return !( l == r ); +} + +template< class T, class U > +gsl_NODISCARD inline gsl_api gsl_constexpr gsl_TRAILING_RETURN_TYPE_( bool ) +operator<=( not_null<T> const & l, not_null<U> const & r ) +gsl_RETURN_DECLTYPE_( !( r < l ) ) +{ + return !( r < l ); +} +template< class T, class U > +gsl_NODISCARD inline gsl_api gsl_constexpr gsl_TRAILING_RETURN_TYPE_( bool ) +operator<=( not_null<T> const & l, U const & r ) +gsl_RETURN_DECLTYPE_( !( r < l ) ) +{ + return !( r < l ); +} +template< class T, class U > +gsl_NODISCARD inline gsl_api gsl_constexpr gsl_TRAILING_RETURN_TYPE_( bool ) +operator<=( T const & l, not_null<U> const & r ) +gsl_RETURN_DECLTYPE_( !( r < l ) ) +{ + return !( r < l ); +} + +template< class T, class U > +gsl_NODISCARD inline gsl_api gsl_constexpr gsl_TRAILING_RETURN_TYPE_( bool ) +operator>( not_null<T> const & l, not_null<U> const & r ) +gsl_RETURN_DECLTYPE_( r < l ) +{ + return r < l; +} +template< class T, class U > +gsl_NODISCARD inline gsl_api gsl_constexpr gsl_TRAILING_RETURN_TYPE_( bool ) +operator>( not_null<T> const & l, U const & r ) +gsl_RETURN_DECLTYPE_( r < l ) +{ + return r < l; +} +template< class T, class U > +gsl_NODISCARD inline gsl_api gsl_constexpr gsl_TRAILING_RETURN_TYPE_( bool ) +operator>( T const & l, not_null<U> const & r ) +gsl_RETURN_DECLTYPE_( r < l ) +{ + return r < l; +} + +template< class T, class U > +gsl_NODISCARD inline gsl_api gsl_constexpr gsl_TRAILING_RETURN_TYPE_( bool ) +operator>=( not_null<T> const & l, not_null<U> const & r ) +gsl_RETURN_DECLTYPE_( !( l < r ) ) +{ + return !( l < r ); +} +template< class T, class U > +gsl_NODISCARD inline gsl_api gsl_constexpr gsl_TRAILING_RETURN_TYPE_( bool ) +operator>=( not_null<T> const & l, U const & r ) +gsl_RETURN_DECLTYPE_( !( l < r ) ) +{ + return !( l < r ); +} +template< class T, class U > +gsl_NODISCARD inline gsl_api gsl_constexpr gsl_TRAILING_RETURN_TYPE_( bool ) +operator>=( T const & l, not_null<U> const & r ) +gsl_RETURN_DECLTYPE_( !( l < r ) ) +{ + return !( l < r ); +} + +// print not_null + +template< class CharType, class Traits, class T > +std::basic_ostream< CharType, Traits > & operator<<( std::basic_ostream< CharType, Traits > & os, not_null<T> const & p ) +{ + return os << p.operator->(); +} + + +// +// Byte-specific type. +// +#if gsl_HAVE( ENUM_CLASS_CONSTRUCTION_FROM_UNDERLYING_TYPE ) + enum class gsl_may_alias byte : unsigned char {}; +#else + struct gsl_may_alias byte { typedef unsigned char type; type v; }; +#endif + +template< class T > +gsl_NODISCARD gsl_api inline gsl_constexpr byte +to_byte( T v ) gsl_noexcept +{ +#if gsl_HAVE( ENUM_CLASS_CONSTRUCTION_FROM_UNDERLYING_TYPE ) + return static_cast<byte>( v ); +#elif gsl_HAVE( CONSTEXPR_11 ) + return { static_cast<typename byte::type>( v ) }; +#else + byte b = { static_cast<typename byte::type>( v ) }; return b; +#endif +} + +template< class IntegerType gsl_ENABLE_IF_(( std::is_integral<IntegerType>::value )) > +gsl_NODISCARD gsl_api inline gsl_constexpr IntegerType +to_integer( byte b ) gsl_noexcept +{ +#if gsl_HAVE( ENUM_CLASS_CONSTRUCTION_FROM_UNDERLYING_TYPE ) + return static_cast<typename std::underlying_type<byte>::type>( b ); +#else + return b.v; +#endif +} + +gsl_NODISCARD gsl_api inline gsl_constexpr unsigned char +to_uchar( byte b ) gsl_noexcept +{ + return to_integer<unsigned char>( b ); +} + +gsl_NODISCARD gsl_api inline gsl_constexpr unsigned char +to_uchar( int i ) gsl_noexcept +{ + return static_cast<unsigned char>( i ); +} + +template< class IntegerType gsl_ENABLE_IF_(( std::is_integral<IntegerType>::value )) > +gsl_api inline gsl_constexpr14 byte & +operator<<=( byte & b, IntegerType shift ) gsl_noexcept +{ +#if gsl_HAVE( ENUM_CLASS_CONSTRUCTION_FROM_UNDERLYING_TYPE ) + return b = ::gsl::to_byte( ::gsl::to_uchar( b ) << shift ); +#else + b.v = ::gsl::to_uchar( b.v << shift ); return b; +#endif +} + +template< class IntegerType gsl_ENABLE_IF_(( std::is_integral<IntegerType>::value )) > +gsl_NODISCARD gsl_api inline gsl_constexpr byte +operator<<( byte b, IntegerType shift ) gsl_noexcept +{ + return ::gsl::to_byte( ::gsl::to_uchar( b ) << shift ); +} + +template< class IntegerType gsl_ENABLE_IF_(( std::is_integral<IntegerType>::value )) > +gsl_NODISCARD gsl_api inline gsl_constexpr14 byte & +operator>>=( byte & b, IntegerType shift ) gsl_noexcept +{ +#if gsl_HAVE( ENUM_CLASS_CONSTRUCTION_FROM_UNDERLYING_TYPE ) + return b = ::gsl::to_byte( ::gsl::to_uchar( b ) >> shift ); +#else + b.v = ::gsl::to_uchar( b.v >> shift ); return b; +#endif +} + +template< class IntegerType gsl_ENABLE_IF_(( std::is_integral<IntegerType>::value )) > +gsl_NODISCARD gsl_api inline gsl_constexpr byte +operator>>( byte b, IntegerType shift ) gsl_noexcept +{ + return ::gsl::to_byte( ::gsl::to_uchar( b ) >> shift ); +} + +#if gsl_HAVE( ENUM_CLASS_CONSTRUCTION_FROM_UNDERLYING_TYPE ) +gsl_DEFINE_ENUM_BITMASK_OPERATORS( byte ) +gsl_DEFINE_ENUM_RELATIONAL_OPERATORS( byte ) +#else // a.k.a. !gsl_HAVE( ENUM_CLASS_CONSTRUCTION_FROM_UNDERLYING_TYPE ) +gsl_api inline gsl_constexpr bool operator==( byte l, byte r ) gsl_noexcept +{ + return l.v == r.v; +} + +gsl_api inline gsl_constexpr bool operator!=( byte l, byte r ) gsl_noexcept +{ + return !( l == r ); +} + +gsl_api inline gsl_constexpr bool operator< ( byte l, byte r ) gsl_noexcept +{ + return l.v < r.v; +} + +gsl_api inline gsl_constexpr bool operator<=( byte l, byte r ) gsl_noexcept +{ + return !( r < l ); +} + +gsl_api inline gsl_constexpr bool operator> ( byte l, byte r ) gsl_noexcept +{ + return ( r < l ); +} + +gsl_api inline gsl_constexpr bool operator>=( byte l, byte r ) gsl_noexcept +{ + return !( l < r ); +} + +gsl_api inline gsl_constexpr14 byte & operator|=( byte & l, byte r ) gsl_noexcept +{ + l.v |= r.v; return l; +} + +gsl_api inline gsl_constexpr byte operator|( byte l, byte r ) gsl_noexcept +{ + return ::gsl::to_byte( l.v | r.v ); +} + +gsl_api inline gsl_constexpr14 byte & operator&=( byte & l, byte r ) gsl_noexcept +{ + l.v &= r.v; return l; +} + +gsl_api inline gsl_constexpr byte operator&( byte l, byte r ) gsl_noexcept +{ + return ::gsl::to_byte( l.v & r.v ); +} + +gsl_api inline gsl_constexpr14 byte & operator^=( byte & l, byte r ) gsl_noexcept +{ + l.v ^= r.v; return l; +} + +gsl_api inline gsl_constexpr byte operator^( byte l, byte r ) gsl_noexcept +{ + return ::gsl::to_byte( l.v ^ r.v ); +} + +gsl_api inline gsl_constexpr byte operator~( byte b ) gsl_noexcept +{ + return ::gsl::to_byte( ~b.v ); +} +#endif // gsl_HAVE( ENUM_CLASS_CONSTRUCTION_FROM_UNDERLYING_TYPE ) + +#if gsl_FEATURE_TO_STD( WITH_CONTAINER ) + +// Tag to select span constructor taking a container: + +struct with_container_t { gsl_constexpr with_container_t( ) gsl_noexcept { } }; +const gsl_constexpr with_container_t with_container; // TODO: this can lead to ODR violations because the symbol will be defined in multiple translation units + +#endif + +namespace detail { + +template< class T > +gsl_api gsl_constexpr14 T * endptr( T * data, gsl_CONFIG_SPAN_INDEX_TYPE size ) +{ + // Be sure to run the check before doing pointer arithmetics, which would be UB for `nullptr` and non-0 integers. + gsl_Expects( size == 0 || data != gsl_nullptr ); + return data + size; +} + +} // namespace detail + +// +// span<> - A 1D view of contiguous T's, replace (*,len). +// +template< class T > +class span +{ + template< class U > friend class span; + +public: + typedef gsl_CONFIG_SPAN_INDEX_TYPE index_type; + + typedef T element_type; + typedef typename std11::remove_cv< T >::type value_type; + + typedef T & reference; + typedef T * pointer; + typedef T const * const_pointer; + typedef T const & const_reference; + + typedef pointer iterator; + typedef const_pointer const_iterator; + + typedef std::reverse_iterator< iterator > reverse_iterator; + typedef std::reverse_iterator< const_iterator > const_reverse_iterator; + + typedef gsl_CONFIG_SPAN_INDEX_TYPE size_type; + typedef std::ptrdiff_t difference_type; + + // 26.7.3.2 Constructors, copy, and assignment [span.cons] + + gsl_api gsl_constexpr span() gsl_noexcept + : first_( gsl_nullptr ) + , last_ ( gsl_nullptr ) + { + } + +#if ! gsl_DEPRECATE_TO_LEVEL( 5 ) + +#if gsl_HAVE( NULLPTR ) + gsl_api gsl_constexpr14 span( std::nullptr_t, index_type size_in ) + : first_( nullptr ) + , last_ ( nullptr ) + { + gsl_Expects( size_in == 0 ); + } +#endif + +#if gsl_HAVE( IS_DELETE ) + gsl_DEPRECATED + gsl_api gsl_constexpr span( reference data_in ) + : span( &data_in, 1 ) + {} + + gsl_api gsl_constexpr span( element_type && ) = delete; +#endif + +#endif // deprecate + + gsl_api gsl_constexpr14 span( pointer data_in, index_type size_in ) + : first_( data_in ) + , last_( detail::endptr( data_in, size_in ) ) + { + } + + gsl_api gsl_constexpr14 span( pointer first_in, pointer last_in ) + : first_( first_in ) + , last_ ( last_in ) + { + gsl_Expects( first_in <= last_in ); + } + +#if ! gsl_DEPRECATE_TO_LEVEL( 5 ) + + template< class U > + gsl_api gsl_constexpr14 span( U * data_in, index_type size_in ) + : first_( data_in ) + , last_( detail::endptr( data_in, size_in ) ) + { + } + +#endif // deprecate + +#if ! gsl_DEPRECATE_TO_LEVEL( 5 ) + template< class U, size_t N > + gsl_api gsl_constexpr span( U (&arr)[N] ) gsl_noexcept + : first_( gsl_ADDRESSOF( arr[0] ) ) + , last_ ( gsl_ADDRESSOF( arr[0] ) + N ) + {} +#else + template< size_t N + gsl_ENABLE_IF_(( std::is_convertible<value_type(*)[], element_type(*)[] >::value )) + > + gsl_api gsl_constexpr span( element_type (&arr)[N] ) gsl_noexcept + : first_( gsl_ADDRESSOF( arr[0] ) ) + , last_ ( gsl_ADDRESSOF( arr[0] ) + N ) + {} +#endif // deprecate + +#if gsl_HAVE( ARRAY ) +#if ! gsl_DEPRECATE_TO_LEVEL( 5 ) + + template< class U, size_t N > + gsl_api gsl_constexpr span( std::array< U, N > & arr ) + : first_( arr.data() ) + , last_ ( arr.data() + N ) + {} + + template< class U, size_t N > + gsl_api gsl_constexpr span( std::array< U, N > const & arr ) + : first_( arr.data() ) + , last_ ( arr.data() + N ) + {} + +#else + + template< size_t N + gsl_ENABLE_IF_(( std::is_convertible<value_type(*)[], element_type(*)[] >::value )) + > + gsl_constexpr span( std::array< value_type, N > & arr ) + : first_( arr.data() ) + , last_ ( arr.data() + N ) + {} + + template< size_t N + gsl_ENABLE_IF_(( std::is_convertible<value_type(*)[], element_type(*)[] >::value )) + > + gsl_constexpr span( std::array< value_type, N > const & arr ) + : first_( arr.data() ) + , last_ ( arr.data() + N ) + {} + +#endif // deprecate +#endif // gsl_HAVE( ARRAY ) + +#if gsl_HAVE( CONSTRAINED_SPAN_CONTAINER_CTOR ) + template< class Container + gsl_ENABLE_IF_(( detail::is_compatible_container< Container, element_type >::value )) + > + gsl_api gsl_constexpr span( Container & cont ) gsl_noexcept + : first_( std17::data( cont ) ) + , last_ ( std17::data( cont ) + std17::size( cont ) ) + {} + + template< class Container + gsl_ENABLE_IF_(( + std::is_const< element_type >::value + && detail::is_compatible_container< Container, element_type >::value + )) + > + gsl_api gsl_constexpr span( Container const & cont ) gsl_noexcept + : first_( std17::data( cont ) ) + , last_ ( std17::data( cont ) + std17::size( cont ) ) + {} + +#elif gsl_HAVE( UNCONSTRAINED_SPAN_CONTAINER_CTOR ) + + template< class Container > + gsl_constexpr span( Container & cont ) + : first_( cont.size() == 0 ? gsl_nullptr : gsl_ADDRESSOF( cont[0] ) ) + , last_ ( cont.size() == 0 ? gsl_nullptr : gsl_ADDRESSOF( cont[0] ) + cont.size() ) + {} + + template< class Container > + gsl_constexpr span( Container const & cont ) + : first_( cont.size() == 0 ? gsl_nullptr : gsl_ADDRESSOF( cont[0] ) ) + , last_ ( cont.size() == 0 ? gsl_nullptr : gsl_ADDRESSOF( cont[0] ) + cont.size() ) + {} + +#endif + +#if gsl_FEATURE_TO_STD( WITH_CONTAINER ) + + template< class Container > + gsl_constexpr span( with_container_t, Container & cont ) gsl_noexcept + : first_( cont.size() == 0 ? gsl_nullptr : gsl_ADDRESSOF( cont[0] ) ) + , last_ ( cont.size() == 0 ? gsl_nullptr : gsl_ADDRESSOF( cont[0] ) + cont.size() ) + {} + + template< class Container > + gsl_constexpr span( with_container_t, Container const & cont ) gsl_noexcept + : first_( cont.size() == 0 ? gsl_nullptr : gsl_ADDRESSOF( cont[0] ) ) + , last_ ( cont.size() == 0 ? gsl_nullptr : gsl_ADDRESSOF( cont[0] ) + cont.size() ) + {} + +#endif + +#if !gsl_DEPRECATE_TO_LEVEL( 4 ) + // constructor taking shared_ptr deprecated since 0.29.0 + +# if gsl_HAVE( SHARED_PTR ) + gsl_DEPRECATED + gsl_constexpr span( shared_ptr<element_type> const & ptr ) + : first_( ptr.get() ) + , last_ ( ptr.get() ? ptr.get() + 1 : gsl_nullptr ) + {} +# endif + + // constructors taking unique_ptr deprecated since 0.29.0 + +# if gsl_HAVE( UNIQUE_PTR ) +# if gsl_HAVE( DEFAULT_FUNCTION_TEMPLATE_ARG ) + template< class ArrayElementType = typename std::add_pointer<element_type>::type > +# else + template< class ArrayElementType > +# endif + gsl_DEPRECATED + gsl_constexpr span( unique_ptr<ArrayElementType> const & ptr, index_type count ) + : first_( ptr.get() ) + , last_ ( ptr.get() + count ) + {} + + gsl_DEPRECATED + gsl_constexpr span( unique_ptr<element_type> const & ptr ) + : first_( ptr.get() ) + , last_ ( ptr.get() ? ptr.get() + 1 : gsl_nullptr ) + {} +# endif + +#endif // deprecate shared_ptr, unique_ptr + +#if gsl_HAVE( IS_DEFAULT ) && ! gsl_BETWEEN( gsl_COMPILER_GNUC_VERSION, 430, 600) + gsl_constexpr span( span && ) gsl_noexcept = default; + gsl_constexpr span( span const & ) = default; +#else + gsl_api gsl_constexpr span( span const & other ) + : first_( other.begin() ) + , last_ ( other.end() ) + {} +#endif + +#if gsl_HAVE( IS_DEFAULT ) + gsl_constexpr14 span & operator=( span && ) gsl_noexcept = default; + gsl_constexpr14 span & operator=( span const & ) gsl_noexcept = default; +#else + gsl_constexpr14 span & operator=( span other ) gsl_noexcept + { + first_ = other.first_; + last_ = other.last_; + return *this; + } +#endif + + template< class U + gsl_ENABLE_IF_(( std::is_convertible<U(*)[], element_type(*)[]>::value )) + > + gsl_api gsl_constexpr span( span<U> const & other ) + : first_( other.begin() ) + , last_ ( other.end() ) + {} + +#if 0 + // Converting from other span ? + template< class U > operator=(); +#endif + + // 26.7.3.3 Subviews [span.sub] + + gsl_NODISCARD gsl_api gsl_constexpr14 span + first( index_type count ) const + { + gsl_Expects( std::size_t( count ) <= std::size_t( this->size() ) ); + return span( this->data(), count ); + } + + gsl_NODISCARD gsl_api gsl_constexpr14 span + last( index_type count ) const + { + gsl_Expects( std::size_t( count ) <= std::size_t( this->size() ) ); + return span( this->data() + this->size() - count, count ); + } + + gsl_NODISCARD gsl_api gsl_constexpr14 span + subspan( index_type offset ) const + { + gsl_Expects( std::size_t( offset ) <= std::size_t( this->size() ) ); + return span( this->data() + offset, this->size() - offset ); + } + + gsl_NODISCARD gsl_api gsl_constexpr14 span + subspan( index_type offset, index_type count ) const + { + gsl_Expects( + std::size_t( offset ) <= std::size_t( this->size() ) && + std::size_t( count ) <= std::size_t( this->size() - offset ) ); + return span( this->data() + offset, count ); + } + + // 26.7.3.4 Observers [span.obs] + + gsl_NODISCARD gsl_api gsl_constexpr index_type + size() const gsl_noexcept + { + return narrow_cast<index_type>( last_ - first_ ); + } + + gsl_NODISCARD gsl_api gsl_constexpr std::ptrdiff_t + ssize() const gsl_noexcept + { + return narrow_cast<std::ptrdiff_t>( last_ - first_ ); + } + + gsl_NODISCARD gsl_api gsl_constexpr index_type + size_bytes() const gsl_noexcept + { + return size() * narrow_cast<index_type>( sizeof( element_type ) ); + } + + gsl_NODISCARD gsl_api gsl_constexpr bool + empty() const gsl_noexcept + { + return size() == 0; + } + + // 26.7.3.5 Element access [span.elem] + + gsl_NODISCARD gsl_api gsl_constexpr14 reference + operator[]( index_type pos ) const + { + gsl_Expects( pos < size() ); + return first_[ pos ]; + } + +#if ! gsl_DEPRECATE_TO_LEVEL( 6 ) + gsl_DEPRECATED_MSG("use subscript indexing instead") + gsl_api gsl_constexpr14 reference + operator()( index_type pos ) const + { + return (*this)[ pos ]; + } + + gsl_DEPRECATED_MSG("use subscript indexing instead") + gsl_api gsl_constexpr14 reference + at( index_type pos ) const + { + return (*this)[ pos ]; + } +#endif // deprecate + + gsl_NODISCARD gsl_api gsl_constexpr14 reference + front() const + { + gsl_Expects( first_ != last_ ); + return *first_; + } + + gsl_NODISCARD gsl_api gsl_constexpr14 reference + back() const + { + gsl_Expects( first_ != last_ ); + return *(last_ - 1); + } + + gsl_NODISCARD gsl_api gsl_constexpr pointer + data() const gsl_noexcept + { + return first_; + } + + // 26.7.3.6 Iterator support [span.iterators] + + gsl_NODISCARD gsl_api gsl_constexpr iterator + begin() const gsl_noexcept + { + return iterator( first_ ); + } + + gsl_NODISCARD gsl_api gsl_constexpr iterator + end() const gsl_noexcept + { + return iterator( last_ ); + } + + gsl_NODISCARD gsl_api gsl_constexpr const_iterator + cbegin() const gsl_noexcept + { +#if gsl_CPP11_OR_GREATER + return { begin() }; +#else + return const_iterator( begin() ); +#endif + } + + gsl_NODISCARD gsl_api gsl_constexpr const_iterator + cend() const gsl_noexcept + { +#if gsl_CPP11_OR_GREATER + return { end() }; +#else + return const_iterator( end() ); +#endif + } + + gsl_NODISCARD gsl_constexpr17 reverse_iterator + rbegin() const gsl_noexcept + { + return reverse_iterator( end() ); + } + + gsl_NODISCARD gsl_constexpr17 reverse_iterator + rend() const gsl_noexcept + { + return reverse_iterator( begin() ); + } + + gsl_NODISCARD gsl_constexpr17 const_reverse_iterator + crbegin() const gsl_noexcept + { + return const_reverse_iterator( cend() ); + } + + gsl_NODISCARD gsl_constexpr17 const_reverse_iterator + crend() const gsl_noexcept + { + return const_reverse_iterator( cbegin() ); + } + + gsl_constexpr14 void swap( span & other ) gsl_noexcept + { + std::swap( first_, other.first_ ); + std::swap( last_ , other.last_ ); + } + +#if ! gsl_DEPRECATE_TO_LEVEL( 3 ) + // member length() deprecated since 0.29.0 + + gsl_DEPRECATED_MSG("use size() instead") + gsl_api gsl_constexpr index_type length() const gsl_noexcept + { + return size(); + } + + // member length_bytes() deprecated since 0.29.0 + + gsl_DEPRECATED_MSG("use size_bytes() instead") + gsl_api gsl_constexpr index_type length_bytes() const gsl_noexcept + { + return size_bytes(); + } +#endif + +#if ! gsl_DEPRECATE_TO_LEVEL( 2 ) + // member as_bytes(), as_writeable_bytes deprecated since 0.17.0 + + gsl_DEPRECATED_MSG("use free function gsl::as_bytes() instead") + gsl_api span< const byte > as_bytes() const gsl_noexcept + { + return span< const byte >( reinterpret_cast<const byte *>( data() ), size_bytes() ); // NOLINT + } + + gsl_DEPRECATED_MSG("use free function gsl::as_writable_bytes() instead") + gsl_api span< byte > as_writeable_bytes() const gsl_noexcept + { + return span< byte >( reinterpret_cast<byte *>( data() ), size_bytes() ); // NOLINT + } + +#endif + + template< class U > + gsl_NODISCARD gsl_api span< U > + as_span() const + { + gsl_Expects( ( this->size_bytes() % sizeof(U) ) == 0 ); + return span< U >( reinterpret_cast<U *>( this->data() ), this->size_bytes() / sizeof( U ) ); // NOLINT + } + +private: + pointer first_; + pointer last_; +}; + +// class template argument deduction guides: + +#if gsl_HAVE( DEDUCTION_GUIDES ) // gsl_CPP17_OR_GREATER + +template< class T, size_t N > +span( T (&)[N] ) -> span<T /*, N*/>; + +template< class T, size_t N > +span( std::array<T, N> & ) -> span<T /*, N*/>; + +template< class T, size_t N > +span( std::array<T, N> const & ) -> span<const T /*, N*/>; + +template< class Container > +span( Container& ) -> span<typename Container::value_type>; + +template< class Container > +span( Container const & ) -> span<const typename Container::value_type>; + +#endif // gsl_HAVE( DEDUCTION_GUIDES ) + +// 26.7.3.7 Comparison operators [span.comparison] + +#if gsl_CONFIG( ALLOWS_SPAN_COMPARISON ) +# if gsl_CONFIG( ALLOWS_NONSTRICT_SPAN_COMPARISON ) + +template< class T, class U > +gsl_SUPPRESS_MSGSL_WARNING(stl.1) +gsl_NODISCARD inline gsl_constexpr bool operator==( span<T> const & l, span<U> const & r ) +{ + return l.size() == r.size() + && (l.begin() == r.begin() || std98::equal( l.begin(), l.end(), r.begin() ) ); +} + +template< class T, class U > +gsl_SUPPRESS_MSGSL_WARNING(stl.1) +gsl_NODISCARD inline gsl_constexpr bool operator< ( span<T> const & l, span<U> const & r ) +{ + return std98::lexicographical_compare( l.begin(), l.end(), r.begin(), r.end() ); +} + +# else // a.k.a. !gsl_CONFIG( ALLOWS_NONSTRICT_SPAN_COMPARISON ) + +template< class T > +gsl_SUPPRESS_MSGSL_WARNING(stl.1) +gsl_NODISCARD inline gsl_constexpr bool operator==( span<T> const & l, span<T> const & r ) +{ + return l.size() == r.size() + && (l.begin() == r.begin() || std98::equal( l.begin(), l.end(), r.begin() ) ); +} + +template< class T > +gsl_SUPPRESS_MSGSL_WARNING(stl.1) +gsl_NODISCARD inline gsl_constexpr bool operator< ( span<T> const & l, span<T> const & r ) +{ + return std98::lexicographical_compare( l.begin(), l.end(), r.begin(), r.end() ); +} +# endif // gsl_CONFIG( ALLOWS_NONSTRICT_SPAN_COMPARISON ) + +template< class T, class U > +gsl_NODISCARD inline gsl_constexpr bool operator!=( span<T> const & l, span<U> const & r ) +{ + return !( l == r ); +} + +template< class T, class U > +gsl_NODISCARD inline gsl_constexpr bool operator<=( span<T> const & l, span<U> const & r ) +{ + return !( r < l ); +} + +template< class T, class U > +gsl_NODISCARD inline gsl_constexpr bool operator> ( span<T> const & l, span<U> const & r ) +{ + return ( r < l ); +} + +template< class T, class U > +gsl_NODISCARD inline gsl_constexpr bool operator>=( span<T> const & l, span<U> const & r ) +{ + return !( l < r ); +} +#endif // gsl_CONFIG( ALLOWS_SPAN_COMPARISON ) + +// span algorithms + +template< class T > +gsl_NODISCARD gsl_api inline gsl_constexpr std::size_t +size( span<T> const & spn ) +{ + return static_cast<std::size_t>( spn.size() ); +} + +template< class T > +gsl_NODISCARD gsl_api inline gsl_constexpr std::ptrdiff_t +ssize( span<T> const & spn ) +{ + return spn.ssize(); +} + +namespace detail { + +template< class II, class N, class OI > +gsl_api gsl_constexpr14 inline OI copy_n( II first, N count, OI result ) +{ + if ( count > 0 ) + { + *result++ = *first; + for ( N i = 1; i < count; ++i ) + { + *result++ = *++first; + } + } + return result; +} +} + +template< class T, class U > +gsl_api gsl_constexpr14 inline void copy( span<T> src, span<U> dest ) +{ +#if gsl_CPP14_OR_GREATER // gsl_HAVE( TYPE_TRAITS ) (circumvent Travis clang 3.4) + static_assert( std::is_assignable<U &, T const &>::value, "Cannot assign elements of source span to elements of destination span" ); +#endif + gsl_Expects( dest.size() >= src.size() ); + detail::copy_n( src.data(), src.size(), dest.data() ); +} + +// span creator functions (see ctors) + +template< class T > +gsl_NODISCARD gsl_api inline span< const byte > +as_bytes( span<T> spn ) gsl_noexcept +{ + return span< const byte >( reinterpret_cast<const byte *>( spn.data() ), spn.size_bytes() ); // NOLINT +} + +template< class T> +gsl_NODISCARD gsl_api inline span< byte > +as_writable_bytes( span<T> spn ) gsl_noexcept +{ + return span< byte >( reinterpret_cast<byte *>( spn.data() ), spn.size_bytes() ); // NOLINT +} + +#if ! gsl_DEPRECATE_TO_LEVEL( 6 ) +template< class T> +gsl_DEPRECATED_MSG("use as_writable_bytes() (different spelling) instead") +gsl_api inline span< byte > as_writeable_bytes( span<T> spn ) gsl_noexcept +{ + return span< byte >( reinterpret_cast<byte *>( spn.data() ), spn.size_bytes() ); // NOLINT +} +#endif // deprecate + +#if gsl_FEATURE_TO_STD( MAKE_SPAN ) + +template< class T > +gsl_NODISCARD gsl_api inline gsl_constexpr span<T> +make_span( T * ptr, typename span<T>::index_type count ) +{ + return span<T>( ptr, count ); +} + +template< class T > +gsl_NODISCARD gsl_api inline gsl_constexpr span<T> +make_span( T * first, T * last ) +{ + return span<T>( first, last ); +} + +template< class T, size_t N > +gsl_NODISCARD inline gsl_constexpr span<T> +make_span( T (&arr)[N] ) +{ + return span<T>( gsl_ADDRESSOF( arr[0] ), N ); +} + +#if gsl_HAVE( ARRAY ) + +template< class T, size_t N > +gsl_NODISCARD inline gsl_constexpr span<T> +make_span( std::array<T,N> & arr ) +{ + return span<T>( arr ); +} + +template< class T, size_t N > +gsl_NODISCARD inline gsl_constexpr span<const T> +make_span( std::array<T,N> const & arr ) +{ + return span<const T>( arr ); +} +#endif + +#if gsl_HAVE( CONSTRAINED_SPAN_CONTAINER_CTOR ) && gsl_HAVE( AUTO ) + +template< class Container, class EP = decltype( std17::data(std::declval<Container&>())) > +gsl_NODISCARD inline gsl_constexpr auto +make_span( Container & cont ) -> span< typename std::remove_pointer<EP>::type > +{ + return span< typename std::remove_pointer<EP>::type >( cont ); +} + +template< class Container, class EP = decltype( std17::data(std::declval<Container&>())) > +gsl_NODISCARD inline gsl_constexpr auto +make_span( Container const & cont ) -> span< const typename std::remove_pointer<EP>::type > +{ + return span< const typename std::remove_pointer<EP>::type >( cont ); +} + +#else + +template< class T > +inline span<T> +make_span( std::vector<T> & cont ) +{ + return span<T>( with_container, cont ); +} + +template< class T > +inline span<const T> +make_span( std::vector<T> const & cont ) +{ + return span<const T>( with_container, cont ); +} +#endif + +#if gsl_FEATURE_TO_STD( WITH_CONTAINER ) + +template< class Container > +gsl_NODISCARD inline gsl_constexpr span<typename Container::value_type> +make_span( with_container_t, Container & cont ) gsl_noexcept +{ + return span< typename Container::value_type >( with_container, cont ); +} + +template< class Container > +gsl_NODISCARD inline gsl_constexpr span<const typename Container::value_type> +make_span( with_container_t, Container const & cont ) gsl_noexcept +{ + return span< const typename Container::value_type >( with_container, cont ); +} + +#endif // gsl_FEATURE_TO_STD( WITH_CONTAINER ) + +#if !gsl_DEPRECATE_TO_LEVEL( 4 ) +template< class Ptr > +gsl_DEPRECATED +inline span<typename Ptr::element_type> +make_span( Ptr & ptr ) +{ + return span<typename Ptr::element_type>( ptr ); +} +#endif // !gsl_DEPRECATE_TO_LEVEL( 4 ) + +template< class Ptr > +gsl_DEPRECATED +inline span<typename Ptr::element_type> +make_span( Ptr & ptr, typename span<typename Ptr::element_type>::index_type count ) +{ + return span<typename Ptr::element_type>( ptr, count ); +} + +#endif // gsl_FEATURE_TO_STD( MAKE_SPAN ) + +#if gsl_FEATURE_TO_STD( BYTE_SPAN ) + +template< class T > +gsl_NODISCARD gsl_api inline gsl_constexpr span<byte> +byte_span( T & t ) gsl_noexcept +{ + return span<byte>( reinterpret_cast<byte *>( &t ), sizeof(T) ); +} + +template< class T > +gsl_NODISCARD gsl_api inline gsl_constexpr span<const byte> +byte_span( T const & t ) gsl_noexcept +{ + return span<const byte>( reinterpret_cast<byte const *>( &t ), sizeof(T) ); +} + +#endif // gsl_FEATURE_TO_STD( BYTE_SPAN ) + +// +// basic_string_span: +// + +template< class T > +class basic_string_span; + +namespace detail { + +template< class T > +struct is_basic_string_span_oracle : std11::false_type {}; + +template< class T > +struct is_basic_string_span_oracle< basic_string_span<T> > : std11::true_type {}; + +template< class T > +struct is_basic_string_span : is_basic_string_span_oracle< typename std11::remove_cv<T>::type > {}; + +template< class T > +gsl_api inline gsl_constexpr14 std::size_t string_length( T * ptr, std::size_t max ) +{ + if ( ptr == gsl_nullptr || max <= 0 ) + return 0; + + std::size_t len = 0; + while ( len < max && ptr[len] ) // NOLINT + ++len; + + return len; +} + +} // namespace detail + +// +// basic_string_span<> - A view of contiguous characters, replace (*,len). +// +template< class T > +class basic_string_span +{ +public: + typedef T element_type; + typedef span<T> span_type; + + typedef typename span_type::size_type size_type; + typedef typename span_type::index_type index_type; + typedef typename span_type::difference_type difference_type; + + typedef typename span_type::pointer pointer ; + typedef typename span_type::reference reference ; + + typedef typename span_type::iterator iterator ; + typedef typename span_type::const_iterator const_iterator ; + typedef typename span_type::reverse_iterator reverse_iterator; + typedef typename span_type::const_reverse_iterator const_reverse_iterator; + + // construction: + +#if gsl_HAVE( IS_DEFAULT ) + gsl_constexpr basic_string_span() gsl_noexcept = default; +#else + gsl_api gsl_constexpr basic_string_span() gsl_noexcept {} +#endif + +#if gsl_HAVE( NULLPTR ) + gsl_api gsl_constexpr basic_string_span( std::nullptr_t ) gsl_noexcept + : span_( nullptr, static_cast<index_type>( 0 ) ) + {} +#endif + +#ifdef __CUDACC_RELAXED_CONSTEXPR__ + gsl_api +#endif // __CUDACC_RELAXED_CONSTEXPR__ + gsl_constexpr basic_string_span( pointer ptr ) + : span_( remove_z( ptr, (std::numeric_limits<index_type>::max)() ) ) + {} + + gsl_api gsl_constexpr basic_string_span( pointer ptr, index_type count ) + : span_( ptr, count ) + {} + + gsl_api gsl_constexpr basic_string_span( pointer firstElem, pointer lastElem ) + : span_( firstElem, lastElem ) + {} + + template< std::size_t N > + gsl_constexpr basic_string_span( element_type (&arr)[N] ) + : span_( remove_z( gsl_ADDRESSOF( arr[0] ), N ) ) + {} + +#if gsl_HAVE( ARRAY ) + + template< std::size_t N > + gsl_constexpr basic_string_span( std::array< typename std11::remove_const<element_type>::type, N> & arr ) + : span_( remove_z( arr ) ) + {} + + template< std::size_t N > + gsl_constexpr basic_string_span( std::array< typename std11::remove_const<element_type>::type, N> const & arr ) + : span_( remove_z( arr ) ) + {} + +#endif + +#if gsl_HAVE( CONSTRAINED_SPAN_CONTAINER_CTOR ) + + // Exclude: array, [basic_string,] basic_string_span + + template< class Container + gsl_ENABLE_IF_(( + ! detail::is_std_array< Container >::value + && ! detail::is_basic_string_span< Container >::value + && std::is_convertible< typename Container::pointer, pointer >::value + && std::is_convertible< typename Container::pointer, decltype(std::declval<Container>().data()) >::value + )) + > + gsl_constexpr basic_string_span( Container & cont ) + : span_( ( cont ) ) + {} + + // Exclude: array, [basic_string,] basic_string_span + + template< class Container + gsl_ENABLE_IF_(( + ! detail::is_std_array< Container >::value + && ! detail::is_basic_string_span< Container >::value + && std::is_convertible< typename Container::pointer, pointer >::value + && std::is_convertible< typename Container::pointer, decltype(std::declval<Container const &>().data()) >::value + )) + > + gsl_constexpr basic_string_span( Container const & cont ) + : span_( ( cont ) ) + {} + +#elif gsl_HAVE( UNCONSTRAINED_SPAN_CONTAINER_CTOR ) + + template< class Container > + gsl_constexpr basic_string_span( Container & cont ) + : span_( cont ) + {} + + template< class Container > + gsl_constexpr basic_string_span( Container const & cont ) + : span_( cont ) + {} + +#else + + template< class U > + gsl_api gsl_constexpr basic_string_span( span<U> const & rhs ) + : span_( rhs ) + {} + +#endif + +#if gsl_FEATURE_TO_STD( WITH_CONTAINER ) + + template< class Container > + gsl_constexpr basic_string_span( with_container_t, Container & cont ) + : span_( with_container, cont ) + {} +#endif + +#if gsl_HAVE( IS_DEFAULT ) +# if gsl_BETWEEN( gsl_COMPILER_GNUC_VERSION, 440, 600 ) + gsl_constexpr basic_string_span( basic_string_span const & ) = default; + + gsl_constexpr basic_string_span( basic_string_span && ) = default; +# else + gsl_constexpr basic_string_span( basic_string_span const & ) gsl_noexcept = default; + + gsl_constexpr basic_string_span( basic_string_span && ) gsl_noexcept = default; +# endif +#endif + + template< class U + gsl_ENABLE_IF_(( std::is_convertible<typename basic_string_span<U>::pointer, pointer>::value )) + > + gsl_api gsl_constexpr basic_string_span( basic_string_span<U> const & rhs ) + : span_( reinterpret_cast<pointer>( rhs.data() ), rhs.length() ) // NOLINT + {} + +#if gsl_STDLIB_CPP11_120 + template< class U + gsl_ENABLE_IF_(( std::is_convertible<typename basic_string_span<U>::pointer, pointer>::value )) + > + gsl_api gsl_constexpr basic_string_span( basic_string_span<U> && rhs ) + : span_( reinterpret_cast<pointer>( rhs.data() ), rhs.length() ) // NOLINT + {} +#endif // gsl_STDLIB_CPP11_120 + + template< class CharTraits, class Allocator > + gsl_constexpr basic_string_span( + std::basic_string< typename std11::remove_const<element_type>::type, CharTraits, Allocator > & str ) + : span_( gsl_ADDRESSOF( str[0] ), str.length() ) + {} + + template< class CharTraits, class Allocator > + gsl_constexpr basic_string_span( + std::basic_string< typename std11::remove_const<element_type>::type, CharTraits, Allocator > const & str ) + : span_( gsl_ADDRESSOF( str[0] ), str.length() ) + {} + + // assignment: + +#if gsl_HAVE( IS_DEFAULT ) + gsl_constexpr14 basic_string_span & operator=( basic_string_span const & ) gsl_noexcept = default; + + gsl_constexpr14 basic_string_span & operator=( basic_string_span && ) gsl_noexcept = default; +#endif + + // sub span: + + /*gsl_api*/ // currently disabled due to an apparent NVCC bug + gsl_NODISCARD gsl_constexpr14 basic_string_span + first( index_type count ) const + { + return span_.first( count ); + } + + /*gsl_api*/ // currently disabled due to an apparent NVCC bug + gsl_NODISCARD gsl_constexpr14 basic_string_span + last( index_type count ) const + { + return span_.last( count ); + } + + /*gsl_api*/ // currently disabled due to an apparent NVCC bug + gsl_NODISCARD gsl_constexpr14 basic_string_span + subspan( index_type offset ) const + { + return span_.subspan( offset ); + } + + /*gsl_api*/ // currently disabled due to an apparent NVCC bug + gsl_NODISCARD gsl_constexpr14 basic_string_span + subspan( index_type offset, index_type count ) const + { + return span_.subspan( offset, count ); + } + + // observers: + + gsl_NODISCARD gsl_api gsl_constexpr index_type + length() const gsl_noexcept + { + return span_.size(); + } + + gsl_NODISCARD gsl_api gsl_constexpr index_type + size() const gsl_noexcept + { + return span_.size(); + } + + gsl_NODISCARD gsl_api gsl_constexpr index_type + length_bytes() const gsl_noexcept + { + return span_.size_bytes(); + } + + gsl_NODISCARD gsl_api gsl_constexpr index_type + size_bytes() const gsl_noexcept + { + return span_.size_bytes(); + } + + gsl_NODISCARD gsl_api gsl_constexpr bool + empty() const gsl_noexcept + { + return size() == 0; + } + + gsl_NODISCARD gsl_api gsl_constexpr14 reference + operator[]( index_type idx ) const + { + return span_[idx]; + } + +#if ! gsl_DEPRECATE_TO_LEVEL( 6 ) + gsl_DEPRECATED_MSG("use subscript indexing instead") + gsl_api gsl_constexpr14 reference operator()( index_type idx ) const + { + return span_[idx]; + } +#endif // deprecate + + gsl_NODISCARD gsl_api gsl_constexpr14 reference + front() const + { + return span_.front(); + } + + gsl_NODISCARD gsl_api gsl_constexpr14 reference + back() const + { + return span_.back(); + } + + gsl_NODISCARD gsl_api gsl_constexpr pointer + data() const gsl_noexcept + { + return span_.data(); + } + + gsl_NODISCARD gsl_api gsl_constexpr iterator + begin() const gsl_noexcept + { + return span_.begin(); + } + + gsl_NODISCARD gsl_api gsl_constexpr iterator + end() const gsl_noexcept + { + return span_.end(); + } + + gsl_NODISCARD gsl_constexpr17 reverse_iterator + rbegin() const gsl_noexcept + { + return span_.rbegin(); + } + + gsl_NODISCARD gsl_constexpr17 reverse_iterator + rend() const gsl_noexcept + { + return span_.rend(); + } + + // const version not in p0123r2: + + gsl_NODISCARD gsl_api gsl_constexpr const_iterator + cbegin() const gsl_noexcept + { + return span_.cbegin(); + } + + gsl_NODISCARD gsl_api gsl_constexpr const_iterator + cend() const gsl_noexcept + { + return span_.cend(); + } + + gsl_NODISCARD gsl_constexpr17 const_reverse_iterator + crbegin() const gsl_noexcept + { + return span_.crbegin(); + } + + gsl_NODISCARD gsl_constexpr17 const_reverse_iterator + crend() const gsl_noexcept + { + return span_.crend(); + } + +private: + gsl_api static gsl_constexpr14 span_type remove_z( pointer sz, std::size_t max ) + { + return span_type( sz, detail::string_length( sz, max ) ); + } + +#if gsl_HAVE( ARRAY ) + template< size_t N > + gsl_NODISCARD static gsl_constexpr14 span_type + remove_z( std::array<typename std11::remove_const<element_type>::type, N> & arr ) + { + return remove_z( gsl_ADDRESSOF( arr[0] ), narrow_cast< std::size_t >( N ) ); + } + + template< size_t N > + gsl_NODISCARD static gsl_constexpr14 span_type + remove_z( std::array<typename std11::remove_const<element_type>::type, N> const & arr ) + { + return remove_z( gsl_ADDRESSOF( arr[0] ), narrow_cast< std::size_t >( N ) ); + } +#endif + +private: + span_type span_; +}; + +// basic_string_span comparison functions: + +#if gsl_CONFIG( ALLOWS_NONSTRICT_SPAN_COMPARISON ) + +template< class T, class U > +gsl_SUPPRESS_MSGSL_WARNING(stl.1) +gsl_NODISCARD inline gsl_constexpr14 bool +operator==( basic_string_span<T> const & l, U const & u ) gsl_noexcept +{ + const basic_string_span< typename std11::add_const<T>::type > r( u ); + + return l.size() == r.size() + && std98::equal( l.begin(), l.end(), r.begin() ); +} + +template< class T, class U > +gsl_SUPPRESS_MSGSL_WARNING(stl.1) +gsl_NODISCARD inline gsl_constexpr14 bool +operator<( basic_string_span<T> const & l, U const & u ) gsl_noexcept +{ + const basic_string_span< typename std11::add_const<T>::type > r( u ); + + return std98::lexicographical_compare( l.begin(), l.end(), r.begin(), r.end() ); +} + +#if gsl_HAVE( DEFAULT_FUNCTION_TEMPLATE_ARG ) + +template< class T, class U + gsl_ENABLE_IF_(( !detail::is_basic_string_span<U>::value )) +> +gsl_SUPPRESS_MSGSL_WARNING(stl.1) +gsl_NODISCARD inline gsl_constexpr14 bool +operator==( U const & u, basic_string_span<T> const & r ) gsl_noexcept +{ + const basic_string_span< typename std11::add_const<T>::type > l( u ); + + return l.size() == r.size() + && std98::equal( l.begin(), l.end(), r.begin() ); +} + +template< class T, class U + gsl_ENABLE_IF_(( !detail::is_basic_string_span<U>::value )) +> +gsl_SUPPRESS_MSGSL_WARNING(stl.1) +gsl_NODISCARD inline gsl_constexpr14 bool +operator<( U const & u, basic_string_span<T> const & r ) gsl_noexcept +{ + const basic_string_span< typename std11::add_const<T>::type > l( u ); + + return std98::lexicographical_compare( l.begin(), l.end(), r.begin(), r.end() ); +} +#endif + +#else //gsl_CONFIG( ALLOWS_NONSTRICT_SPAN_COMPARISON ) + +template< class T > +gsl_SUPPRESS_MSGSL_WARNING(stl.1) +gsl_NODISCARD inline gsl_constexpr14 bool +operator==( basic_string_span<T> const & l, basic_string_span<T> const & r ) gsl_noexcept +{ + return l.size() == r.size() + && std98::equal( l.begin(), l.end(), r.begin() ); +} + +template< class T > +gsl_SUPPRESS_MSGSL_WARNING(stl.1) +gsl_NODISCARD inline gsl_constexpr14 bool +operator<( basic_string_span<T> const & l, basic_string_span<T> const & r ) gsl_noexcept +{ + return std98::lexicographical_compare( l.begin(), l.end(), r.begin(), r.end() ); +} + +#endif // gsl_CONFIG( ALLOWS_NONSTRICT_SPAN_COMPARISON ) + +template< class T, class U > +gsl_NODISCARD inline gsl_constexpr14 bool +operator!=( basic_string_span<T> const & l, U const & r ) gsl_noexcept +{ + return !( l == r ); +} + +template< class T, class U > +gsl_NODISCARD inline gsl_constexpr14 bool +operator<=( basic_string_span<T> const & l, U const & r ) gsl_noexcept +{ +#if gsl_HAVE( DEFAULT_FUNCTION_TEMPLATE_ARG ) || ! gsl_CONFIG( ALLOWS_NONSTRICT_SPAN_COMPARISON ) + return !( r < l ); +#else + basic_string_span< typename std11::add_const<T>::type > rr( r ); + return !( rr < l ); +#endif +} + +template< class T, class U > +gsl_NODISCARD inline gsl_constexpr14 bool +operator>( basic_string_span<T> const & l, U const & r ) gsl_noexcept +{ +#if gsl_HAVE( DEFAULT_FUNCTION_TEMPLATE_ARG ) || ! gsl_CONFIG( ALLOWS_NONSTRICT_SPAN_COMPARISON ) + return ( r < l ); +#else + basic_string_span< typename std11::add_const<T>::type > rr( r ); + return ( rr < l ); +#endif +} + +template< class T, class U > +gsl_NODISCARD inline gsl_constexpr14 bool +operator>=( basic_string_span<T> const & l, U const & r ) gsl_noexcept +{ + return !( l < r ); +} + +#if gsl_HAVE( DEFAULT_FUNCTION_TEMPLATE_ARG ) + +template< class T, class U + gsl_ENABLE_IF_(( !detail::is_basic_string_span<U>::value )) +> +gsl_NODISCARD inline gsl_constexpr14 bool +operator!=( U const & l, basic_string_span<T> const & r ) gsl_noexcept +{ + return !( l == r ); +} + +template< class T, class U + gsl_ENABLE_IF_(( !detail::is_basic_string_span<U>::value )) +> +gsl_NODISCARD inline gsl_constexpr14 bool +operator<=( U const & l, basic_string_span<T> const & r ) gsl_noexcept +{ + return !( r < l ); +} + +template< class T, class U + gsl_ENABLE_IF_(( !detail::is_basic_string_span<U>::value )) +> +gsl_NODISCARD inline gsl_constexpr14 bool +operator>( U const & l, basic_string_span<T> const & r ) gsl_noexcept +{ + return ( r < l ); +} + +template< class T, class U + gsl_ENABLE_IF_(( !detail::is_basic_string_span<U>::value )) +> +gsl_NODISCARD inline gsl_constexpr14 bool +operator>=( U const & l, basic_string_span<T> const & r ) gsl_noexcept +{ + return !( l < r ); +} + +#endif // gsl_HAVE( DEFAULT_FUNCTION_TEMPLATE_ARG ) + +// convert basic_string_span to byte span: + +template< class T > +gsl_NODISCARD gsl_api inline span< const byte > +as_bytes( basic_string_span<T> spn ) gsl_noexcept +{ + return span< const byte >( reinterpret_cast<const byte *>( spn.data() ), spn.size_bytes() ); // NOLINT +} + +// +// String types: +// + +typedef char * zstring; +typedef const char * czstring; + +#if gsl_HAVE( WCHAR ) +typedef wchar_t * wzstring; +typedef const wchar_t * cwzstring; +#endif + +typedef basic_string_span< char > string_span; +typedef basic_string_span< char const > cstring_span; + +#if gsl_HAVE( WCHAR ) +typedef basic_string_span< wchar_t > wstring_span; +typedef basic_string_span< wchar_t const > cwstring_span; +#endif + +// to_string() allow (explicit) conversions from string_span to string + +#if 0 + +template< class T > +inline std::basic_string< typename std::remove_const<T>::type > to_string( basic_string_span<T> spn ) +{ + std::string( spn.data(), spn.length() ); +} + +#else + +gsl_NODISCARD inline std::string +to_string( string_span const & spn ) +{ + return std::string( spn.data(), static_cast<std::size_t>( spn.length() ) ); +} + +gsl_NODISCARD inline std::string +to_string( cstring_span const & spn ) +{ + return std::string( spn.data(), static_cast<std::size_t>( spn.length() ) ); +} + +#if gsl_HAVE( WCHAR ) + +gsl_NODISCARD inline std::wstring +to_string( wstring_span const & spn ) +{ + return std::wstring( spn.data(), static_cast<std::size_t>( spn.length() ) ); +} + +gsl_NODISCARD inline std::wstring +to_string( cwstring_span const & spn ) +{ + return std::wstring( spn.data(), static_cast<std::size_t>( spn.length() ) ); +} + +#endif // gsl_HAVE( WCHAR ) +#endif // to_string() + +// +// Stream output for string_span types +// + +namespace detail { + +template< class Stream > +void write_padding( Stream & os, std::streamsize n ) +{ + for ( std::streamsize i = 0; i < n; ++i ) + os.rdbuf()->sputc( os.fill() ); +} + +template< class Stream, class Span > +Stream & write_to_stream( Stream & os, Span const & spn ) +{ + typename Stream::sentry sentry( os ); + + if ( !os ) + return os; + + const std::streamsize length = gsl::narrow_failfast<std::streamsize>( spn.length() ); + + // Whether, and how, to pad + const bool pad = ( length < os.width() ); + const bool left_pad = pad && ( os.flags() & std::ios_base::adjustfield ) == std::ios_base::right; + + if ( left_pad ) + detail::write_padding( os, os.width() - length ); + + // Write span characters + os.rdbuf()->sputn( spn.begin(), length ); + + if ( pad && !left_pad ) + detail::write_padding( os, os.width() - length ); + + // Reset output stream width + os.width(0); + + return os; +} + +} // namespace detail + +template< typename Traits > +std::basic_ostream< char, Traits > & operator<<( std::basic_ostream< char, Traits > & os, string_span const & spn ) +{ + return detail::write_to_stream( os, spn ); +} + +template< typename Traits > +std::basic_ostream< char, Traits > & operator<<( std::basic_ostream< char, Traits > & os, cstring_span const & spn ) +{ + return detail::write_to_stream( os, spn ); +} + +#if gsl_HAVE( WCHAR ) + +template< typename Traits > +std::basic_ostream< wchar_t, Traits > & operator<<( std::basic_ostream< wchar_t, Traits > & os, wstring_span const & spn ) +{ + return detail::write_to_stream( os, spn ); +} + +template< typename Traits > +std::basic_ostream< wchar_t, Traits > & operator<<( std::basic_ostream< wchar_t, Traits > & os, cwstring_span const & spn ) +{ + return detail::write_to_stream( os, spn ); +} + +#endif // gsl_HAVE( WCHAR ) + +// +// ensure_sentinel() +// +// Provides a way to obtain a span from a contiguous sequence +// that ends with a (non-inclusive) sentinel value. +// +// Will fail-fast if sentinel cannot be found before max elements are examined. +// +namespace detail { + +template< class T, class SizeType, const T Sentinel > +gsl_constexpr14 static span<T> ensure_sentinel( T * seq, SizeType max = (std::numeric_limits<SizeType>::max)() ) +{ + typedef T * pointer; + + gsl_SUPPRESS_MSVC_WARNING( 26429, "f.23: symbol 'cur' is never tested for nullness, it can be marked as not_null" ) + pointer cur = seq; + + while ( static_cast<SizeType>( cur - seq ) < max && *cur != Sentinel ) + ++cur; + + gsl_Expects( *cur == Sentinel ); + + return span<T>( seq, gsl::narrow_cast< typename span<T>::index_type >( cur - seq ) ); +} +} // namespace detail + +// +// ensure_z - creates a string_span for a czstring or cwzstring. +// Will fail fast if a null-terminator cannot be found before +// the limit of size_type. +// + +template< class T > +gsl_NODISCARD inline gsl_constexpr14 span<T> +ensure_z( T * const & sz, size_t max = (std::numeric_limits<size_t>::max)() ) +{ + return detail::ensure_sentinel<T, size_t, 0>( sz, max ); +} + +template< class T, size_t N > +gsl_NODISCARD inline gsl_constexpr14 span<T> +ensure_z( T (&sz)[N] ) +{ + return ::gsl::ensure_z( gsl_ADDRESSOF( sz[0] ), N ); +} + +# if gsl_HAVE( TYPE_TRAITS ) + +template< class Container > +gsl_NODISCARD inline gsl_constexpr14 span< typename std::remove_pointer<typename Container::pointer>::type > +ensure_z( Container & cont ) +{ + return ::gsl::ensure_z( cont.data(), cont.length() ); +} +# endif + +// +// basic_zstring_span<> - A view of contiguous null-terminated characters, replace (*,len). +// + +template <typename T> +class basic_zstring_span +{ +public: + typedef T element_type; + typedef span<T> span_type; + + typedef typename span_type::index_type index_type; + typedef typename span_type::difference_type difference_type; + + typedef element_type * czstring_type; + typedef basic_string_span<element_type> string_span_type; + + gsl_api gsl_constexpr14 basic_zstring_span( span_type s ) + : span_( s ) + { + // expects a zero-terminated span + gsl_Expects( s.back() == '\0' ); + } + +#if gsl_HAVE( IS_DEFAULT ) + gsl_constexpr basic_zstring_span( basic_zstring_span const & ) = default; + gsl_constexpr basic_zstring_span( basic_zstring_span && ) = default; + gsl_constexpr14 basic_zstring_span & operator=( basic_zstring_span const & ) = default; + gsl_constexpr14 basic_zstring_span & operator=( basic_zstring_span && ) = default; +#else + gsl_api gsl_constexpr basic_zstring_span( basic_zstring_span const & other) : span_ ( other.span_ ) {} + gsl_api gsl_constexpr basic_zstring_span & operator=( basic_zstring_span const & other ) { span_ = other.span_; return *this; } +#endif + + gsl_NODISCARD gsl_api gsl_constexpr bool + empty() const gsl_noexcept + { + return false; + } + + gsl_NODISCARD gsl_api gsl_constexpr string_span_type + as_string_span() const gsl_noexcept + { + return string_span_type( span_.data(), span_.size() - 1 ); + } + + /*gsl_api*/ // currently disabled due to an apparent NVCC bug + gsl_NODISCARD gsl_constexpr string_span_type + ensure_z() const + { + return ::gsl::ensure_z(span_.data(), span_.size()); + } + + gsl_NODISCARD gsl_api gsl_constexpr czstring_type + assume_z() const gsl_noexcept + { + return span_.data(); + } + +private: + span_type span_; +}; + +// +// zString types: +// + +typedef basic_zstring_span< char > zstring_span; +typedef basic_zstring_span< char const > czstring_span; + +#if gsl_HAVE( WCHAR ) +typedef basic_zstring_span< wchar_t > wzstring_span; +typedef basic_zstring_span< wchar_t const > cwzstring_span; +#endif + +} // namespace gsl + +#if gsl_HAVE( HASH ) + +// +// std::hash specializations for GSL types +// + +namespace gsl { + +namespace detail { + +// +// Helper struct for std::hash specializations +// + +template<bool Condition> +struct conditionally_enabled_hash +{ + +}; + +// disabled as described in [unord.hash] +template<> +struct conditionally_enabled_hash< false > +{ +gsl_is_delete_access: + conditionally_enabled_hash() gsl_is_delete; + conditionally_enabled_hash( conditionally_enabled_hash const & ) gsl_is_delete; + conditionally_enabled_hash( conditionally_enabled_hash && ) gsl_is_delete; + conditionally_enabled_hash & operator=( conditionally_enabled_hash const & ) gsl_is_delete; + conditionally_enabled_hash & operator=( conditionally_enabled_hash && ) gsl_is_delete; +}; + +} // namespace detail + +} // namespace gsl + +namespace std { + +template< class T > +struct hash< ::gsl::not_null< T > > : public ::gsl::detail::conditionally_enabled_hash<is_default_constructible<hash<T>>::value> +{ +public: + gsl_NODISCARD gsl_constexpr std::size_t + operator()( ::gsl::not_null<T> const & v ) const + // hash function is not `noexcept` because `as_nullable()` has preconditions + { + return hash<T>()( ::gsl::as_nullable( v ) ); + } +}; +template< class T > +struct hash< ::gsl::not_null< T* > > +{ +public: + gsl_NODISCARD gsl_constexpr std::size_t + operator()( ::gsl::not_null< T* > const & v ) const gsl_noexcept + { + return hash<T*>()( ::gsl::as_nullable( v ) ); + } +}; + +template<> +struct hash< ::gsl::byte > +{ +public: + gsl_NODISCARD gsl_constexpr std::size_t operator()( ::gsl::byte v ) const gsl_noexcept + { + return ::gsl::to_integer<std::size_t>( v ); + } +}; + +} // namespace std + +#endif // gsl_HAVE( HASH ) + +#if gsl_FEATURE( GSL_LITE_NAMESPACE ) + +// gsl_lite namespace: + +// gsl-lite currently keeps all symbols in the namespace `gsl`. The `gsl_lite` namespace contains all the symbols in the +// `gsl` namespace, plus some extensions that are not specified in the Core Guidelines. +// +// Going forward, we want to support coexistence of gsl-lite with M-GSL, so we want to encourage using the `gsl_lite` +// namespace when consuming gsl-lite. Typical use in library code would be: +// +// #include <gsl-lite/gsl-lite.hpp> // instead of <gsl/gsl-lite.hpp> +// +// namespace foo { +// namespace gsl = ::gsl_lite; // convenience alias +// double mean( gsl::span<double const> elements ) +// { +// gsl_Expects( ! elements.empty() ); // instead of Expects() +// ... +// } +// } // namespace foo +// +// In a future version, the new <gsl-lite/gsl-lite.hpp> header will only define the `gsl_lite` namespace and no +// unprefixed `Expects()` and `Ensures()` macros to avoid collision with M-GSL. To ensure backward compatibility, the +// old header <gsl/gsl-lite.hpp> will keep defining the `gsl` namespace and the `Expects()` and `Ensures()` macros. + +namespace gsl_lite { + +namespace std11 = ::gsl::std11; +namespace std14 = ::gsl::std14; +namespace std17 = ::gsl::std17; +namespace std20 = ::gsl::std20; + +using namespace std11; +using namespace std14; +using namespace std17; +using namespace std20; + +using namespace ::gsl::detail::no_adl; + +# if gsl_HAVE( SHARED_PTR ) +using std::unique_ptr; +using std::shared_ptr; +using std::make_shared; +# endif + +using ::gsl::index; +using ::gsl::dim; +using ::gsl::stride; +using ::gsl::diff; + +# if gsl_HAVE( ALIAS_TEMPLATE ) +# if gsl_BETWEEN( gsl_COMPILER_MSVC_VERSION, 1, 141 ) // VS 2015 and earlier have trouble with `using` for alias templates + template< class T +# if gsl_HAVE( TYPE_TRAITS ) + , typename = typename std::enable_if< std::is_pointer<T>::value >::type +# endif + > + using owner = T; +# else +using ::gsl::owner; +# endif +# endif + +using ::gsl::fail_fast; + +using ::gsl::finally; +# if gsl_FEATURE( EXPERIMENTAL_RETURN_GUARD ) +using ::gsl::on_return; +using ::gsl::on_error; +# endif // gsl_FEATURE( EXPERIMENTAL_RETURN_GUARD ) + +using ::gsl::narrow_cast; +using ::gsl::narrowing_error; +using ::gsl::narrow; +using ::gsl::narrow_failfast; + +using ::gsl::at; + +using ::gsl::not_null; +using ::gsl::not_null_ic; +using ::gsl::make_not_null; + +using ::gsl::byte; + +using ::gsl::to_byte; +using ::gsl::to_integer; +using ::gsl::to_uchar; +using ::gsl::to_string; + +using ::gsl::with_container_t; +using ::gsl::with_container; + +using ::gsl::span; +using ::gsl::make_span; +using ::gsl::byte_span; +using ::gsl::copy; +using ::gsl::as_bytes; +using ::gsl::as_writable_bytes; +# if ! gsl_DEPRECATE_TO_LEVEL( 6 ) +using ::gsl::as_writeable_bytes; +# endif + +using ::gsl::basic_string_span; +using ::gsl::string_span; +using ::gsl::cstring_span; + +using ::gsl::basic_zstring_span; +using ::gsl::zstring_span; +using ::gsl::czstring_span; + +using ::gsl::zstring; +using ::gsl::czstring; + +# if gsl_HAVE( WCHAR ) +using ::gsl::wzstring; +using ::gsl::cwzstring; + +using ::gsl::wzstring_span; +using ::gsl::cwzstring_span; +# endif // gsl_HAVE( WCHAR ) + +using ::gsl::ensure_z; + +} // namespace gsl_lite + +#endif // gsl_FEATURE( GSL_LITE_NAMESPACE ) + +gsl_RESTORE_MSVC_WARNINGS() + +// #undef internal macros +#undef gsl_STATIC_ASSERT_ +#undef gsl_ENABLE_IF_ +#undef gsl_TRAILING_RETURN_TYPE_ +#undef gsl_RETURN_DECLTYPE_ + +#endif // GSL_GSL_LITE_HPP_INCLUDED + +// end of file diff --git a/vbz/CMakeLists.txt b/vbz/CMakeLists.txt index 0791655..964b765 100644 --- a/vbz/CMakeLists.txt +++ b/vbz/CMakeLists.txt @@ -31,7 +31,9 @@ add_dependencies(vbz streamvbyte ) -if (WIN32 OR APPLE OR "${CMAKE_SYSTEM_PROCESSOR}" MATCHES "x86_64") +if (WIN32 OR + (APPLE AND NOT "${CMAKE_SYSTEM_PROCESSOR}" MATCHES "arm64") OR + "${CMAKE_SYSTEM_PROCESSOR}" MATCHES "x86_64") if(NOT MSVC) target_compile_options(vbz PRIVATE -mssse3) endif() diff --git a/vbz/perf/test_data_generator.h b/vbz/perf/test_data_generator.h index 4b13d81..1bb593b 100644 --- a/vbz/perf/test_data_generator.h +++ b/vbz/perf/test_data_generator.h @@ -2,7 +2,7 @@ #include "../test/test_data.h" -#include <gsl/gsl> +#include <gsl/gsl-lite.hpp> #include <numeric> #include <random> diff --git a/vbz/test/CMakeLists.txt b/vbz/test/CMakeLists.txt index 5c8a3df..0e1b48c 100644 --- a/vbz/test/CMakeLists.txt +++ b/vbz/test/CMakeLists.txt @@ -9,13 +9,16 @@ add_sanitizers(vbz_test) set_property(TARGET vbz_test PROPERTY CXX_STANDARD 11) +find_package( Threads ) + target_link_libraries(vbz_test PUBLIC vbz + ${CMAKE_THREAD_LIBS_INIT} ) add_test( NAME vbz_test COMMAND vbz_test WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} -)
\ No newline at end of file +) diff --git a/vbz/test/test_utils.h b/vbz/test/test_utils.h index 596c1b0..138ffe9 100644 --- a/vbz/test/test_utils.h +++ b/vbz/test/test_utils.h @@ -1,6 +1,6 @@ #pragma once -#include <gsl/gsl> +#include <gsl/gsl-lite.hpp> #include <iostream> diff --git a/vbz/v0/vbz_streamvbyte.cpp b/vbz/v0/vbz_streamvbyte.cpp index 9ffeb01..609075e 100644 --- a/vbz/v0/vbz_streamvbyte.cpp +++ b/vbz/v0/vbz_streamvbyte.cpp @@ -2,7 +2,7 @@ #include "vbz_streamvbyte_impl.h" #include "vbz.h" -#include <gsl/gsl> +#include <gsl/gsl-lite.hpp> vbz_size_t vbz_max_streamvbyte_compressed_size_v0( std::size_t integer_size, diff --git a/vbz/v0/vbz_streamvbyte_impl.h b/vbz/v0/vbz_streamvbyte_impl.h index 015ad13..357cb61 100644 --- a/vbz/v0/vbz_streamvbyte_impl.h +++ b/vbz/v0/vbz_streamvbyte_impl.h @@ -5,7 +5,9 @@ #include "streamvbyte.h" #include "streamvbyte_zigzag.h" -#include <gsl/gsl> +#include <gsl/gsl-lite.hpp> + +#include <vector> /// \brief Generic implementation, safe for all integer types, and platforms. template <typename T, bool UseZigZag> @@ -53,14 +55,14 @@ struct StreamVByteWorkerV0 if (!UseZigZag) { - cast(gsl::make_span(intermediate_buffer), gsl::make_span(output)); + cast(gsl::make_span(intermediate_buffer), output); return vbz_size_t(output.size() * sizeof(T)); } std::vector<std::int32_t> output_buffer(output.size()); zigzag_delta_decode(intermediate_buffer.data(), output_buffer.data(), output_buffer.size(), 0); - cast(gsl::make_span(output_buffer), gsl::make_span(output)); + cast(gsl::make_span(output_buffer), output); return vbz_size_t(output.size() * sizeof(T)); } diff --git a/vbz/v1/vbz_streamvbyte.cpp b/vbz/v1/vbz_streamvbyte.cpp index 9fc3414..d2d9a67 100644 --- a/vbz/v1/vbz_streamvbyte.cpp +++ b/vbz/v1/vbz_streamvbyte.cpp @@ -3,7 +3,7 @@ #include "../v0/vbz_streamvbyte_impl.h" // for 4 byte case #include "vbz.h" -#include <gsl/gsl> +#include <gsl/gsl-lite.hpp> vbz_size_t vbz_max_streamvbyte_compressed_size_v1( std::size_t integer_size, diff --git a/vbz/v1/vbz_streamvbyte_impl.h b/vbz/v1/vbz_streamvbyte_impl.h index be306f9..b3bce88 100644 --- a/vbz/v1/vbz_streamvbyte_impl.h +++ b/vbz/v1/vbz_streamvbyte_impl.h @@ -5,9 +5,10 @@ #include "streamvbyte.h" #include "streamvbyte_zigzag.h" -#include <gsl/gsl> +#include <gsl/gsl-lite.hpp> #include <cassert> +#include <vector> #ifdef _MSC_VER # define VBZ_RESTRICT __restrict @@ -224,14 +225,14 @@ struct StreamVByteWorkerV1 if (!UseZigZag) { - cast(gsl::make_span(intermediate_buffer), gsl::make_span(output)); + cast(gsl::make_span(intermediate_buffer), output); return vbz_size_t(output.size() * sizeof(T)); } std::vector<std::int32_t> output_buffer(output.size()); zigzag_delta_decode(intermediate_buffer.data(), output_buffer.data(), output_buffer.size(), 0); - cast(gsl::make_span(output_buffer), gsl::make_span(output)); + cast(gsl::make_span(output_buffer), output); return vbz_size_t(output.size() * sizeof(T)); } diff --git a/vbz/vbz.cpp b/vbz/vbz.cpp index 56dbe8b..8ae0b74 100644 --- a/vbz/vbz.cpp +++ b/vbz/vbz.cpp @@ -1,7 +1,7 @@ #include "v0/vbz_streamvbyte.h" #include "v1/vbz_streamvbyte.h" -#include <gsl/gsl> +#include <gsl/gsl-lite.hpp> #include <zstd.h> #include <cassert> diff --git a/vbz_plugin/CMakeLists.txt b/vbz_plugin/CMakeLists.txt index 1b0603a..e4612f0 100644 --- a/vbz_plugin/CMakeLists.txt +++ b/vbz_plugin/CMakeLists.txt @@ -1,5 +1,5 @@ -add_library(vbz_hdf_plugin SHARED +add_library(vbz_hdf_plugin vbz_plugin_user_utils.h vbz_plugin.cpp vbz_plugin.h @@ -10,6 +10,16 @@ generate_export_header(vbz_hdf_plugin EXPORT_FILE_NAME vbz_plugin/vbz_hdf_plugin set_property(TARGET vbz_hdf_plugin PROPERTY CXX_STANDARD 11) +if(WIN32 AND HDF5_USE_STATIC_LIBRARIES) + # See vbz_plugin.cpp -- if also building with Python on Windows then the runtime + # used is determined by that Python version, so we only support dynamic builds. + if(ENABLE_PYTHON) + message(FATAL_ERROR "Cannot enable HDF5_USE_STATIC_LIBRARIES as well as ENABLE_PYTHON") + else() + add_definitions(-DHDF5_USE_STATIC_LIBRARIES) + endif() +endif() + target_include_directories( vbz_hdf_plugin PUBLIC diff --git a/vbz_plugin/vbz_plugin.cpp b/vbz_plugin/vbz_plugin.cpp index 4e39dd1..75e1612 100644 --- a/vbz_plugin/vbz_plugin.cpp +++ b/vbz_plugin/vbz_plugin.cpp @@ -2,7 +2,7 @@ #include "vbz_plugin.h" #include "vbz.h" -#include <gsl/gsl> +#include <gsl/gsl-lite.hpp> #include <hdf5/hdf5_plugin_types.h> #include <array> @@ -32,7 +32,7 @@ int checksum(gsl::span<char const> input) } #endif -#ifdef _WIN32 +#if defined(_WIN32) && !defined(HDF5_USE_STATIC_LIBRARIES) HMODULE get_hdf_module() { static HMODULE module = nullptr; @@ -64,7 +64,7 @@ HMODULE get_hdf_module() // void* h5_malloc(std::size_t size) { -#ifdef _WIN32 +#if defined(_WIN32) && !defined(HDF5_USE_STATIC_LIBRARIES) static auto module = get_hdf_module(); static auto malloc_memory = (void*(*)(size_t, bool))GetProcAddress(module, "H5allocate_memory"); @@ -76,7 +76,7 @@ void* h5_malloc(std::size_t size) void h5_free(void* memory) { -#ifdef _WIN32 +#if defined(_WIN32) && !defined(HDF5_USE_STATIC_LIBRARIES) static auto module = get_hdf_module(); static auto free_hdf5 = (int(*)(void *))GetProcAddress(module, "H5free_memory"); |