diff options
32 files changed, 5653 insertions, 12421 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 5a6f360..b3b7f1d 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/debian/changelog b/debian/changelog index c810268..9764f81 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,18 @@ +libvbz-hdf-plugin (1.0.2-1) unstable; urgency=medium + + * New upstream version + * Standards-Version: 4.6.1 (routine-update) + * Drop unnecessary dependency on build-essential. + * Apply multi-arch hints. + + libvbz-hdf-plugin-dev: Add Multi-Arch: same. + * Refresh use-packaged-streamvbyte.patch. + * Refresh fix-install-location.patch. + * Delete update-catch2.patch: applied upstream. + * d/rules: enable hardening. + * Add symbols tracking for libvbz-hdf-plugin0. + + -- Étienne Mollier <emollier@debian.org> Sun, 03 Jul 2022 14:23:31 +0200 + libvbz-hdf-plugin (1.0.1-3) unstable; urgency=medium [ Steve Langasek ] diff --git a/debian/control b/debian/control index bdb016d..f30f5b5 100644 --- a/debian/control +++ b/debian/control @@ -1,16 +1,17 @@ Source: libvbz-hdf-plugin Maintainer: Debian Med Packaging Team <debian-med-packaging@lists.alioth.debian.org> -Uploaders: Andreas Tille <tille@debian.org>, Nilesh Patra <nilesh@debian.org> +Uploaders: Andreas Tille <tille@debian.org>, + Nilesh Patra <nilesh@debian.org>, + Étienne Mollier <emollier@debian.org> Section: science Priority: optional Build-Depends: debhelper-compat (= 13), -# d-shlibs, # not possible since no static lib cmake, libzstd-dev, libhdf5-dev, libstreamvbyte-dev, dh-exec -Standards-Version: 4.6.0 +Standards-Version: 4.6.1 Vcs-Browser: https://salsa.debian.org/med-team/libvbz-hdf-plugin Vcs-Git: https://salsa.debian.org/med-team/libvbz-hdf-plugin.git Homepage: https://github.com/nanoporetech/vbz_compression/ @@ -41,6 +42,7 @@ Section: libdevel Depends: libvbz-hdf-plugin0 (= ${binary:Version}), ${shlibs:Depends}, ${misc:Depends} +Multi-Arch: same Description: VBZ compression plugin for nanopore signal data (devel) VBZ Compression uses variable byte integer encoding to compress nanopore signal data. diff --git a/debian/libvbz-hdf-plugin0.symbols b/debian/libvbz-hdf-plugin0.symbols new file mode 100644 index 0000000..613eef4 --- /dev/null +++ b/debian/libvbz-hdf-plugin0.symbols @@ -0,0 +1,33 @@ +libvbz_hdf_plugin.so.0 libvbz-hdf-plugin0 #MINVER# +* Build-Depends-Package: libvbz-hdf-plugin-dev + H5PLget_plugin_info@Base 1.0.2 + H5PLget_plugin_type@Base 1.0.2 + (arch=any-amd64 arm64 mips64el ppc64el s390x alpha ia64 ppc64 sparc64 riscv64)_Z10vbz_filterjmPKjmPmPPv@Base 1.0.2 + (arch=any-i386 armel armhf mipsel hppa m68k powerpc sh4)_Z10vbz_filterjjPKjjPjPPv@Base 1.0.2 + _Z23streamvbyte_decode_halfPKhPjj@Base 1.0.2 + _Z23streamvbyte_encode_halfPKjjPh@Base 1.0.2 + (arch=any-amd64 arm64 mips64el ppc64el s390x alpha ia64 ppc64 sparc64 riscv64)_Z38vbz_max_streamvbyte_compressed_size_v0mj@Base 1.0.2 + (arch=any-amd64 arm64 mips64el ppc64el s390x alpha ia64 ppc64 sparc64 riscv64)_Z38vbz_max_streamvbyte_compressed_size_v1mj@Base 1.0.2 + (arch=any-i386 armel armhf mipsel hppa m68k powerpc sh4)_Z38vbz_max_streamvbyte_compressed_size_v0jj@Base 1.0.2 + (arch=any-i386 armel armhf mipsel hppa m68k powerpc sh4)_Z38vbz_max_streamvbyte_compressed_size_v1jj@Base 1.0.2 + _Z41vbz_delta_zig_zag_streamvbyte_compress_v0PKvjPvjib@Base 1.0.2 + _Z41vbz_delta_zig_zag_streamvbyte_compress_v1PKvjPvjib@Base 1.0.2 + _Z43vbz_delta_zig_zag_streamvbyte_decompress_v0PKvjPvjib@Base 1.0.2 + _Z43vbz_delta_zig_zag_streamvbyte_decompress_v1PKvjPvjib@Base 1.0.2 + (arch=any-amd64)_ZN19StreamVByteWorkerV0IsLb1EE10decompressEN3gsl4spanIKcEENS2_IcEE@Base 1.0.2 + _ZNKSt5ctypeIcE8do_widenEc@Base 1.0.2 + streamvbyte_decode@Base 1.0.2 + streamvbyte_encode@Base 1.0.2 + vbz_compress@Base 1.0.2 + vbz_compress_sized@Base 1.0.2 + vbz_decompress@Base 1.0.2 + vbz_decompress_sized@Base 1.0.2 + vbz_decompressed_size@Base 1.0.2 + vbz_error_string@Base 1.0.2 + vbz_is_error@Base 1.0.2 + vbz_max_compressed_size@Base 1.0.2 + vbz_plugin_info@Base 1.0.2 + zigzag_decode@Base 1.0.2 + zigzag_delta_decode@Base 1.0.2 + zigzag_delta_encode@Base 1.0.2 + zigzag_encode@Base 1.0.2 diff --git a/debian/patches/fix-install-location.patch b/debian/patches/fix-install-location.patch index e6a3177..bf3d071 100644 --- a/debian/patches/fix-install-location.patch +++ b/debian/patches/fix-install-location.patch @@ -2,9 +2,9 @@ Description: Fix install location for .so Author: Nilesh Patra <nilesh@debian.org> Forwarded: not-needed Last-Update: 2021-05-22 ---- a/vbz_plugin/CMakeLists.txt -+++ b/vbz_plugin/CMakeLists.txt -@@ -62,7 +62,7 @@ +--- libvbz-hdf-plugin.orig/vbz_plugin/CMakeLists.txt ++++ libvbz-hdf-plugin/vbz_plugin/CMakeLists.txt +@@ -72,7 +72,7 @@ set(VBZ_PLUGIN_COMPONENT COMPONENT hdf_plugin) endif() diff --git a/debian/patches/series b/debian/patches/series index 2d66ccd..06ebda1 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -1,4 +1,3 @@ use-packaged-streamvbyte.patch fix-install-location.patch soversion.patch -update-catch2.patch diff --git a/debian/patches/update-catch2.patch b/debian/patches/update-catch2.patch deleted file mode 100644 index 072fc69..0000000 --- a/debian/patches/update-catch2.patch +++ /dev/null @@ -1,9997 +0,0 @@ -Description: import catch2 version 2.13.8 to fix build failure with glibc 2.34 -Author: Steve Langasek <steve.langasek@ubuntu.com> -Last-Update: 2022-04-12 -Forwarded: no -Bug-Debian: https://bugs.debian.org/1009620 - -Index: libvbz-hdf-plugin-1.0.1/third_party/catch2/catch.hpp -=================================================================== ---- libvbz-hdf-plugin-1.0.1.orig/third_party/catch2/catch.hpp -+++ libvbz-hdf-plugin-1.0.1/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 @@ - - #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 @@ - // 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 @@ - // 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 @@ - # 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 @@ - #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 @@ - # 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 @@ - # 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 @@ - # 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 @@ - 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 @@ - } // 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 @@ - // start catch_interfaces_testcase.h - - #include <vector> --#include <memory> - - namespace Catch { - -@@ -474,8 +574,6 @@ - virtual ~ITestInvoker(); - }; - -- using ITestCasePtr = std::shared_ptr<ITestInvoker>; -- - class TestCase; - struct IConfig; - -@@ -485,6 +583,7 @@ - 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 @@ - #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 @@ - m_size( stdString.size() ) - {} - -- ~StringRef() noexcept { -- delete[] m_data; -- } -- -- 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; -+ explicit operator std::string() const { -+ return std::string(m_start, m_size); - } - -- 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 @@ - #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 -+#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 --// 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_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 @@ - }; \ - } \ - 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 @@ - }; \ - 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 - -- #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_2( TestNameClass, TestName, ClassName, Name, Tags, ... ) \ -+#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_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 @@ - - 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 @@ - } - - // 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 @@ - - 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 @@ - } - }; - -+#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 @@ - 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 @@ - #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 @@ - # 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 @@ - } - #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 @@ - #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 @@ - } - #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 @@ - #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 @@ - 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 @@ - - public: - explicit UnaryExpr( LhsT lhs ) -- : ITransientExpression{ false, lhs ? true : false }, -+ : ITransientExpression{ false, static_cast<bool>(lhs) }, - m_lhs( lhs ) - {} - }; -@@ -1773,6 +2372,32 @@ - 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 @@ - // start catch_interfaces_capture.h - - #include <string> -+#include <chrono> - - namespace Catch { - -@@ -1815,15 +2441,20 @@ - 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 @@ - 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 @@ - 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 @@ - /////////////////////////////////////////////////////////////////////////////// - #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 @@ - 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 @@ - } // 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 @@ - struct IReporterRegistry; - struct IReporterFactory; - struct ITagAliasRegistry; -+ struct IMutableEnumValuesRegistry; -+ - class StartupExceptionRegistry; - - using IReporterFactoryPtr = std::shared_ptr<IReporterFactory>; -@@ -2365,7 +2968,6 @@ - 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 @@ - 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 @@ - {} - - 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 @@ - catch( T& ex ) { - return m_translateFunction( ex ); - } -+#endif - } - - protected: -@@ -2452,9 +3059,10 @@ - /////////////////////////////////////////////////////////////////////////////// - #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 @@ - 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 @@ - - #include <string> - #include <iosfwd> -+#include <vector> - - namespace Catch { - -@@ -2595,7 +3204,13 @@ - 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 @@ - 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 @@ - 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 @@ - 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 @@ - } // 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 @@ - }; - - 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 @@ - - // 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 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 @@ - 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 @@ - 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 @@ - 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 @@ - // 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 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 @@ - 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 @@ - // 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 @@ - [[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 @@ - #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 @@ - } - - 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&; - -- auto size() const -> size_t { return m_size; } -- auto operator[]( size_t index ) const -> T { -- assert( index < m_size ); -- return m_generator->get( index ); -+ 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; -+ -+ 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(); -+ } -+ -+} // namespace Generators -+} // namespace Catch - -- template<typename T> -- class GeneratorRandomiser : public IGenerator<T> { -- Generator<T> m_baseGenerator; -+#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) -+ -+// end catch_generators.hpp -+// start catch_generators_generic.hpp -+ -+namespace Catch { -+namespace Generators { - -- std::vector<size_t> m_indices; -+ 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 -+ -+ // 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; -+ } -+ }; - -- return Generator<T>( size, pf::make_unique<GeneratorRandomiser<T>>( std::move( gen ), size ) ); -+ 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(); -+} - -- Generators() : GeneratorBase( 0 ) {} -+// end catch_context.h -+// start catch_interfaces_config.h - -- void populate( T&& val ) { -- m_size += 1; -- m_generators.emplace_back( value( std::move( val ) ) ); -+// start catch_option.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 ) -+ {} -+ -+ ~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; - } -- void populate( Generator<T>&& generator ) { -- m_size += generator.size(); -- m_generators.emplace_back( std::move( generator ) ); -+ Option& operator = ( T const& _value ) { -+ reset(); -+ nullableValue = new( storage ) T( _value ); -+ return *this; - } - -- template<typename U, typename... Gs> -- void populate( U&& valueOrGenerator, Gs... moreGenerators ) { -- populate( std::forward<U>( valueOrGenerator ) ); -- populate( std::forward<Gs>( moreGenerators )... ); -+ void reset() { -+ if( nullableValue ) -+ nullableValue->~T(); -+ nullableValue = nullptr; - } - -- 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 << ')'); -+ 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; -+ } -+ -+ 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()); -+ } -+ -+ Integer const& get() const override { -+ return m_current_number; -+ } -+ bool next() override { -+ m_current_number = m_dist(m_rng); -+ return true; - } -+}; - -- auto acquireGeneratorTracker( SourceLineInfo const& lineInfo ) -> IGeneratorTracker&; -+// 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 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; -+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; -+ } -+ -+ 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)); -+} - -- IGeneratorTracker& tracker = acquireGeneratorTracker( lineInfo ); -- if( !tracker.hasGenerator() ) -- tracker.setGenerator( pf::make_unique<Generators<UnderlyingType>>( generatorExpression() ) ); -+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"); -+ -+ 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]; -+ } - -- auto const& generator = static_cast<Generators<UnderlyingType> const&>( *tracker.getGenerator() ); -- return generator[tracker.getIndex()]; -+ 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 @@ - arcSafeRelease( m_substr ); - } - -- bool match( NSString* arg ) const override { -+ bool match( NSString* str ) const override { - return false; - } - -@@ -3685,7 +4973,7 @@ - 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 @@ - // 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 @@ - 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 { - -+ 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 @@ - 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 @@ - 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 @@ - 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 @@ - #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 @@ - - 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 @@ - 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 @@ - 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 @@ - } // end namespace Catch - - // end catch_assertionresult.h --// start catch_option.hpp -+#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING) -+// start catch_estimate.hpp - --namespace Catch { -+ // Statistics estimates - -- // 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(); -- } -+namespace Catch { -+ namespace Benchmark { -+ template <typename Duration> -+ struct Estimate { -+ Duration point; -+ Duration lower_bound; -+ Duration upper_bound; -+ double confidence_interval; - -- Option& operator= ( Option const& _other ) { -- if( &_other != this ) { -- reset(); -- if( _other ) -- nullableValue = new( storage ) T( *_other ); -+ 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; -- } -+// Outlier information - -- bool some() const { return nullableValue != nullptr; } -- bool none() const { return nullableValue == nullptr; } -+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 - -- bool operator !() const { return nullableValue == nullptr; } -- explicit operator bool() const { -- return some(); -- } -+ 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 @@ - - 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 @@ - 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 @@ - - 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 @@ - // 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 @@ - - 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 @@ - - 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 @@ - - 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 @@ - #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 @@ - - static std::string getDescription(); - -- ReporterPreferences getPreferences() const override; -- - void noMatchingTestCases(std::string const& spec) override; - - void assertionStarting(AssertionInfo const&) override; -@@ -4891,6 +6161,8 @@ - - 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 @@ - 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 @@ - - void printTotalsDivider(Totals const& totals); - void printSummaryDivider(); -+ void printTestFilters(); - - private: - bool m_headerPrinted = false; -@@ -4945,6 +6222,14 @@ - #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 @@ - - 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 @@ - - private: - mutable XmlWriter* m_writer = nullptr; -+ XmlFormatting m_fmt; - }; - - XmlWriter( std::ostream& os = Catch::cout() ); -@@ -4991,11 +6277,11 @@ - 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 @@ - 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 @@ - - private: - -+ void applyFormatting(XmlFormatting fmt); -+ - void writeDeclaration(); - - void newlineIfNecessary(); -@@ -5063,9 +6351,10 @@ - - 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 @@ - - 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 @@ - // 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 @@ - 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 @@ - - // Debug/ checking - virtual bool isSectionTracker() const = 0; -- virtual bool isIndexTracker() const = 0; -+ virtual bool isGeneratorTracker() const = 0; - }; - - class TrackerContext { -@@ -5206,8 +7542,6 @@ - - public: - -- static TrackerContext& instance(); -- - ITracker& startRun(); - void endRun(); - -@@ -5231,7 +7565,6 @@ - }; - - using Children = std::vector<ITrackerPtr>; -- NameAndLocation m_nameAndLocation; - TrackerContext& m_ctx; - ITracker* m_parent; - Children m_children; -@@ -5240,11 +7573,13 @@ - 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 @@ - void openChild() override; - - bool isSectionTracker() const override; -- bool isIndexTracker() const override; -+ bool isGeneratorTracker() const override; - - void open(); - -@@ -5269,33 +7604,24 @@ - - 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 @@ - using TestCaseTracking::ITracker; - using TestCaseTracking::TrackerContext; - using TestCaseTracking::SectionTracker; --using TestCaseTracking::IndexTracker; - - } // namespace Catch - -@@ -5321,6 +7646,217 @@ - } - // 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 @@ - 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 @@ - // 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 @@ - - #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 @@ - #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 @@ - - // 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 @@ - 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 @@ - 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 @@ - } - - bool AssertionResult::hasExpression() const { -- return m_info.capturedExpression[0] != 0; -+ return !m_info.capturedExpression.empty(); - } - - bool AssertionResult::hasMessage() const { -@@ -5852,16 +8335,22 @@ - } - - 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 @@ - - } // 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 @@ - 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 @@ - // ----------- end of #include from clara_textflow.hpp ----------- - // ........... back in clara.hpp - -+#include <cctype> - #include <string> - #include <memory> - #include <set> -@@ -6617,7 +9084,7 @@ - } - 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 @@ - 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 @@ - }; - 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 @@ - | 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 @@ - | 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 { - -- 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 @@ - : 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 @@ - 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 @@ - } - - // 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 @@ - }; - - struct NoColourImpl : IColourImpl { -- void use( Colour::Code ) {} -+ void use( Colour::Code ) override {} - - static IColourImpl* instance() { - static NoColourImpl s_instance; -@@ -7591,7 +10121,7 @@ - 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 @@ - // 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 @@ - - 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 { - - Colour::Colour( Code _colourCode ) { use( _colourCode ); } -- Colour::Colour( Colour&& rhs ) noexcept { -- m_moved = rhs.m_moved; -- rhs.m_moved = true; -- } -- Colour& Colour::operator=( 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&& other ) noexcept { -+ m_moved = other.m_moved; -+ other.m_moved = true; - return *this; - } - -@@ -7743,7 +10274,13 @@ - - 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 @@ - 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 @@ - 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 @@ - } - - // 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 @@ - // 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 @@ - - 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 @@ - // 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 @@ - 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 @@ - 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 @@ - } - } - -+ 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 @@ - 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 @@ - 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 @@ - { 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 @@ - 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 @@ - } - } - -- 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 @@ - - IGeneratorTracker::~IGeneratorTracker() {} - --namespace Generators { -- -- GeneratorBase::~GeneratorBase() {} -- -- std::vector<size_t> randomiseIndices( size_t selectionSize, size_t sourceSize ) { -- -- assert( selectionSize <= sourceSize ); -- std::vector<size_t> indices; -- indices.reserve( selectionSize ); -- std::uniform_int_distribution<size_t> uid( 0, sourceSize-1 ); -+const char* GeneratorException::what() const noexcept { -+ return m_msg; -+} - -- 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; -- } -+namespace Generators { - -- auto acquireGeneratorTracker( SourceLineInfo const& lineInfo ) -> IGeneratorTracker& { -- return getResultCapture().acquireGeneratorTracker( lineInfo ); -- } -+ GeneratorUntypedBase::~GeneratorUntypedBase() {} - -- 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 @@ - - 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 @@ - - 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 { - - 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 @@ - } - - 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 @@ - } - - 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 @@ - 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 @@ - - } // 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 @@ - } // 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) -+ -+ float nextafter(float x, float y) { -+ return ::nextafterf(x, y); -+ } - -- if ((lc.i < 0) != (rc.i < 0)) { -- // Potentially we can have +0 and -0 -- return lhs == rhs; -+ double nextafter(double x, double y) { -+ return ::nextafter(x, y); - } - -- auto ulpDiff = std::abs(lc.i - rc.i); -- return ulpDiff <= maxUlpDiff; -+#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); - } - -+template <typename FloatingPoint> -+void write(std::ostream& out, FloatingPoint num) { -+ out << std::scientific -+ << std::setprecision(std::numeric_limits<FloatingPoint>::max_digits10 - 1) -+ << num; - } - --namespace Catch { -+} // 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 @@ - 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 @@ - #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 @@ - 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 @@ - //////////////////////////////////////////////////////////////////////////// - - 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 @@ - // 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 @@ - 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 @@ - {} - 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 @@ - 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 { - -- 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 @@ - 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 { - - 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 @@ - 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 @@ - ExceptionTranslatorRegistry m_exceptionTranslatorRegistry; - TagAliasRegistry m_tagAliasRegistry; - StartupExceptionRegistry m_exceptionRegistry; -+ Detail::EnumValuesRegistry m_enumValuesRegistry; - }; - } - -@@ -9671,7 +12586,6 @@ - - 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 @@ - 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 @@ - 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 @@ - // 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 @@ - - 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 @@ - - 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 @@ - - 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 @@ - 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 @@ - // 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 @@ - m_lastAssertionPassed = true; - ++m_totals.assertions.passed; - resetAssertionInfo(); -+ m_messageScopes.clear(); - } - - bool RunContext::aborting() const { -@@ -9986,13 +12986,10 @@ - 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 @@ - 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 @@ - 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 @@ - 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 @@ - 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 @@ - // end catch_version.h - #include <cstdlib> - #include <iomanip> -+#include <set> -+#include <iterator> - - namespace Catch { - -@@ -10299,52 +13310,76 @@ - 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); -+ } - -- bool first = true; -- for (const auto& input : config->getTestsOrTags()) { -- if (!first) { testConfig << ' '; } -- first = false; -- testConfig << input; -+ for (auto const& match : m_matches) { -+ if (match.tests.empty()) { -+ m_context.reporter().noMatchingTestCases(match.name); -+ totals.error = -1; -+ } - } - -- context.reporter().noMatchingTestCases(testConfig.str()); -- totals.error = -1; -+ if (!invalidArgs.empty()) { -+ for (auto const& invalidArg: invalidArgs) -+ m_context.reporter().reportInvalidArguments(invalidArg); -+ } -+ -+ 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 @@ - #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 @@ - } - 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 @@ - - 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 @@ - 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 @@ - 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 @@ - // 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 @@ - } - - } // end namespace Catch -+#endif - // end catch_startup_exception_registry.cpp - // start catch_stream.cpp - -@@ -10593,7 +13640,7 @@ - - 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 @@ - - 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 @@ - #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 @@ - 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 @@ - 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 @@ - // 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 @@ - 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 @@ - 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 @@ - 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 @@ - } - } - 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 @@ - // 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; - -- std::vector<TestCase> sorted = unsortedTestCases; -+ 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; -+ } -+ -+ 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 @@ - 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 @@ - } - - 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 @@ - - 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 @@ - 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 @@ - } - - 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 @@ - 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 @@ - } - - 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 @@ - } - } - -+ 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 @@ - } - - 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() ); -- } -- -- 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; -+ m_filters.insert( m_filters.end(), filters.begin()+1, filters.end() ); - } - -- int IndexTracker::index() const { return m_index; } -- -- void IndexTracker::moveNext() { -- m_index++; -- m_children.clear(); -+ std::vector<std::string> const& SectionTracker::getFilters() const { -+ return m_filters; - } - -- 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 @@ - using TestCaseTracking::ITracker; - using TestCaseTracking::TrackerContext; - using TestCaseTracking::SectionTracker; --using TestCaseTracking::IndexTracker; - - } // namespace Catch - -@@ -11586,47 +14621,81 @@ - - 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 @@ - 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; -- } -- } -- 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(); -+ 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; -+ } -+ -+ m_substring += c; -+ if( !isControlChar( c ) ) { -+ m_patternName += c; -+ m_realPatternPos++; -+ } -+ 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 ); - } -- 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>(); - } -- void TestSpecParser::startNewMode( Mode mode, std::size_t start ) { -+ bool TestSpecParser::processOtherChar( char c ) { -+ if( !isControlChar( c ) ) -+ return false; -+ m_substring += c; -+ endMode(); -+ return true; -+ } -+ 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 @@ - } - } - -+ 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 @@ - // 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 @@ - 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 @@ - } - #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 @@ - 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 @@ - // 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 @@ - } - - Version const& libraryVersion() { -- static Version version( 2, 5, 0, "", 0 ); -+ static Version version( 2, 13, 8, "", 0 ); - return version; - } - -@@ -12127,14 +15395,12 @@ - // 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 @@ - 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 @@ - } - - 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 @@ - // (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 @@ - 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 @@ - 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 @@ - } - 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 @@ - } - - 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 @@ - 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 @@ - - 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 @@ - #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 @@ - 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 @@ - 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 @@ - } - - 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 @@ - #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 @@ - 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 @@ - 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 @@ - case Unit::Nanoseconds: - return "ns"; - case Unit::Microseconds: -- return "µs"; -+ return "us"; - case Unit::Milliseconds: - return "ms"; - case Unit::Seconds: -@@ -13016,7 +16360,7 @@ - - } - 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 @@ - 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 @@ - - 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 @@ - 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 @@ - 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 @@ - } - - void ConsoleReporter::sectionStarting(SectionInfo const& _sectionInfo) { -+ m_tablePrinter->close(); - m_headerPrinted = false; - StreamingReporterBase::sectionStarting(_sectionInfo); - } -@@ -13146,8 +16514,9 @@ - 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 @@ - StreamingReporterBase::sectionEnded(_sectionStats); - } - --void ConsoleReporter::benchmarkStarting(BenchmarkInfo const& info) { -- lazyPrintWithoutClosingBenchmarkTable(); -- -- auto nameCol = Column( info.name ).width( static_cast<std::size_t>( m_tablePrinter->columnInfos()[0].width - 2 ) ); -+#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING) -+void ConsoleReporter::benchmarkPreparing(std::string const& name) { -+ lazyPrintWithoutClosingBenchmarkTable(); -+ -+ 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 @@ - stream << std::endl; - StreamingReporterBase::testRunEnded(_testRunStats); - } -+void ConsoleReporter::testRunStarting(TestRunInfo const& _testInfo) { -+ StreamingReporterBase::testRunStarting(_testInfo); -+ printTestFilters(); -+} - - void ConsoleReporter::lazyPrint() { - -@@ -13251,11 +16649,9 @@ - - 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 @@ - 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 @@ - #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 @@ - #include <sstream> - #include <ctime> - #include <algorithm> -+#include <iomanip> - - namespace Catch { - -@@ -13420,7 +16828,7 @@ - #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 @@ - 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 @@ - - 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 @@ - 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 @@ - 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 @@ - 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 @@ - 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 @@ - - 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 @@ - rss << msg.message << '\n'; - - rss << "at " << result.getSourceInfo(); -- xml.writeText( rss.str(), false ); -+ xml.writeText( rss.str(), XmlFormatting::Newline ); - } - } - -@@ -13659,19 +17116,41 @@ - 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 @@ - 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 @@ - 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 @@ - .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 @@ - .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 @@ - - #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 @@ - #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 @@ - #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 @@ - #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 @@ - - #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 @@ - #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 @@ - #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 @@ - - #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 @@ - #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 @@ - #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 @@ - #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 @@ - #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 @@ - #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 @@ - #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/debian/patches/use-packaged-streamvbyte.patch b/debian/patches/use-packaged-streamvbyte.patch index 5586f96..7e6428b 100644 --- a/debian/patches/use-packaged-streamvbyte.patch +++ b/debian/patches/use-packaged-streamvbyte.patch @@ -2,9 +2,9 @@ Description: Use packaged streamvbyte instead of third_party Author: Nilesh Patra <nilesh@debian.org> Forwarded: not-needed Last-Update: 2021-05-22 ---- a/CMakeLists.txt -+++ b/CMakeLists.txt -@@ -138,34 +138,8 @@ +--- libvbz-hdf-plugin.orig/CMakeLists.txt ++++ libvbz-hdf-plugin/CMakeLists.txt +@@ -145,34 +145,8 @@ find_package(HDF5 1.8.16) find_package(zstd 1.3.1 REQUIRED) find_package(Sanitizers) @@ -41,8 +41,8 @@ Last-Update: 2021-05-22 ######################################################################## # ---- a/vbz/CMakeLists.txt -+++ b/vbz/CMakeLists.txt +--- libvbz-hdf-plugin.orig/vbz/CMakeLists.txt ++++ libvbz-hdf-plugin/vbz/CMakeLists.txt @@ -22,14 +22,16 @@ PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} @@ -62,9 +62,9 @@ Last-Update: 2021-05-22 - streamvbyte -) - if (WIN32 OR APPLE OR "${CMAKE_SYSTEM_PROCESSOR}" MATCHES "x86_64") - if(NOT MSVC) -@@ -37,12 +39,6 @@ + if (WIN32 OR + (APPLE AND NOT "${CMAKE_SYSTEM_PROCESSOR}" MATCHES "arm64") OR +@@ -39,12 +41,6 @@ endif() endif() diff --git a/debian/rules b/debian/rules index 916af7f..2092f08 100755 --- a/debian/rules +++ b/debian/rules @@ -2,6 +2,7 @@ # DH_VERBOSE := 1 export LC_ALL=C.UTF-8 +export DEB_BUILD_MAINT_OPTIONS = hardening=+all include /usr/share/dpkg/default.mk 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/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 d519f7d..4526474 100644 --- a/vbz/CMakeLists.txt +++ b/vbz/CMakeLists.txt @@ -33,7 +33,9 @@ target_link_libraries(vbz # This explicit dependency is required to make sure the header files are installed into the right # location before we try building against them. -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 cfc73e5..565c179 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 @@ -11,6 +11,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"); |