summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorÉtienne Mollier <emollier@debian.org>2022-07-03 13:51:25 +0200
committerÉtienne Mollier <emollier@debian.org>2022-07-03 13:51:25 +0200
commitac1745a2d7dd6e2010b6ea804dd89a0d6918111f (patch)
treebaa360e08891b38e5ec5e6e0fd71459a585733eb
parent9a5186edead2633a422df47926164e69cd4d3fcd (diff)
New upstream version 1.0.2
-rw-r--r--CMakeLists.txt9
-rw-r--r--cmake/Findzstd.cmake10
-rw-r--r--cmake/ONTFindModuleHelpers.cmake5
-rw-r--r--cmake/SignFile.cmake30
-rw-r--r--cmake/conan.cmake344
-rw-r--r--python/test/requirements_1.10.txt5
-rw-r--r--python/test/requirements_1.12.txt2
-rw-r--r--third_party/catch2/catch.hpp6938
-rw-r--r--third_party/gsl-disable-gsl-suppress.patch11
-rw-r--r--[-rwxr-xr-x]third_party/gsl.h10
-rw-r--r--[-rwxr-xr-x]third_party/gsl/gsl6
-rw-r--r--[-rwxr-xr-x]third_party/gsl/gsl-lite-vc6.hpp (renamed from third_party/gsl/gsl-lite-vc6.h)56
-rw-r--r--[-rwxr-xr-x]third_party/gsl/gsl-lite.h2258
-rw-r--r--third_party/gsl/gsl-lite.hpp5197
-rw-r--r--vbz/CMakeLists.txt4
-rw-r--r--vbz/perf/test_data_generator.h2
-rw-r--r--vbz/test/CMakeLists.txt5
-rw-r--r--vbz/test/test_utils.h2
-rw-r--r--vbz/v0/vbz_streamvbyte.cpp2
-rw-r--r--vbz/v0/vbz_streamvbyte_impl.h8
-rw-r--r--vbz/v1/vbz_streamvbyte.cpp2
-rw-r--r--vbz/v1/vbz_streamvbyte_impl.h7
-rw-r--r--vbz/vbz.cpp2
-rw-r--r--vbz_plugin/CMakeLists.txt12
-rw-r--r--vbz_plugin/vbz_plugin.cpp8
25 files changed, 10859 insertions, 4076 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 5f01ecd..b9421f8 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -17,6 +17,7 @@ project(hdf_plugins
)
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
+set(CMAKE_CXX_STANDARD 14)
include(ExternalProject)
include(GenerateExportHeader)
@@ -75,6 +76,8 @@ if (NOT VBZ_BUILD_ARCHIVE)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
endif()
+option(BUILD_SHARED_LIBS "Build shared library for VBZ plugin" ON)
+
if (ENABLE_CONAN)
#
# Dependencies: Conan
@@ -87,7 +90,7 @@ if (ENABLE_CONAN)
include(conan)
set(_requirements
- "zstd/1.3.4@nanopore/stable")
+ "zstd/1.4.8@nanopore/stable")
set(_generators
cmake
json)
@@ -111,10 +114,14 @@ if (ENABLE_CONAN)
list(APPEND _extra_args BUILD_TYPE "${_build_type_${_build_type}}")
endif()
endif()
+ if (CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
+ list(APPEND CONAN_EXTRA_SETTINGS "compiler.cppstd=${CMAKE_CXX_STANDARD}")
+ endif()
if (CONAN_EXTRA_SETTINGS)
list(APPEND _extra_args
SETTINGS
${CONAN_EXTRA_SETTINGS}
+ BUILD missing
)
endif()
diff --git a/cmake/Findzstd.cmake b/cmake/Findzstd.cmake
index 7fd4b4a..493a53b 100644
--- a/cmake/Findzstd.cmake
+++ b/cmake/Findzstd.cmake
@@ -1,6 +1,8 @@
find_path(ZSTD_INCLUDE_DIR
NAMES zstd.h
- PATHS ${CONAN_INCLUDE_DIRS_RELEASE}
+ PATHS
+ ${CONAN_INCLUDE_DIRS_RELEASE}
+ ${CONAN_INCLUDE_DIRS_DEBUG}
)
set(ZSTD_NAMES zstd zstd_static)
@@ -11,7 +13,9 @@ find_library(ZSTD_LIBRARY_RELEASE
PATHS ${CONAN_LIB_DIRS_RELEASE}
)
find_library(ZSTD_LIBRARY_DEBUG
- NAMES ${ZSTD_NAMES_DEBUG}
+ NAMES
+ ${ZSTD_NAMES_DEBUG}
+ ${ZSTD_NAMES}
PATHS ${CONAN_LIB_DIRS_DEBUG}
)
@@ -68,4 +72,4 @@ if (ZSTD_FOUND)
IMPORTED_LOCATION "${ZSTD_LIBRARY}")
endif()
endif()
-endif() \ No newline at end of file
+endif()
diff --git a/cmake/ONTFindModuleHelpers.cmake b/cmake/ONTFindModuleHelpers.cmake
index d795912..bcc987c 100644
--- a/cmake/ONTFindModuleHelpers.cmake
+++ b/cmake/ONTFindModuleHelpers.cmake
@@ -172,6 +172,9 @@ macro(ont_find_package_handle_library_components module_name)
if(NOT _ONT_FPWC_SKIP_PKG_CONFIG)
find_package(PkgConfig QUIET)
endif()
+ # CMake 3.17+ warns when find_package_handle_standard_args() is called with a name that doesn't
+ # match the find module name; this tells it that we really did mean to do that
+ set(FPHSA_NAME_MISMATCHED TRUE)
foreach(_comp ${_ONT_FPWC_COMPONENTS})
set(_dep_vars)
set(_dep_targets)
@@ -290,6 +293,8 @@ macro(ont_find_package_handle_library_components module_name)
"${module_name}::${_comp}")
endif()
endforeach()
+ # we need to unset it again because this is a macro, not a function
+ unset(FPHSA_NAME_MISMATCHED)
if(${module_name}_DEBUG_LIBRARIES)
list(REMOVE_DUPLICATES ${module_name}_DEBUG_LIBRARIES)
endif()
diff --git a/cmake/SignFile.cmake b/cmake/SignFile.cmake
index cfa320d..286bacc 100644
--- a/cmake/SignFile.cmake
+++ b/cmake/SignFile.cmake
@@ -24,7 +24,8 @@ elseif(WIN32)
message("Signing file... ${file_to_sign}${comment}")
set(SIGN_COMMAND ${SIGNTOOL_EXE} sign "/v" "/sha1" "${MINKNOW_CODE_SIGN_IDENTITY}"
- "/t" "http://timestamp.globalsign.com/scripts/"
+ "/tr" "http://rfc3161timestamp.globalsign.com/advanced"
+ "/td" "SHA256"
${file_to_sign}
)
@@ -32,13 +33,26 @@ else()
message(FATAL_ERROR "Cannot sign code on this platform.")
endif()
-message("Running sign command: ${SIGN_COMMAND}")
-execute_process(
- COMMAND ${SIGN_COMMAND}
- RESULT_VARIABLE result
- OUTPUT_VARIABLE output
- ERROR_VARIABLE output
-)
+set(retry_count 10)
+foreach(retry_index RANGE ${retry_count})
+ message("Running sign command: ${SIGN_COMMAND}")
+ execute_process(
+ COMMAND ${SIGN_COMMAND}
+ RESULT_VARIABLE result
+ OUTPUT_VARIABLE output
+ ERROR_VARIABLE output
+ )
+
+ if (result EQUAL 0)
+ break()
+ endif()
+
+ message(WARN "Signing failed, waiting and retrying (${retry_index}/${retry_count})")
+ execute_process(
+ COMMAND ${CMAKE_COMMAND} -E sleep 5
+ )
+
+endforeach()
if (NOT result EQUAL 0)
message(FATAL_ERROR "Could not sign file: ${result}: ${output}")
diff --git a/cmake/conan.cmake b/cmake/conan.cmake
index db9a18a..1bd1289 100644
--- a/cmake/conan.cmake
+++ b/cmake/conan.cmake
@@ -52,40 +52,49 @@ function(_get_msvc_ide_version result)
set(${result} 14 PARENT_SCOPE)
elseif(NOT MSVC_VERSION VERSION_LESS 1910 AND MSVC_VERSION VERSION_LESS 1920)
set(${result} 15 PARENT_SCOPE)
+ elseif(NOT MSVC_VERSION VERSION_LESS 1920 AND MSVC_VERSION VERSION_LESS 1930)
+ set(${result} 16 PARENT_SCOPE)
else()
message(FATAL_ERROR "Conan: Unknown MSVC compiler version [${MSVC_VERSION}]")
endif()
endfunction()
function(conan_cmake_settings result)
- message(STATUS "COMPILER " ${CMAKE_CXX_COMPILER})
- message(STATUS "COMPILER " ${CMAKE_CXX_COMPILER_ID})
- message(STATUS "VERSION " ${CMAKE_CXX_COMPILER_VERSION})
- message(STATUS "FLAGS " ${CMAKE_LANG_FLAGS})
- message(STATUS "LIB ARCH " ${CMAKE_CXX_LIBRARY_ARCHITECTURE})
- message(STATUS "BUILD TYPE " ${CMAKE_BUILD_TYPE})
- message(STATUS "GENERATOR " ${CMAKE_GENERATOR})
- message(STATUS "GENERATOR WIN64 " ${CMAKE_CL_64})
-
- message(STATUS "Conan ** WARNING** : This detection of settings from cmake is experimental and incomplete. "
- "Please check 'conan.cmake' and contribute")
+ #message(STATUS "COMPILER " ${CMAKE_CXX_COMPILER})
+ #message(STATUS "COMPILER " ${CMAKE_CXX_COMPILER_ID})
+ #message(STATUS "VERSION " ${CMAKE_CXX_COMPILER_VERSION})
+ #message(STATUS "FLAGS " ${CMAKE_LANG_FLAGS})
+ #message(STATUS "LIB ARCH " ${CMAKE_CXX_LIBRARY_ARCHITECTURE})
+ #message(STATUS "BUILD TYPE " ${CMAKE_BUILD_TYPE})
+ #message(STATUS "GENERATOR " ${CMAKE_GENERATOR})
+ #message(STATUS "GENERATOR WIN64 " ${CMAKE_CL_64})
+
+ message(STATUS "Conan: Automatic detection of conan settings from cmake")
parse_arguments(${ARGV})
- set(arch ${ARGUMENTS_ARCH})
- if(CONAN_CMAKE_MULTI)
- set(_SETTINGS -g cmake_multi)
- else()
- set(_SETTINGS -g cmake)
- endif()
if(ARGUMENTS_BUILD_TYPE)
- set(_SETTINGS ${_SETTINGS} -s build_type=${ARGUMENTS_BUILD_TYPE})
+ set(_CONAN_SETTING_BUILD_TYPE ${ARGUMENTS_BUILD_TYPE})
elseif(CMAKE_BUILD_TYPE)
- set(_SETTINGS ${_SETTINGS} -s build_type=${CMAKE_BUILD_TYPE})
+ set(_CONAN_SETTING_BUILD_TYPE ${CMAKE_BUILD_TYPE})
else()
message(FATAL_ERROR "Please specify in command line CMAKE_BUILD_TYPE (-DCMAKE_BUILD_TYPE=Release)")
endif()
+ string(TOUPPER ${_CONAN_SETTING_BUILD_TYPE} _CONAN_SETTING_BUILD_TYPE_UPPER)
+ if (_CONAN_SETTING_BUILD_TYPE_UPPER STREQUAL "DEBUG")
+ set(_CONAN_SETTING_BUILD_TYPE "Debug")
+ elseif(_CONAN_SETTING_BUILD_TYPE_UPPER STREQUAL "RELEASE")
+ set(_CONAN_SETTING_BUILD_TYPE "Release")
+ elseif(_CONAN_SETTING_BUILD_TYPE_UPPER STREQUAL "RELWITHDEBINFO")
+ set(_CONAN_SETTING_BUILD_TYPE "RelWithDebInfo")
+ elseif(_CONAN_SETTING_BUILD_TYPE_UPPER STREQUAL "MINSIZEREL")
+ set(_CONAN_SETTING_BUILD_TYPE "MinSizeRel")
+ endif()
+
+ if(ARGUMENTS_ARCH)
+ set(_CONAN_SETTING_ARCH ${ARGUMENTS_ARCH})
+ endif()
#handle -s os setting
if(CMAKE_SYSTEM_NAME)
#use default conan os setting if CMAKE_SYSTEM_NAME is not defined
@@ -93,11 +102,11 @@ function(conan_cmake_settings result)
if(${CMAKE_SYSTEM_NAME} STREQUAL "Darwin")
set(CONAN_SYSTEM_NAME Macos)
endif()
- set(CONAN_SUPPORTED_PLATFORMS Windows Linux Macos Android iOS FreeBSD)
+ set(CONAN_SUPPORTED_PLATFORMS Windows Linux Macos Android iOS FreeBSD WindowsStore)
list (FIND CONAN_SUPPORTED_PLATFORMS "${CONAN_SYSTEM_NAME}" _index)
if (${_index} GREATER -1)
#check if the cmake system is a conan supported one
- set(_SETTINGS ${_SETTINGS} -s os=${CONAN_SYSTEM_NAME})
+ set(_CONAN_SETTING_OS ${CONAN_SYSTEM_NAME})
else()
message(FATAL_ERROR "cmake system ${CONAN_SYSTEM_NAME} is not supported by conan. Use one of ${CONAN_SUPPORTED_PLATFORMS}")
endif()
@@ -114,10 +123,6 @@ function(conan_cmake_settings result)
message(FATAL_ERROR "Conan: Neither C or C++ was detected as a language for the project. Unabled to detect compiler version.")
endif()
- if(arch)
- set(_SETTINGS ${_SETTINGS} -s arch=${arch})
- endif()
-
if (${CMAKE_${LANGUAGE}_COMPILER_ID} STREQUAL GNU)
# using GCC
# TODO: Handle other params
@@ -128,72 +133,74 @@ function(conan_cmake_settings result)
if(${MAJOR} GREATER 4)
set(COMPILER_VERSION ${MAJOR})
endif()
- set(_SETTINGS ${_SETTINGS} -s compiler=gcc -s compiler.version=${COMPILER_VERSION})
+ set(_CONAN_SETTING_COMPILER gcc)
+ set(_CONAN_SETTING_COMPILER_VERSION ${COMPILER_VERSION})
if (USING_CXX)
- conan_cmake_detect_gnu_libcxx(_LIBCXX)
- set(_SETTINGS ${_SETTINGS} -s compiler.libcxx=${_LIBCXX})
+ conan_cmake_detect_unix_libcxx(_LIBCXX)
+ set(_CONAN_SETTING_COMPILER_LIBCXX ${_LIBCXX})
endif ()
elseif (${CMAKE_${LANGUAGE}_COMPILER_ID} STREQUAL AppleClang)
# using AppleClang
string(REPLACE "." ";" VERSION_LIST ${CMAKE_${LANGUAGE}_COMPILER_VERSION})
list(GET VERSION_LIST 0 MAJOR)
list(GET VERSION_LIST 1 MINOR)
- set(_SETTINGS ${_SETTINGS} -s compiler=apple-clang -s compiler.version=${MAJOR}.${MINOR})
+ set(_CONAN_SETTING_COMPILER apple-clang)
+ set(_CONAN_SETTING_COMPILER_VERSION ${MAJOR}.${MINOR})
if (USING_CXX)
- set(_SETTINGS ${_SETTINGS} -s compiler.libcxx=libc++)
+ conan_cmake_detect_unix_libcxx(_LIBCXX)
+ set(_CONAN_SETTING_COMPILER_LIBCXX ${_LIBCXX})
endif ()
elseif (${CMAKE_${LANGUAGE}_COMPILER_ID} STREQUAL Clang)
string(REPLACE "." ";" VERSION_LIST ${CMAKE_${LANGUAGE}_COMPILER_VERSION})
list(GET VERSION_LIST 0 MAJOR)
list(GET VERSION_LIST 1 MINOR)
+ set(_CONAN_SETTING_COMPILER clang)
+ set(_CONAN_SETTING_COMPILER_VERSION ${MAJOR}.${MINOR})
if(APPLE)
cmake_policy(GET CMP0025 APPLE_CLANG_POLICY_ENABLED)
if(NOT APPLE_CLANG_POLICY_ENABLED)
message(STATUS "Conan: APPLE and Clang detected. Assuming apple-clang compiler. Set CMP0025 to avoid it")
- set(_SETTINGS ${_SETTINGS} -s compiler=apple-clang -s compiler.version=${MAJOR}.${MINOR})
- else()
- set(_SETTINGS ${_SETTINGS} -s compiler=clang -s compiler.version=${MAJOR}.${MINOR})
+ set(_CONAN_SETTING_COMPILER apple-clang)
endif()
- if (USING_CXX)
- set(_SETTINGS ${_SETTINGS} -s compiler.libcxx=libc++)
- endif ()
- else()
- set(_SETTINGS ${_SETTINGS} -s compiler=clang -s compiler.version=${MAJOR}.${MINOR})
- if (USING_CXX)
- conan_cmake_detect_gnu_libcxx(_LIBCXX)
- set(_SETTINGS ${_SETTINGS} -s compiler.libcxx=${_LIBCXX})
- endif ()
endif()
+ if(${_CONAN_SETTING_COMPILER} STREQUAL clang AND ${MAJOR} GREATER 7)
+ set(_CONAN_SETTING_COMPILER_VERSION ${MAJOR})
+ endif()
+ if (USING_CXX)
+ conan_cmake_detect_unix_libcxx(_LIBCXX)
+ set(_CONAN_SETTING_COMPILER_LIBCXX ${_LIBCXX})
+ endif ()
elseif(${CMAKE_${LANGUAGE}_COMPILER_ID} STREQUAL MSVC)
set(_VISUAL "Visual Studio")
_get_msvc_ide_version(_VISUAL_VERSION)
if("${_VISUAL_VERSION}" STREQUAL "")
message(FATAL_ERROR "Conan: Visual Studio not recognized")
else()
- set(_SETTINGS ${_SETTINGS} -s compiler=${_VISUAL} -s compiler.version=${_VISUAL_VERSION})
+ set(_CONAN_SETTING_COMPILER ${_VISUAL})
+ set(_CONAN_SETTING_COMPILER_VERSION ${_VISUAL_VERSION})
endif()
- if(NOT arch)
+ if(NOT _CONAN_SETTING_ARCH)
if (MSVC_${LANGUAGE}_ARCHITECTURE_ID MATCHES "64")
- set(_SETTINGS ${_SETTINGS} -s arch=x86_64)
+ set(_CONAN_SETTING_ARCH x86_64)
elseif (MSVC_${LANGUAGE}_ARCHITECTURE_ID MATCHES "^ARM")
message(STATUS "Conan: Using default ARM architecture from MSVC")
- set(_SETTINGS ${_SETTINGS} -s arch=armv6)
+ set(_CONAN_SETTING_ARCH armv6)
elseif (MSVC_${LANGUAGE}_ARCHITECTURE_ID MATCHES "86")
- set(_SETTINGS ${_SETTINGS} -s arch=x86)
+ set(_CONAN_SETTING_ARCH x86)
else ()
message(FATAL_ERROR "Conan: Unknown MSVC architecture [${MSVC_${LANGUAGE}_ARCHITECTURE_ID}]")
endif()
endif()
conan_cmake_detect_vs_runtime(_vs_runtime)
- message(STATUS "Detected VS runtime: ${_vs_runtime}")
- set(_SETTINGS ${_SETTINGS} -s compiler.runtime=${_vs_runtime})
-
+ message(STATUS "Conan: Detected VS runtime: ${_vs_runtime}")
+ set(_CONAN_SETTING_COMPILER_RUNTIME ${_vs_runtime})
+
if (CMAKE_GENERATOR_TOOLSET)
- set(_SETTINGS ${_SETTINGS} -s compiler.toolset=${CMAKE_VS_PLATFORM_TOOLSET})
+ set(_CONAN_SETTING_COMPILER_TOOLSET ${CMAKE_VS_PLATFORM_TOOLSET})
elseif(CMAKE_VS_PLATFORM_TOOLSET AND (CMAKE_GENERATOR STREQUAL "Ninja"))
- set(_SETTINGS ${_SETTINGS} -s compiler.toolset=${CMAKE_VS_PLATFORM_TOOLSET})
+ set(_CONAN_SETTING_COMPILER_TOOLSET ${CMAKE_VS_PLATFORM_TOOLSET})
endif()
# Temp fix due to https://github.com/conan-io/cmake-conan/issues/166
elseif (${CMAKE_${LANGUAGE}_COMPILER_ID} STREQUAL Intel)
@@ -205,56 +212,113 @@ function(conan_cmake_settings result)
set(_CONAN_SETTING_COMPILER_VERSION ${COMPILER_VERSION})
set(_SETTINGS ${_SETTINGS} -s compiler=icc -s compiler.version=${COMPILER_VERSION})
if (USING_CXX)
- conan_cmake_detect_gnu_libcxx(_LIBCXX)
+ conan_cmake_detect_unix_libcxx(_LIBCXX)
set(_CONAN_SETTING_COMPILER_LIBCXX ${_LIBCXX})
endif ()
else()
message(FATAL_ERROR "Conan: compiler setup not recognized")
endif()
+ # If profile is defined it is used
+ if(CMAKE_BUILD_TYPE STREQUAL "Debug" AND ARGUMENTS_DEBUG_PROFILE)
+ set(_APPLIED_PROFILES ${ARGUMENTS_DEBUG_PROFILE})
+ elseif(CMAKE_BUILD_TYPE STREQUAL "Release" AND ARGUMENTS_RELEASE_PROFILE)
+ set(_APPLIED_PROFILES ${ARGUMENTS_RELEASE_PROFILE})
+ elseif(CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo" AND ARGUMENTS_RELWITHDEBINFO_PROFILE)
+ set(_APPLIED_PROFILES ${ARGUMENTS_RELWITHDEBINFO_PROFILE})
+ elseif(CMAKE_BUILD_TYPE STREQUAL "MinSizeRel" AND ARGUMENTS_MINSIZEREL_PROFILE)
+ set(_APPLIED_PROFILES ${ARGUMENTS_MINSIZEREL_PROFILE})
+ elseif(ARGUMENTS_PROFILE)
+ set(_APPLIED_PROFILES ${ARGUMENTS_PROFILE})
+ endif()
+
+ foreach(ARG ${_APPLIED_PROFILES})
+ set(_SETTINGS ${_SETTINGS} -pr ${ARG})
+ endforeach()
+
+ if(NOT _SETTINGS OR ARGUMENTS_PROFILE_AUTO STREQUAL "ALL")
+ set(ARGUMENTS_PROFILE_AUTO arch build_type compiler compiler.version
+ compiler.runtime compiler.libcxx compiler.toolset)
+ endif()
+
+ # Automatic from CMake
+ foreach(ARG ${ARGUMENTS_PROFILE_AUTO})
+ string(TOUPPER ${ARG} _arg_name)
+ string(REPLACE "." "_" _arg_name ${_arg_name})
+ if(_CONAN_SETTING_${_arg_name})
+ set(_SETTINGS ${_SETTINGS} -s ${ARG}=${_CONAN_SETTING_${_arg_name}})
+ endif()
+ endforeach()
+
foreach(ARG ${ARGUMENTS_SETTINGS})
set(_SETTINGS ${_SETTINGS} -s ${ARG})
endforeach()
+ message(STATUS "Conan: Settings= ${_SETTINGS}")
+
set(${result} ${_SETTINGS} PARENT_SCOPE)
endfunction()
-function(conan_cmake_detect_gnu_libcxx result)
- # Allow -D_GLIBCXX_USE_CXX11_ABI=ON/OFF as argument to cmake
- if(DEFINED _GLIBCXX_USE_CXX11_ABI)
- if(_GLIBCXX_USE_CXX11_ABI)
- set(${result} libstdc++11 PARENT_SCOPE)
- return()
- else()
- set(${result} libstdc++ PARENT_SCOPE)
- return()
+function(conan_cmake_detect_unix_libcxx result)
+ set(compile_options)
+
+ # Take into account any -stdlib in compile options
+ get_directory_property(options DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} COMPILE_OPTIONS)
+ foreach(option ${options})
+ if(option MATCHES "^-std")
+ set(compile_options ${compile_options} "${option}")
endif()
- endif()
+ endforeach()
- # Check if there's any add_definitions(-D_GLIBCXX_USE_CXX11_ABI=0)
+ # Take into account any _GLIBCXX_USE_CXX11_ABI in compile definitions
get_directory_property(defines DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} COMPILE_DEFINITIONS)
foreach(define ${defines})
- if(define STREQUAL "_GLIBCXX_USE_CXX11_ABI=0")
- set(${result} libstdc++ PARENT_SCOPE)
- return()
+ if(define MATCHES "_GLIBCXX_USE_CXX11_ABI")
+ if(define MATCHES "^-D")
+ set(compile_options ${compile_options} "${define}")
+ else()
+ set(compile_options ${compile_options} "-D${define}")
+ endif()
endif()
endforeach()
- # Use C++11 stdlib as default if gcc is 5.1+
- if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS "5.1")
- set(${result} libstdc++ PARENT_SCOPE)
+ execute_process(
+ COMMAND ${CMAKE_COMMAND} -E echo "#include <string>"
+ COMMAND ${CMAKE_CXX_COMPILER} -x c++ ${compile_options} -E -dM -
+ OUTPUT_VARIABLE string_defines
+ )
+
+ if(string_defines MATCHES "#define __GLIBCXX__")
+ # Allow -D_GLIBCXX_USE_CXX11_ABI=ON/OFF as argument to cmake
+ if(DEFINED _GLIBCXX_USE_CXX11_ABI)
+ if(_GLIBCXX_USE_CXX11_ABI)
+ set(${result} libstdc++11 PARENT_SCOPE)
+ return()
+ else()
+ set(${result} libstdc++ PARENT_SCOPE)
+ return()
+ endif()
+ endif()
+
+ if(string_defines MATCHES "#define _GLIBCXX_USE_CXX11_ABI 1\n")
+ set(${result} libstdc++11 PARENT_SCOPE)
+ else()
+ # Either the compiler is missing the define because it is old, and so
+ # it can't use the new abi, or the compiler was configured to use the
+ # old abi by the user or distro (e.g. devtoolset on RHEL/CentOS)
+ set(${result} libstdc++ PARENT_SCOPE)
+ endif()
else()
- set(${result} libstdc++11 PARENT_SCOPE)
+ set(${result} libc++ PARENT_SCOPE)
endif()
endfunction()
-
function(conan_cmake_detect_vs_runtime result)
string(TOUPPER ${CMAKE_BUILD_TYPE} build_type)
set(variables CMAKE_CXX_FLAGS_${build_type} CMAKE_C_FLAGS_${build_type} CMAKE_CXX_FLAGS CMAKE_C_FLAGS)
foreach(variable ${variables})
- string(REPLACE " " ";" flags ${${variable}})
+ string(REPLACE " " ";" flags "${${variable}}")
foreach (flag ${flags})
if(${flag} STREQUAL "/MD" OR ${flag} STREQUAL "/MDd" OR ${flag} STREQUAL "/MT" OR ${flag} STREQUAL "/MTd")
string(SUBSTRING ${flag} 1 -1 runtime)
@@ -272,10 +336,12 @@ endfunction()
macro(parse_arguments)
- set(options BASIC_SETUP CMAKE_TARGETS UPDATE KEEP_RPATHS NO_OUTPUT_DIRS)
- set(oneValueArgs CONANFILE DEBUG_PROFILE RELEASE_PROFILE RELWITHDEBINFO_PROFILE MINSIZEREL_PROFILE PROFILE ARCH BUILD_TYPE)
- set(multiValueArgs REQUIRES OPTIONS IMPORTS SETTINGS BUILD CONAN_COMMAND)
- cmake_parse_arguments(ARGUMENTS "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN} )
+ set(options BASIC_SETUP CMAKE_TARGETS UPDATE KEEP_RPATHS NO_LOAD NO_OUTPUT_DIRS OUTPUT_QUIET NO_IMPORTS)
+ set(oneValueArgs CONANFILE ARCH BUILD_TYPE INSTALL_FOLDER CONAN_COMMAND)
+ set(multiValueArgs DEBUG_PROFILE RELEASE_PROFILE RELWITHDEBINFO_PROFILE MINSIZEREL_PROFILE
+ PROFILE REQUIRES OPTIONS IMPORTS SETTINGS BUILD ENV GENERATORS PROFILE_AUTO
+ INSTALL_ARGS)
+ cmake_parse_arguments(ARGUMENTS "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
endmacro()
function(conan_cmake_install)
@@ -286,6 +352,12 @@ function(conan_cmake_install)
# cmake does not identify conan as command, even if it is +x and it is in the path
parse_arguments(${ARGV})
+ if(CONAN_CMAKE_MULTI)
+ set(ARGUMENTS_GENERATORS ${ARGUMENTS_GENERATORS} cmake_multi)
+ else()
+ set(ARGUMENTS_GENERATORS ${ARGUMENTS_GENERATORS} cmake)
+ endif()
+
set(CONAN_BUILD_POLICY "")
foreach(ARG ${ARGUMENTS_BUILD})
if(${ARG} STREQUAL "all")
@@ -305,37 +377,43 @@ function(conan_cmake_install)
set(CONANFILE ${CMAKE_CURRENT_SOURCE_DIR}/${ARGUMENTS_CONANFILE})
# A conan file has been specified - apply specified options as well if provided
foreach(ARG ${ARGUMENTS_OPTIONS})
- set(CONAN_OPTIONS ${CONAN_OPTIONS} -o ${ARG})
+ set(CONAN_OPTIONS ${CONAN_OPTIONS} -o=${ARG})
endforeach()
else()
set(CONANFILE ".")
endif()
- if(CMAKE_BUILD_TYPE STREQUAL "Debug" AND ARGUMENTS_DEBUG_PROFILE)
- set(settings -pr ${ARGUMENTS_DEBUG_PROFILE})
- endif()
- if(CMAKE_BUILD_TYPE STREQUAL "Release" AND ARGUMENTS_RELEASE_PROFILE)
- set(settings -pr ${ARGUMENTS_RELEASE_PROFILE})
- endif()
- if(CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo" AND ARGUMENTS_RELWITHDEBINFO_PROFILE)
- set(settings -pr ${ARGUMENTS_RELWITHDEBINFO_PROFILE})
- endif()
- if(CMAKE_BUILD_TYPE STREQUAL "MinSizeRel" AND ARGUMENTS_MINSIZEREL_PROFILE)
- set(settings -pr ${ARGUMENTS_MINSIZEREL_PROFILE})
- endif()
- if(ARGUMENTS_PROFILE)
- set(settings -pr ${ARGUMENTS_PROFILE})
- endif()
if(ARGUMENTS_UPDATE)
set(CONAN_INSTALL_UPDATE --update)
endif()
- set(conan_args install ${CONANFILE} ${settings} ${CONAN_BUILD_POLICY} ${CONAN_INSTALL_UPDATE} ${CONAN_OPTIONS})
+ if(ARGUMENTS_NO_IMPORTS)
+ set(CONAN_INSTALL_NO_IMPORTS --no-imports)
+ endif()
+ set(CONAN_INSTALL_FOLDER "")
+ if(ARGUMENTS_INSTALL_FOLDER)
+ set(CONAN_INSTALL_FOLDER -if=${ARGUMENTS_INSTALL_FOLDER})
+ endif()
+ foreach(ARG ${ARGUMENTS_GENERATORS})
+ set(CONAN_GENERATORS ${CONAN_GENERATORS} -g=${ARG})
+ endforeach()
+ foreach(ARG ${ARGUMENTS_ENV})
+ set(CONAN_ENV_VARS ${CONAN_ENV_VARS} -e=${ARG})
+ endforeach()
+ set(conan_args install ${CONANFILE} ${settings} ${CONAN_ENV_VARS} ${CONAN_GENERATORS} ${CONAN_BUILD_POLICY} ${CONAN_INSTALL_UPDATE} ${CONAN_INSTALL_NO_IMPORTS} ${CONAN_OPTIONS} ${CONAN_INSTALL_FOLDER} ${ARGUMENTS_INSTALL_ARGS})
string (REPLACE ";" " " _conan_args "${conan_args}")
message(STATUS "Conan executing: ${conan_command} ${_conan_args}")
- execute_process(COMMAND ${conan_command} ${conan_args}
- RESULT_VARIABLE return_code
- WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
+ if(ARGUMENTS_OUTPUT_QUIET)
+ execute_process(COMMAND ${conan_command} ${conan_args}
+ RESULT_VARIABLE return_code
+ OUTPUT_VARIABLE conan_output
+ ERROR_VARIABLE conan_output
+ WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
+ else()
+ execute_process(COMMAND ${conan_command} ${conan_args}
+ RESULT_VARIABLE return_code
+ WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
+ endif()
if(NOT "${return_code}" STREQUAL "0")
message(FATAL_ERROR "Conan install failed='${return_code}'")
@@ -347,9 +425,10 @@ endfunction()
function(conan_cmake_setup_conanfile)
parse_arguments(${ARGV})
if(ARGUMENTS_CONANFILE)
+ get_filename_component(_CONANFILE_NAME ${ARGUMENTS_CONANFILE} NAME)
# configure_file will make sure cmake re-runs when conanfile is updated
- configure_file(${ARGUMENTS_CONANFILE} ${ARGUMENTS_CONANFILE}.junk)
- file(REMOVE ${CMAKE_CURRENT_BINARY_DIR}/${ARGUMENTS_CONANFILE}.junk)
+ configure_file(${ARGUMENTS_CONANFILE} ${CMAKE_CURRENT_BINARY_DIR}/${_CONANFILE_NAME}.junk)
+ file(REMOVE ${CMAKE_CURRENT_BINARY_DIR}/${_CONANFILE_NAME}.junk)
else()
conan_cmake_generate_conanfile(${ARGV})
endif()
@@ -385,11 +464,16 @@ macro(conan_load_buildinfo)
else()
set(_CONANBUILDINFO conanbuildinfo.cmake)
endif()
+ if(ARGUMENTS_INSTALL_FOLDER)
+ set(_CONANBUILDINFOFOLDER ${ARGUMENTS_INSTALL_FOLDER})
+ else()
+ set(_CONANBUILDINFOFOLDER ${CMAKE_CURRENT_BINARY_DIR})
+ endif()
# Checks for the existence of conanbuildinfo.cmake, and loads it
# important that it is macro, so variables defined at parent scope
- if(EXISTS "${CMAKE_CURRENT_BINARY_DIR}/${_CONANBUILDINFO}")
+ if(EXISTS "${_CONANBUILDINFOFOLDER}/${_CONANBUILDINFO}")
message(STATUS "Conan: Loading ${_CONANBUILDINFO}")
- include(${CMAKE_CURRENT_BINARY_DIR}/${_CONANBUILDINFO})
+ include(${_CONANBUILDINFOFOLDER}/${_CONANBUILDINFO})
else()
message(FATAL_ERROR "${_CONANBUILDINFO} doesn't exist in ${CMAKE_CURRENT_BINARY_DIR}")
endif()
@@ -399,16 +483,19 @@ endmacro()
macro(conan_cmake_run)
parse_arguments(${ARGV})
- if(CMAKE_CONFIGURATION_TYPES AND NOT CMAKE_BUILD_TYPE AND NOT CONAN_EXPORTED)
+ if(CMAKE_CONFIGURATION_TYPES AND NOT CMAKE_BUILD_TYPE AND NOT CONAN_EXPORTED
+ AND NOT ARGUMENTS_BUILD_TYPE)
set(CONAN_CMAKE_MULTI ON)
message(STATUS "Conan: Using cmake-multi generator")
else()
set(CONAN_CMAKE_MULTI OFF)
endif()
+
if(NOT CONAN_EXPORTED)
conan_cmake_setup_conanfile(${ARGV})
if(CONAN_CMAKE_MULTI)
foreach(CMAKE_BUILD_TYPE "Release" "Debug")
+ set(ENV{CONAN_IMPORT_PATH} ${CMAKE_BUILD_TYPE})
conan_cmake_settings(settings ${ARGV})
conan_cmake_install(SETTINGS ${settings} ${ARGV})
endforeach()
@@ -419,7 +506,9 @@ macro(conan_cmake_run)
endif()
endif()
- conan_load_buildinfo()
+ if (NOT ARGUMENTS_NO_LOAD)
+ conan_load_buildinfo()
+ endif()
if(ARGUMENTS_BASIC_SETUP)
foreach(_option CMAKE_TARGETS KEEP_RPATHS NO_OUTPUT_DIRS)
@@ -434,3 +523,52 @@ macro(conan_cmake_run)
conan_basic_setup(${_setup_options})
endif()
endmacro()
+
+macro(conan_check)
+ # Checks conan availability in PATH
+ # Arguments REQUIRED and VERSION are optional
+ # Example usage:
+ # conan_check(VERSION 1.0.0 REQUIRED)
+ message(STATUS "Conan: checking conan executable in path")
+ set(options REQUIRED)
+ set(oneValueArgs VERSION)
+ cmake_parse_arguments(CONAN "${options}" "${oneValueArgs}" "" ${ARGN})
+
+ find_program(CONAN_CMD conan)
+ if(NOT CONAN_CMD AND CONAN_REQUIRED)
+ message(FATAL_ERROR "Conan executable not found!")
+ endif()
+ message(STATUS "Conan: Found program ${CONAN_CMD}")
+ execute_process(COMMAND ${CONAN_CMD} --version
+ OUTPUT_VARIABLE CONAN_VERSION_OUTPUT
+ ERROR_VARIABLE CONAN_VERSION_OUTPUT)
+ message(STATUS "Conan: Version found ${CONAN_VERSION_OUTPUT}")
+
+ if(DEFINED CONAN_VERSION)
+ string(REGEX MATCH ".*Conan version ([0-9]+\.[0-9]+\.[0-9]+)" FOO
+ "${CONAN_VERSION_OUTPUT}")
+ if(${CMAKE_MATCH_1} VERSION_LESS ${CONAN_VERSION})
+ message(FATAL_ERROR "Conan outdated. Installed: ${CMAKE_MATCH_1}, \
+ required: ${CONAN_VERSION}. Consider updating via 'pip \
+ install conan==${CONAN_VERSION}'.")
+ endif()
+ endif()
+endmacro()
+
+macro(conan_add_remote)
+ # Adds a remote
+ # Arguments URL and NAME are required, INDEX is optional
+ # Example usage:
+ # conan_add_remote(NAME bincrafters INDEX 1
+ # URL https://api.bintray.com/conan/bincrafters/public-conan)
+ set(oneValueArgs URL NAME INDEX)
+ cmake_parse_arguments(CONAN "" "${oneValueArgs}" "" ${ARGN})
+
+ if(DEFINED CONAN_INDEX)
+ set(CONAN_INDEX_ARG "-i ${CONAN_INDEX}")
+ endif()
+
+ message(STATUS "Conan: Adding ${CONAN_NAME} remote repository (${CONAN_URL})")
+ execute_process(COMMAND ${CONAN_CMD} remote add ${CONAN_NAME} ${CONAN_URL}
+ ${CONAN_INDEX_ARG} -f)
+endmacro()
diff --git a/python/test/requirements_1.10.txt b/python/test/requirements_1.10.txt
index 0146f57..e1195fe 100644
--- a/python/test/requirements_1.10.txt
+++ b/python/test/requirements_1.10.txt
@@ -1 +1,4 @@
-h5py==2.9.0 \ No newline at end of file
+# h5py 2 support was dropped in Python 3.9
+h5py==2.10.0
+# numpy 1.18.5 is the last version that supports Python 3.5
+numpy==1.18.5
diff --git a/python/test/requirements_1.12.txt b/python/test/requirements_1.12.txt
new file mode 100644
index 0000000..b46db0d
--- /dev/null
+++ b/python/test/requirements_1.12.txt
@@ -0,0 +1,2 @@
+# Originally built against Python 3.9
+h5py==3.6.0
diff --git a/third_party/catch2/catch.hpp b/third_party/catch2/catch.hpp
index b1b2411..db1fed3 100644
--- a/third_party/catch2/catch.hpp
+++ b/third_party/catch2/catch.hpp
@@ -1,9 +1,9 @@
/*
- * Catch v2.5.0
- * Generated: 2018-11-26 20:46:12.165372
+ * Catch v2.13.8
+ * Generated: 2022-01-03 21:20:09.589503
* ----------------------------------------------------------
* This file has been merged from multiple headers. Please don't edit it directly
- * Copyright (c) 2018 Two Blue Cubes Ltd. All rights reserved.
+ * Copyright (c) 2022 Two Blue Cubes Ltd. All rights reserved.
*
* Distributed under the Boost Software License, Version 1.0. (See accompanying
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -14,8 +14,8 @@
#define CATCH_VERSION_MAJOR 2
-#define CATCH_VERSION_MINOR 5
-#define CATCH_VERSION_PATCH 0
+#define CATCH_VERSION_MINOR 13
+#define CATCH_VERSION_PATCH 8
#ifdef __clang__
# pragma clang system_header
@@ -36,10 +36,11 @@
# pragma clang diagnostic ignored "-Wcovered-switch-default"
# endif
#elif defined __GNUC__
- // GCC likes to warn on REQUIREs, and we cannot suppress them
- // locally because g++'s support for _Pragma is lacking in older,
- // still supported, versions
-# pragma GCC diagnostic ignored "-Wparentheses"
+ // Because REQUIREs trigger GCC's -Wparentheses, and because still
+ // supported version of g++ have only buggy support for _Pragmas,
+ // Wparentheses have to be suppressed globally.
+# pragma GCC diagnostic ignored "-Wparentheses" // See #674 for details
+
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wunused-variable"
# pragma GCC diagnostic ignored "-Wpadded"
@@ -65,13 +66,16 @@
#if !defined(CATCH_CONFIG_IMPL_ONLY)
// start catch_platform.h
+// See e.g.:
+// https://opensource.apple.com/source/CarbonHeaders/CarbonHeaders-18.1/TargetConditionals.h.auto.html
#ifdef __APPLE__
-# include <TargetConditionals.h>
-# if TARGET_OS_OSX == 1
-# define CATCH_PLATFORM_MAC
-# elif TARGET_OS_IPHONE == 1
-# define CATCH_PLATFORM_IPHONE
-# endif
+# include <TargetConditionals.h>
+# if (defined(TARGET_OS_OSX) && TARGET_OS_OSX == 1) || \
+ (defined(TARGET_OS_MAC) && TARGET_OS_MAC == 1)
+# define CATCH_PLATFORM_MAC
+# elif (defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE == 1)
+# define CATCH_PLATFORM_IPHONE
+# endif
#elif defined(linux) || defined(__linux) || defined(__linux__)
# define CATCH_PLATFORM_LINUX
@@ -131,30 +135,51 @@ namespace Catch {
#endif
-#if defined(CATCH_CPP17_OR_GREATER)
-# define CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS
+// Only GCC compiler should be used in this block, so other compilers trying to
+// mask themselves as GCC should be ignored.
+#if defined(__GNUC__) && !defined(__clang__) && !defined(__ICC) && !defined(__CUDACC__) && !defined(__LCC__)
+# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION _Pragma( "GCC diagnostic push" )
+# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION _Pragma( "GCC diagnostic pop" )
+
+# define CATCH_INTERNAL_IGNORE_BUT_WARN(...) (void)__builtin_constant_p(__VA_ARGS__)
+
#endif
-#ifdef __clang__
+#if defined(__clang__)
-# define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
- _Pragma( "clang diagnostic push" ) \
- _Pragma( "clang diagnostic ignored \"-Wexit-time-destructors\"" ) \
- _Pragma( "clang diagnostic ignored \"-Wglobal-constructors\"")
-# define CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS \
- _Pragma( "clang diagnostic pop" )
-
-# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \
- _Pragma( "clang diagnostic push" ) \
- _Pragma( "clang diagnostic ignored \"-Wparentheses\"" )
-# define CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS \
- _Pragma( "clang diagnostic pop" )
-
-# define CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS \
- _Pragma( "clang diagnostic push" ) \
- _Pragma( "clang diagnostic ignored \"-Wunused-variable\"" )
-# define CATCH_INTERNAL_UNSUPPRESS_UNUSED_WARNINGS \
- _Pragma( "clang diagnostic pop" )
+# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION _Pragma( "clang diagnostic push" )
+# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION _Pragma( "clang diagnostic pop" )
+
+// As of this writing, IBM XL's implementation of __builtin_constant_p has a bug
+// which results in calls to destructors being emitted for each temporary,
+// without a matching initialization. In practice, this can result in something
+// like `std::string::~string` being called on an uninitialized value.
+//
+// For example, this code will likely segfault under IBM XL:
+// ```
+// REQUIRE(std::string("12") + "34" == "1234")
+// ```
+//
+// Therefore, `CATCH_INTERNAL_IGNORE_BUT_WARN` is not implemented.
+# if !defined(__ibmxl__) && !defined(__CUDACC__)
+# define CATCH_INTERNAL_IGNORE_BUT_WARN(...) (void)__builtin_constant_p(__VA_ARGS__) /* NOLINT(cppcoreguidelines-pro-type-vararg, hicpp-vararg) */
+# endif
+
+# define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
+ _Pragma( "clang diagnostic ignored \"-Wexit-time-destructors\"" ) \
+ _Pragma( "clang diagnostic ignored \"-Wglobal-constructors\"")
+
+# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \
+ _Pragma( "clang diagnostic ignored \"-Wparentheses\"" )
+
+# define CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS \
+ _Pragma( "clang diagnostic ignored \"-Wunused-variable\"" )
+
+# define CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS \
+ _Pragma( "clang diagnostic ignored \"-Wgnu-zero-variadic-macro-arguments\"" )
+
+# define CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \
+ _Pragma( "clang diagnostic ignored \"-Wunused-template\"" )
#endif // __clang__
@@ -179,6 +204,7 @@ namespace Catch {
// Android somehow still does not support std::to_string
#if defined(__ANDROID__)
# define CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING
+# define CATCH_INTERNAL_CONFIG_ANDROID_LOGWRITE
#endif
////////////////////////////////////////////////////////////////////////////////
@@ -203,20 +229,16 @@ namespace Catch {
// some versions of cygwin (most) do not support std::to_string. Use the libstd check.
// https://gcc.gnu.org/onlinedocs/gcc-4.8.2/libstdc++/api/a01053_source.html line 2812-2813
# if !((__cplusplus >= 201103L) && defined(_GLIBCXX_USE_C99) \
- && !defined(_GLIBCXX_HAVE_BROKEN_VSWPRINTF))
+ && !defined(_GLIBCXX_HAVE_BROKEN_VSWPRINTF))
-# define CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING
+# define CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING
# endif
#endif // __CYGWIN__
////////////////////////////////////////////////////////////////////////////////
// Visual C++
-#ifdef _MSC_VER
-
-# if _MSC_VER >= 1900 // Visual Studio 2015 or newer
-# define CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS
-# endif
+#if defined(_MSC_VER)
// Universal Windows platform does not support SEH
// Or console colours (or console at all...)
@@ -226,13 +248,25 @@ namespace Catch {
# define CATCH_INTERNAL_CONFIG_WINDOWS_SEH
# endif
+# if !defined(__clang__) // Handle Clang masquerading for msvc
+
// MSVC traditional preprocessor needs some workaround for __VA_ARGS__
// _MSVC_TRADITIONAL == 0 means new conformant preprocessor
// _MSVC_TRADITIONAL == 1 means old traditional non-conformant preprocessor
-# if !defined(_MSVC_TRADITIONAL) || (defined(_MSVC_TRADITIONAL) && _MSVC_TRADITIONAL)
-# define CATCH_INTERNAL_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
-# endif
+# if !defined(_MSVC_TRADITIONAL) || (defined(_MSVC_TRADITIONAL) && _MSVC_TRADITIONAL)
+# define CATCH_INTERNAL_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
+# endif // MSVC_TRADITIONAL
+
+// Only do this if we're not using clang on Windows, which uses `diagnostic push` & `diagnostic pop`
+# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION __pragma( warning(push) )
+# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION __pragma( warning(pop) )
+# endif // __clang__
+
+#endif // _MSC_VER
+#if defined(_REENTRANT) || defined(_MSC_VER)
+// Enable async processing, as -pthread is specified or no additional linking is required
+# define CATCH_INTERNAL_CONFIG_USE_ASYNC
#endif // _MSC_VER
////////////////////////////////////////////////////////////////////////////////
@@ -265,30 +299,56 @@ namespace Catch {
#endif
////////////////////////////////////////////////////////////////////////////////
-// Check if string_view is available and usable
-// The check is split apart to work around v140 (VS2015) preprocessor issue...
-#if defined(__has_include)
-#if __has_include(<string_view>) && defined(CATCH_CPP17_OR_GREATER)
-# define CATCH_INTERNAL_CONFIG_CPP17_STRING_VIEW
+
+// RTX is a special version of Windows that is real time.
+// This means that it is detected as Windows, but does not provide
+// the same set of capabilities as real Windows does.
+#if defined(UNDER_RTSS) || defined(RTX64_BUILD)
+ #define CATCH_INTERNAL_CONFIG_NO_WINDOWS_SEH
+ #define CATCH_INTERNAL_CONFIG_NO_ASYNC
+ #define CATCH_CONFIG_COLOUR_NONE
#endif
+
+#if !defined(_GLIBCXX_USE_C99_MATH_TR1)
+#define CATCH_INTERNAL_CONFIG_GLOBAL_NEXTAFTER
#endif
-////////////////////////////////////////////////////////////////////////////////
-// Check if variant is available and usable
+// Various stdlib support checks that require __has_include
#if defined(__has_include)
-# if __has_include(<variant>) && defined(CATCH_CPP17_OR_GREATER)
-# if defined(__clang__) && (__clang_major__ < 8)
- // work around clang bug with libstdc++ https://bugs.llvm.org/show_bug.cgi?id=31852
- // fix should be in clang 8, workaround in libstdc++ 8.2
-# include <ciso646>
-# if defined(__GLIBCXX__) && defined(_GLIBCXX_RELEASE) && (_GLIBCXX_RELEASE < 9)
-# define CATCH_CONFIG_NO_CPP17_VARIANT
-# else
-# define CATCH_INTERNAL_CONFIG_CPP17_VARIANT
-# endif // defined(__GLIBCXX__) && defined(_GLIBCXX_RELEASE) && (_GLIBCXX_RELEASE < 9)
-# endif // defined(__clang__) && (__clang_major__ < 8)
-# endif // __has_include(<variant>) && defined(CATCH_CPP17_OR_GREATER)
-#endif // __has_include
+ // Check if string_view is available and usable
+ #if __has_include(<string_view>) && defined(CATCH_CPP17_OR_GREATER)
+ # define CATCH_INTERNAL_CONFIG_CPP17_STRING_VIEW
+ #endif
+
+ // Check if optional is available and usable
+ # if __has_include(<optional>) && defined(CATCH_CPP17_OR_GREATER)
+ # define CATCH_INTERNAL_CONFIG_CPP17_OPTIONAL
+ # endif // __has_include(<optional>) && defined(CATCH_CPP17_OR_GREATER)
+
+ // Check if byte is available and usable
+ # if __has_include(<cstddef>) && defined(CATCH_CPP17_OR_GREATER)
+ # include <cstddef>
+ # if defined(__cpp_lib_byte) && (__cpp_lib_byte > 0)
+ # define CATCH_INTERNAL_CONFIG_CPP17_BYTE
+ # endif
+ # endif // __has_include(<cstddef>) && defined(CATCH_CPP17_OR_GREATER)
+
+ // Check if variant is available and usable
+ # if __has_include(<variant>) && defined(CATCH_CPP17_OR_GREATER)
+ # if defined(__clang__) && (__clang_major__ < 8)
+ // work around clang bug with libstdc++ https://bugs.llvm.org/show_bug.cgi?id=31852
+ // fix should be in clang 8, workaround in libstdc++ 8.2
+ # include <ciso646>
+ # if defined(__GLIBCXX__) && defined(_GLIBCXX_RELEASE) && (_GLIBCXX_RELEASE < 9)
+ # define CATCH_CONFIG_NO_CPP17_VARIANT
+ # else
+ # define CATCH_INTERNAL_CONFIG_CPP17_VARIANT
+ # endif // defined(__GLIBCXX__) && defined(_GLIBCXX_RELEASE) && (_GLIBCXX_RELEASE < 9)
+ # else
+ # define CATCH_INTERNAL_CONFIG_CPP17_VARIANT
+ # endif // defined(__clang__) && (__clang_major__ < 8)
+ # endif // __has_include(<variant>) && defined(CATCH_CPP17_OR_GREATER)
+#endif // defined(__has_include)
#if defined(CATCH_INTERNAL_CONFIG_COUNTER) && !defined(CATCH_CONFIG_NO_COUNTER) && !defined(CATCH_CONFIG_COUNTER)
# define CATCH_CONFIG_COUNTER
@@ -309,8 +369,8 @@ namespace Catch {
# define CATCH_CONFIG_CPP11_TO_STRING
#endif
-#if defined(CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS) && !defined(CATCH_CONFIG_NO_CPP17_UNCAUGHT_EXCEPTIONS) && !defined(CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS)
-# define CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS
+#if defined(CATCH_INTERNAL_CONFIG_CPP17_OPTIONAL) && !defined(CATCH_CONFIG_NO_CPP17_OPTIONAL) && !defined(CATCH_CONFIG_CPP17_OPTIONAL)
+# define CATCH_CONFIG_CPP17_OPTIONAL
#endif
#if defined(CATCH_INTERNAL_CONFIG_CPP17_STRING_VIEW) && !defined(CATCH_CONFIG_NO_CPP17_STRING_VIEW) && !defined(CATCH_CONFIG_CPP17_STRING_VIEW)
@@ -321,6 +381,10 @@ namespace Catch {
# define CATCH_CONFIG_CPP17_VARIANT
#endif
+#if defined(CATCH_INTERNAL_CONFIG_CPP17_BYTE) && !defined(CATCH_CONFIG_NO_CPP17_BYTE) && !defined(CATCH_CONFIG_CPP17_BYTE)
+# define CATCH_CONFIG_CPP17_BYTE
+#endif
+
#if defined(CATCH_CONFIG_EXPERIMENTAL_REDIRECT)
# define CATCH_INTERNAL_CONFIG_NEW_CAPTURE
#endif
@@ -337,17 +401,53 @@ namespace Catch {
# define CATCH_CONFIG_POLYFILL_ISNAN
#endif
+#if defined(CATCH_INTERNAL_CONFIG_USE_ASYNC) && !defined(CATCH_INTERNAL_CONFIG_NO_ASYNC) && !defined(CATCH_CONFIG_NO_USE_ASYNC) && !defined(CATCH_CONFIG_USE_ASYNC)
+# define CATCH_CONFIG_USE_ASYNC
+#endif
+
+#if defined(CATCH_INTERNAL_CONFIG_ANDROID_LOGWRITE) && !defined(CATCH_CONFIG_NO_ANDROID_LOGWRITE) && !defined(CATCH_CONFIG_ANDROID_LOGWRITE)
+# define CATCH_CONFIG_ANDROID_LOGWRITE
+#endif
+
+#if defined(CATCH_INTERNAL_CONFIG_GLOBAL_NEXTAFTER) && !defined(CATCH_CONFIG_NO_GLOBAL_NEXTAFTER) && !defined(CATCH_CONFIG_GLOBAL_NEXTAFTER)
+# define CATCH_CONFIG_GLOBAL_NEXTAFTER
+#endif
+
+// Even if we do not think the compiler has that warning, we still have
+// to provide a macro that can be used by the code.
+#if !defined(CATCH_INTERNAL_START_WARNINGS_SUPPRESSION)
+# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION
+#endif
+#if !defined(CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION)
+# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
+#endif
#if !defined(CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS)
# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS
-# define CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS
#endif
#if !defined(CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS)
# define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS
-# define CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS
#endif
#if !defined(CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS)
# define CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS
-# define CATCH_INTERNAL_UNSUPPRESS_UNUSED_WARNINGS
+#endif
+#if !defined(CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS)
+# define CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS
+#endif
+
+// The goal of this macro is to avoid evaluation of the arguments, but
+// still have the compiler warn on problems inside...
+#if !defined(CATCH_INTERNAL_IGNORE_BUT_WARN)
+# define CATCH_INTERNAL_IGNORE_BUT_WARN(...)
+#endif
+
+#if defined(__APPLE__) && defined(__apple_build_version__) && (__clang_major__ < 10)
+# undef CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS
+#elif defined(__clang__) && (__clang_major__ < 5)
+# undef CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS
+#endif
+
+#if !defined(CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS)
+# define CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS
#endif
#if defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
@@ -407,12 +507,12 @@ namespace Catch {
line( _line )
{}
- SourceLineInfo( SourceLineInfo const& other ) = default;
- SourceLineInfo( SourceLineInfo && ) = default;
- SourceLineInfo& operator = ( SourceLineInfo const& ) = default;
- SourceLineInfo& operator = ( SourceLineInfo && ) = default;
+ SourceLineInfo( SourceLineInfo const& other ) = default;
+ SourceLineInfo& operator = ( SourceLineInfo const& ) = default;
+ SourceLineInfo( SourceLineInfo&& ) noexcept = default;
+ SourceLineInfo& operator = ( SourceLineInfo&& ) noexcept = default;
- bool empty() const noexcept;
+ bool empty() const noexcept { return file[0] == '\0'; }
bool operator == ( SourceLineInfo const& other ) const noexcept;
bool operator < ( SourceLineInfo const& other ) const noexcept;
@@ -453,9 +553,10 @@ namespace Catch {
} // end namespace Catch
#define CATCH_REGISTER_TAG_ALIAS( alias, spec ) \
+ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
namespace{ Catch::RegistrarForTagAliases INTERNAL_CATCH_UNIQUE_NAME( AutoRegisterTagAlias )( alias, spec, CATCH_INTERNAL_LINEINFO ); } \
- CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS
+ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
// end catch_tag_alias_autoregistrar.h
// start catch_test_registry.h
@@ -463,7 +564,6 @@ namespace Catch {
// start catch_interfaces_testcase.h
#include <vector>
-#include <memory>
namespace Catch {
@@ -474,8 +574,6 @@ namespace Catch {
virtual ~ITestInvoker();
};
- using ITestCasePtr = std::shared_ptr<ITestInvoker>;
-
class TestCase;
struct IConfig;
@@ -485,6 +583,7 @@ namespace Catch {
virtual std::vector<TestCase> const& getAllTestsSorted( IConfig const& config ) const = 0;
};
+ bool isThrowSafe( TestCase const& testCase, IConfig const& config );
bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config );
std::vector<TestCase> filterTests( std::vector<TestCase> const& testCases, TestSpec const& testSpec, IConfig const& config );
std::vector<TestCase> const& getAllTestCasesSorted( IConfig const& config );
@@ -497,55 +596,30 @@ namespace Catch {
#include <cstddef>
#include <string>
#include <iosfwd>
+#include <cassert>
namespace Catch {
- class StringData;
-
/// A non-owning string class (similar to the forthcoming std::string_view)
/// Note that, because a StringRef may be a substring of another string,
- /// it may not be null terminated. c_str() must return a null terminated
- /// string, however, and so the StringRef will internally take ownership
- /// (taking a copy), if necessary. In theory this ownership is not externally
- /// visible - but it does mean (substring) StringRefs should not be shared between
- /// threads.
+ /// it may not be null terminated.
class StringRef {
public:
using size_type = std::size_t;
+ using const_iterator = const char*;
private:
- friend struct StringRefTestAccess;
-
- char const* m_start;
- size_type m_size;
-
- char* m_data = nullptr;
-
- void takeOwnership();
-
static constexpr char const* const s_empty = "";
- public: // construction/ assignment
- StringRef() noexcept
- : StringRef( s_empty, 0 )
- {}
+ char const* m_start = s_empty;
+ size_type m_size = 0;
- StringRef( StringRef const& other ) noexcept
- : m_start( other.m_start ),
- m_size( other.m_size )
- {}
-
- StringRef( StringRef&& other ) noexcept
- : m_start( other.m_start ),
- m_size( other.m_size ),
- m_data( other.m_data )
- {
- other.m_data = nullptr;
- }
+ public: // construction
+ constexpr StringRef() noexcept = default;
StringRef( char const* rawChars ) noexcept;
- StringRef( char const* rawChars, size_type size ) noexcept
+ constexpr StringRef( char const* rawChars, size_type size ) noexcept
: m_start( rawChars ),
m_size( size )
{}
@@ -555,99 +629,64 @@ namespace Catch {
m_size( stdString.size() )
{}
- ~StringRef() noexcept {
- delete[] m_data;
+ explicit operator std::string() const {
+ return std::string(m_start, m_size);
}
- auto operator = ( StringRef const &other ) noexcept -> StringRef& {
- delete[] m_data;
- m_data = nullptr;
- m_start = other.m_start;
- m_size = other.m_size;
- return *this;
- }
-
- operator std::string() const;
-
- void swap( StringRef& other ) noexcept;
-
public: // operators
auto operator == ( StringRef const& other ) const noexcept -> bool;
- auto operator != ( StringRef const& other ) const noexcept -> bool;
+ auto operator != (StringRef const& other) const noexcept -> bool {
+ return !(*this == other);
+ }
- auto operator[] ( size_type index ) const noexcept -> char;
+ auto operator[] ( size_type index ) const noexcept -> char {
+ assert(index < m_size);
+ return m_start[index];
+ }
public: // named queries
- auto empty() const noexcept -> bool {
+ constexpr auto empty() const noexcept -> bool {
return m_size == 0;
}
- auto size() const noexcept -> size_type {
+ constexpr auto size() const noexcept -> size_type {
return m_size;
}
- auto numberOfCharacters() const noexcept -> size_type;
+ // Returns the current start pointer. If the StringRef is not
+ // null-terminated, throws std::domain_exception
auto c_str() const -> char const*;
public: // substrings and searches
- auto substr( size_type start, size_type size ) const noexcept -> StringRef;
+ // Returns a substring of [start, start + length).
+ // If start + length > size(), then the substring is [start, size()).
+ // If start > size(), then the substring is empty.
+ auto substr( size_type start, size_type length ) const noexcept -> StringRef;
- // Returns the current start pointer.
- // Note that the pointer can change when if the StringRef is a substring
- auto currentData() const noexcept -> char const*;
+ // Returns the current start pointer. May not be null-terminated.
+ auto data() const noexcept -> char const*;
- private: // ownership queries - may not be consistent between calls
- auto isOwned() const noexcept -> bool;
- auto isSubstring() const noexcept -> bool;
- };
+ constexpr auto isNullTerminated() const noexcept -> bool {
+ return m_start[m_size] == '\0';
+ }
- auto operator + ( StringRef const& lhs, StringRef const& rhs ) -> std::string;
- auto operator + ( StringRef const& lhs, char const* rhs ) -> std::string;
- auto operator + ( char const* lhs, StringRef const& rhs ) -> std::string;
+ public: // iterators
+ constexpr const_iterator begin() const { return m_start; }
+ constexpr const_iterator end() const { return m_start + m_size; }
+ };
auto operator += ( std::string& lhs, StringRef const& sr ) -> std::string&;
auto operator << ( std::ostream& os, StringRef const& sr ) -> std::ostream&;
- inline auto operator "" _sr( char const* rawChars, std::size_t size ) noexcept -> StringRef {
+ constexpr auto operator "" _sr( char const* rawChars, std::size_t size ) noexcept -> StringRef {
return StringRef( rawChars, size );
}
-
} // namespace Catch
-inline auto operator "" _catch_sr( char const* rawChars, std::size_t size ) noexcept -> Catch::StringRef {
+constexpr auto operator "" _catch_sr( char const* rawChars, std::size_t size ) noexcept -> Catch::StringRef {
return Catch::StringRef( rawChars, size );
}
// end catch_stringref.h
-// start catch_type_traits.hpp
-
-
-namespace Catch{
-
-#ifdef CATCH_CPP17_OR_GREATER
- template <typename...>
- inline constexpr auto is_unique = std::true_type{};
-
- template <typename T, typename... Rest>
- inline constexpr auto is_unique<T, Rest...> = std::bool_constant<
- (!std::is_same_v<T, Rest> && ...) && is_unique<Rest...>
- >{};
-#else
-
-template <typename...>
-struct is_unique : std::true_type{};
-
-template <typename T0, typename T1, typename... Rest>
-struct is_unique<T0, T1, Rest...> : std::integral_constant
-<bool,
- !std::is_same<T0, T1>::value
- && is_unique<T0, Rest...>::value
- && is_unique<T1, Rest...>::value
->{};
-
-#endif
-}
-
-// end catch_type_traits.hpp
// start catch_preprocessor.hpp
@@ -699,21 +738,224 @@ struct is_unique<T0, T1, Rest...> : std::integral_constant
#define INTERNAL_CATCH_EXPAND2(...) INTERNAL_CATCH_NO## __VA_ARGS__
#define INTERNAL_CATCH_DEF(...) INTERNAL_CATCH_DEF __VA_ARGS__
#define INTERNAL_CATCH_NOINTERNAL_CATCH_DEF
+#define INTERNAL_CATCH_STRINGIZE(...) INTERNAL_CATCH_STRINGIZE2(__VA_ARGS__)
+#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
+#define INTERNAL_CATCH_STRINGIZE2(...) #__VA_ARGS__
+#define INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS(param) INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_REMOVE_PARENS(param))
+#else
+// MSVC is adding extra space and needs another indirection to expand INTERNAL_CATCH_NOINTERNAL_CATCH_DEF
+#define INTERNAL_CATCH_STRINGIZE2(...) INTERNAL_CATCH_STRINGIZE3(__VA_ARGS__)
+#define INTERNAL_CATCH_STRINGIZE3(...) #__VA_ARGS__
+#define INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS(param) (INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_REMOVE_PARENS(param)) + 1)
+#endif
+
+#define INTERNAL_CATCH_MAKE_NAMESPACE2(...) ns_##__VA_ARGS__
+#define INTERNAL_CATCH_MAKE_NAMESPACE(name) INTERNAL_CATCH_MAKE_NAMESPACE2(name)
#define INTERNAL_CATCH_REMOVE_PARENS(...) INTERNAL_CATCH_EXPAND1(INTERNAL_CATCH_DEF __VA_ARGS__)
-#define INTERNAL_CATCH_TEMPLATE_UNIQUE_NAME2(Name, ...) INTERNAL_CATCH_TEMPLATE_UNIQUE_NAME3(Name, __VA_ARGS__)
#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
-#define INTERNAL_CATCH_TEMPLATE_UNIQUE_NAME3(Name,...) Name " - " #__VA_ARGS__
-#define INTERNAL_CATCH_TEMPLATE_UNIQUE_NAME(Name,...) INTERNAL_CATCH_TEMPLATE_UNIQUE_NAME2(Name, INTERNAL_CATCH_REMOVE_PARENS(__VA_ARGS__))
+#define INTERNAL_CATCH_MAKE_TYPE_LIST2(...) decltype(get_wrapper<INTERNAL_CATCH_REMOVE_PARENS_GEN(__VA_ARGS__)>())
+#define INTERNAL_CATCH_MAKE_TYPE_LIST(...) INTERNAL_CATCH_MAKE_TYPE_LIST2(INTERNAL_CATCH_REMOVE_PARENS(__VA_ARGS__))
#else
-// MSVC is adding extra space and needs more calls to properly remove ()
-#define INTERNAL_CATCH_TEMPLATE_UNIQUE_NAME3(Name,...) Name " -" #__VA_ARGS__
-#define INTERNAL_CATCH_TEMPLATE_UNIQUE_NAME1(Name, ...) INTERNAL_CATCH_TEMPLATE_UNIQUE_NAME2(Name, __VA_ARGS__)
-#define INTERNAL_CATCH_TEMPLATE_UNIQUE_NAME(Name, ...) INTERNAL_CATCH_TEMPLATE_UNIQUE_NAME1(Name, INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_REMOVE_PARENS(__VA_ARGS__)))
+#define INTERNAL_CATCH_MAKE_TYPE_LIST2(...) INTERNAL_CATCH_EXPAND_VARGS(decltype(get_wrapper<INTERNAL_CATCH_REMOVE_PARENS_GEN(__VA_ARGS__)>()))
+#define INTERNAL_CATCH_MAKE_TYPE_LIST(...) INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_MAKE_TYPE_LIST2(INTERNAL_CATCH_REMOVE_PARENS(__VA_ARGS__)))
+#endif
+
+#define INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES(...)\
+ CATCH_REC_LIST(INTERNAL_CATCH_MAKE_TYPE_LIST,__VA_ARGS__)
+
+#define INTERNAL_CATCH_REMOVE_PARENS_1_ARG(_0) INTERNAL_CATCH_REMOVE_PARENS(_0)
+#define INTERNAL_CATCH_REMOVE_PARENS_2_ARG(_0, _1) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_1_ARG(_1)
+#define INTERNAL_CATCH_REMOVE_PARENS_3_ARG(_0, _1, _2) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_2_ARG(_1, _2)
+#define INTERNAL_CATCH_REMOVE_PARENS_4_ARG(_0, _1, _2, _3) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_3_ARG(_1, _2, _3)
+#define INTERNAL_CATCH_REMOVE_PARENS_5_ARG(_0, _1, _2, _3, _4) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_4_ARG(_1, _2, _3, _4)
+#define INTERNAL_CATCH_REMOVE_PARENS_6_ARG(_0, _1, _2, _3, _4, _5) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_5_ARG(_1, _2, _3, _4, _5)
+#define INTERNAL_CATCH_REMOVE_PARENS_7_ARG(_0, _1, _2, _3, _4, _5, _6) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_6_ARG(_1, _2, _3, _4, _5, _6)
+#define INTERNAL_CATCH_REMOVE_PARENS_8_ARG(_0, _1, _2, _3, _4, _5, _6, _7) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_7_ARG(_1, _2, _3, _4, _5, _6, _7)
+#define INTERNAL_CATCH_REMOVE_PARENS_9_ARG(_0, _1, _2, _3, _4, _5, _6, _7, _8) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_8_ARG(_1, _2, _3, _4, _5, _6, _7, _8)
+#define INTERNAL_CATCH_REMOVE_PARENS_10_ARG(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_9_ARG(_1, _2, _3, _4, _5, _6, _7, _8, _9)
+#define INTERNAL_CATCH_REMOVE_PARENS_11_ARG(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_10_ARG(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10)
+
+#define INTERNAL_CATCH_VA_NARGS_IMPL(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, N, ...) N
+
+#define INTERNAL_CATCH_TYPE_GEN\
+ template<typename...> struct TypeList {};\
+ template<typename...Ts>\
+ constexpr auto get_wrapper() noexcept -> TypeList<Ts...> { return {}; }\
+ template<template<typename...> class...> struct TemplateTypeList{};\
+ template<template<typename...> class...Cs>\
+ constexpr auto get_wrapper() noexcept -> TemplateTypeList<Cs...> { return {}; }\
+ template<typename...>\
+ struct append;\
+ template<typename...>\
+ struct rewrap;\
+ template<template<typename...> class, typename...>\
+ struct create;\
+ template<template<typename...> class, typename>\
+ struct convert;\
+ \
+ template<typename T> \
+ struct append<T> { using type = T; };\
+ template< template<typename...> class L1, typename...E1, template<typename...> class L2, typename...E2, typename...Rest>\
+ struct append<L1<E1...>, L2<E2...>, Rest...> { using type = typename append<L1<E1...,E2...>, Rest...>::type; };\
+ template< template<typename...> class L1, typename...E1, typename...Rest>\
+ struct append<L1<E1...>, TypeList<mpl_::na>, Rest...> { using type = L1<E1...>; };\
+ \
+ template< template<typename...> class Container, template<typename...> class List, typename...elems>\
+ struct rewrap<TemplateTypeList<Container>, List<elems...>> { using type = TypeList<Container<elems...>>; };\
+ template< template<typename...> class Container, template<typename...> class List, class...Elems, typename...Elements>\
+ struct rewrap<TemplateTypeList<Container>, List<Elems...>, Elements...> { using type = typename append<TypeList<Container<Elems...>>, typename rewrap<TemplateTypeList<Container>, Elements...>::type>::type; };\
+ \
+ template<template <typename...> class Final, template< typename...> class...Containers, typename...Types>\
+ struct create<Final, TemplateTypeList<Containers...>, TypeList<Types...>> { using type = typename append<Final<>, typename rewrap<TemplateTypeList<Containers>, Types...>::type...>::type; };\
+ template<template <typename...> class Final, template <typename...> class List, typename...Ts>\
+ struct convert<Final, List<Ts...>> { using type = typename append<Final<>,TypeList<Ts>...>::type; };
+
+#define INTERNAL_CATCH_NTTP_1(signature, ...)\
+ template<INTERNAL_CATCH_REMOVE_PARENS(signature)> struct Nttp{};\
+ template<INTERNAL_CATCH_REMOVE_PARENS(signature)>\
+ constexpr auto get_wrapper() noexcept -> Nttp<__VA_ARGS__> { return {}; } \
+ template<template<INTERNAL_CATCH_REMOVE_PARENS(signature)> class...> struct NttpTemplateTypeList{};\
+ template<template<INTERNAL_CATCH_REMOVE_PARENS(signature)> class...Cs>\
+ constexpr auto get_wrapper() noexcept -> NttpTemplateTypeList<Cs...> { return {}; } \
+ \
+ template< template<INTERNAL_CATCH_REMOVE_PARENS(signature)> class Container, template<INTERNAL_CATCH_REMOVE_PARENS(signature)> class List, INTERNAL_CATCH_REMOVE_PARENS(signature)>\
+ struct rewrap<NttpTemplateTypeList<Container>, List<__VA_ARGS__>> { using type = TypeList<Container<__VA_ARGS__>>; };\
+ template< template<INTERNAL_CATCH_REMOVE_PARENS(signature)> class Container, template<INTERNAL_CATCH_REMOVE_PARENS(signature)> class List, INTERNAL_CATCH_REMOVE_PARENS(signature), typename...Elements>\
+ struct rewrap<NttpTemplateTypeList<Container>, List<__VA_ARGS__>, Elements...> { using type = typename append<TypeList<Container<__VA_ARGS__>>, typename rewrap<NttpTemplateTypeList<Container>, Elements...>::type>::type; };\
+ template<template <typename...> class Final, template<INTERNAL_CATCH_REMOVE_PARENS(signature)> class...Containers, typename...Types>\
+ struct create<Final, NttpTemplateTypeList<Containers...>, TypeList<Types...>> { using type = typename append<Final<>, typename rewrap<NttpTemplateTypeList<Containers>, Types...>::type...>::type; };
+
+#define INTERNAL_CATCH_DECLARE_SIG_TEST0(TestName)
+#define INTERNAL_CATCH_DECLARE_SIG_TEST1(TestName, signature)\
+ template<INTERNAL_CATCH_REMOVE_PARENS(signature)>\
+ static void TestName()
+#define INTERNAL_CATCH_DECLARE_SIG_TEST_X(TestName, signature, ...)\
+ template<INTERNAL_CATCH_REMOVE_PARENS(signature)>\
+ static void TestName()
+
+#define INTERNAL_CATCH_DEFINE_SIG_TEST0(TestName)
+#define INTERNAL_CATCH_DEFINE_SIG_TEST1(TestName, signature)\
+ template<INTERNAL_CATCH_REMOVE_PARENS(signature)>\
+ static void TestName()
+#define INTERNAL_CATCH_DEFINE_SIG_TEST_X(TestName, signature,...)\
+ template<INTERNAL_CATCH_REMOVE_PARENS(signature)>\
+ static void TestName()
+
+#define INTERNAL_CATCH_NTTP_REGISTER0(TestFunc, signature)\
+ template<typename Type>\
+ void reg_test(TypeList<Type>, Catch::NameAndTags nameAndTags)\
+ {\
+ Catch::AutoReg( Catch::makeTestInvoker(&TestFunc<Type>), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), nameAndTags);\
+ }
+
+#define INTERNAL_CATCH_NTTP_REGISTER(TestFunc, signature, ...)\
+ template<INTERNAL_CATCH_REMOVE_PARENS(signature)>\
+ void reg_test(Nttp<__VA_ARGS__>, Catch::NameAndTags nameAndTags)\
+ {\
+ Catch::AutoReg( Catch::makeTestInvoker(&TestFunc<__VA_ARGS__>), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), nameAndTags);\
+ }
+
+#define INTERNAL_CATCH_NTTP_REGISTER_METHOD0(TestName, signature, ...)\
+ template<typename Type>\
+ void reg_test(TypeList<Type>, Catch::StringRef className, Catch::NameAndTags nameAndTags)\
+ {\
+ Catch::AutoReg( Catch::makeTestInvoker(&TestName<Type>::test), CATCH_INTERNAL_LINEINFO, className, nameAndTags);\
+ }
+
+#define INTERNAL_CATCH_NTTP_REGISTER_METHOD(TestName, signature, ...)\
+ template<INTERNAL_CATCH_REMOVE_PARENS(signature)>\
+ void reg_test(Nttp<__VA_ARGS__>, Catch::StringRef className, Catch::NameAndTags nameAndTags)\
+ {\
+ Catch::AutoReg( Catch::makeTestInvoker(&TestName<__VA_ARGS__>::test), CATCH_INTERNAL_LINEINFO, className, nameAndTags);\
+ }
+
+#define INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD0(TestName, ClassName)
+#define INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD1(TestName, ClassName, signature)\
+ template<typename TestType> \
+ struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName)<TestType> { \
+ void test();\
+ }
+
+#define INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X(TestName, ClassName, signature, ...)\
+ template<INTERNAL_CATCH_REMOVE_PARENS(signature)> \
+ struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName)<__VA_ARGS__> { \
+ void test();\
+ }
+
+#define INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD0(TestName)
+#define INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD1(TestName, signature)\
+ template<typename TestType> \
+ void INTERNAL_CATCH_MAKE_NAMESPACE(TestName)::TestName<TestType>::test()
+#define INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X(TestName, signature, ...)\
+ template<INTERNAL_CATCH_REMOVE_PARENS(signature)> \
+ void INTERNAL_CATCH_MAKE_NAMESPACE(TestName)::TestName<__VA_ARGS__>::test()
+
+#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
+#define INTERNAL_CATCH_NTTP_0
+#define INTERNAL_CATCH_NTTP_GEN(...) INTERNAL_CATCH_VA_NARGS_IMPL(__VA_ARGS__, INTERNAL_CATCH_NTTP_1(__VA_ARGS__), INTERNAL_CATCH_NTTP_1(__VA_ARGS__), INTERNAL_CATCH_NTTP_1(__VA_ARGS__), INTERNAL_CATCH_NTTP_1(__VA_ARGS__), INTERNAL_CATCH_NTTP_1(__VA_ARGS__), INTERNAL_CATCH_NTTP_1( __VA_ARGS__), INTERNAL_CATCH_NTTP_1( __VA_ARGS__), INTERNAL_CATCH_NTTP_1( __VA_ARGS__), INTERNAL_CATCH_NTTP_1( __VA_ARGS__),INTERNAL_CATCH_NTTP_1( __VA_ARGS__), INTERNAL_CATCH_NTTP_0)
+#define INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD(TestName, ...) INTERNAL_CATCH_VA_NARGS_IMPL( "dummy", __VA_ARGS__, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD1, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD0)(TestName, __VA_ARGS__)
+#define INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD(TestName, ClassName, ...) INTERNAL_CATCH_VA_NARGS_IMPL( "dummy", __VA_ARGS__, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD1, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD0)(TestName, ClassName, __VA_ARGS__)
+#define INTERNAL_CATCH_NTTP_REG_METHOD_GEN(TestName, ...) INTERNAL_CATCH_VA_NARGS_IMPL( "dummy", __VA_ARGS__, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD0, INTERNAL_CATCH_NTTP_REGISTER_METHOD0)(TestName, __VA_ARGS__)
+#define INTERNAL_CATCH_NTTP_REG_GEN(TestFunc, ...) INTERNAL_CATCH_VA_NARGS_IMPL( "dummy", __VA_ARGS__, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER0, INTERNAL_CATCH_NTTP_REGISTER0)(TestFunc, __VA_ARGS__)
+#define INTERNAL_CATCH_DEFINE_SIG_TEST(TestName, ...) INTERNAL_CATCH_VA_NARGS_IMPL( "dummy", __VA_ARGS__, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X,INTERNAL_CATCH_DEFINE_SIG_TEST_X,INTERNAL_CATCH_DEFINE_SIG_TEST1, INTERNAL_CATCH_DEFINE_SIG_TEST0)(TestName, __VA_ARGS__)
+#define INTERNAL_CATCH_DECLARE_SIG_TEST(TestName, ...) INTERNAL_CATCH_VA_NARGS_IMPL( "dummy", __VA_ARGS__, INTERNAL_CATCH_DECLARE_SIG_TEST_X,INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X,INTERNAL_CATCH_DECLARE_SIG_TEST_X,INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DECLARE_SIG_TEST1, INTERNAL_CATCH_DECLARE_SIG_TEST0)(TestName, __VA_ARGS__)
+#define INTERNAL_CATCH_REMOVE_PARENS_GEN(...) INTERNAL_CATCH_VA_NARGS_IMPL(__VA_ARGS__, INTERNAL_CATCH_REMOVE_PARENS_11_ARG,INTERNAL_CATCH_REMOVE_PARENS_10_ARG,INTERNAL_CATCH_REMOVE_PARENS_9_ARG,INTERNAL_CATCH_REMOVE_PARENS_8_ARG,INTERNAL_CATCH_REMOVE_PARENS_7_ARG,INTERNAL_CATCH_REMOVE_PARENS_6_ARG,INTERNAL_CATCH_REMOVE_PARENS_5_ARG,INTERNAL_CATCH_REMOVE_PARENS_4_ARG,INTERNAL_CATCH_REMOVE_PARENS_3_ARG,INTERNAL_CATCH_REMOVE_PARENS_2_ARG,INTERNAL_CATCH_REMOVE_PARENS_1_ARG)(__VA_ARGS__)
+#else
+#define INTERNAL_CATCH_NTTP_0(signature)
+#define INTERNAL_CATCH_NTTP_GEN(...) INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_VA_NARGS_IMPL(__VA_ARGS__, INTERNAL_CATCH_NTTP_1, INTERNAL_CATCH_NTTP_1, INTERNAL_CATCH_NTTP_1, INTERNAL_CATCH_NTTP_1, INTERNAL_CATCH_NTTP_1, INTERNAL_CATCH_NTTP_1, INTERNAL_CATCH_NTTP_1, INTERNAL_CATCH_NTTP_1, INTERNAL_CATCH_NTTP_1,INTERNAL_CATCH_NTTP_1, INTERNAL_CATCH_NTTP_0)( __VA_ARGS__))
+#define INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD(TestName, ...) INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_VA_NARGS_IMPL( "dummy", __VA_ARGS__, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD1, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD0)(TestName, __VA_ARGS__))
+#define INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD(TestName, ClassName, ...) INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_VA_NARGS_IMPL( "dummy", __VA_ARGS__, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD1, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD0)(TestName, ClassName, __VA_ARGS__))
+#define INTERNAL_CATCH_NTTP_REG_METHOD_GEN(TestName, ...) INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_VA_NARGS_IMPL( "dummy", __VA_ARGS__, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD0, INTERNAL_CATCH_NTTP_REGISTER_METHOD0)(TestName, __VA_ARGS__))
+#define INTERNAL_CATCH_NTTP_REG_GEN(TestFunc, ...) INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_VA_NARGS_IMPL( "dummy", __VA_ARGS__, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER0, INTERNAL_CATCH_NTTP_REGISTER0)(TestFunc, __VA_ARGS__))
+#define INTERNAL_CATCH_DEFINE_SIG_TEST(TestName, ...) INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_VA_NARGS_IMPL( "dummy", __VA_ARGS__, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X,INTERNAL_CATCH_DEFINE_SIG_TEST_X,INTERNAL_CATCH_DEFINE_SIG_TEST1, INTERNAL_CATCH_DEFINE_SIG_TEST0)(TestName, __VA_ARGS__))
+#define INTERNAL_CATCH_DECLARE_SIG_TEST(TestName, ...) INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_VA_NARGS_IMPL( "dummy", __VA_ARGS__, INTERNAL_CATCH_DECLARE_SIG_TEST_X,INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X,INTERNAL_CATCH_DECLARE_SIG_TEST_X,INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DECLARE_SIG_TEST1, INTERNAL_CATCH_DECLARE_SIG_TEST0)(TestName, __VA_ARGS__))
+#define INTERNAL_CATCH_REMOVE_PARENS_GEN(...) INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_VA_NARGS_IMPL(__VA_ARGS__, INTERNAL_CATCH_REMOVE_PARENS_11_ARG,INTERNAL_CATCH_REMOVE_PARENS_10_ARG,INTERNAL_CATCH_REMOVE_PARENS_9_ARG,INTERNAL_CATCH_REMOVE_PARENS_8_ARG,INTERNAL_CATCH_REMOVE_PARENS_7_ARG,INTERNAL_CATCH_REMOVE_PARENS_6_ARG,INTERNAL_CATCH_REMOVE_PARENS_5_ARG,INTERNAL_CATCH_REMOVE_PARENS_4_ARG,INTERNAL_CATCH_REMOVE_PARENS_3_ARG,INTERNAL_CATCH_REMOVE_PARENS_2_ARG,INTERNAL_CATCH_REMOVE_PARENS_1_ARG)(__VA_ARGS__))
#endif
// end catch_preprocessor.hpp
+// start catch_meta.hpp
+
+
+#include <type_traits>
+
+namespace Catch {
+ template<typename T>
+ struct always_false : std::false_type {};
+
+ template <typename> struct true_given : std::true_type {};
+ struct is_callable_tester {
+ template <typename Fun, typename... Args>
+ true_given<decltype(std::declval<Fun>()(std::declval<Args>()...))> static test(int);
+ template <typename...>
+ std::false_type static test(...);
+ };
+
+ template <typename T>
+ struct is_callable;
+
+ template <typename Fun, typename... Args>
+ struct is_callable<Fun(Args...)> : decltype(is_callable_tester::test<Fun, Args...>(0)) {};
+
+#if defined(__cpp_lib_is_invocable) && __cpp_lib_is_invocable >= 201703
+ // std::result_of is deprecated in C++17 and removed in C++20. Hence, it is
+ // replaced with std::invoke_result here.
+ template <typename Func, typename... U>
+ using FunctionReturnType = std::remove_reference_t<std::remove_cv_t<std::invoke_result_t<Func, U...>>>;
+#else
+ // Keep ::type here because we still support C++11
+ template <typename Func, typename... U>
+ using FunctionReturnType = typename std::remove_reference<typename std::remove_cv<typename std::result_of<Func(U...)>::type>::type>::type;
+#endif
+
+} // namespace Catch
+
+namespace mpl_{
+ struct na;
+}
+
+// end catch_meta.hpp
namespace Catch {
template<typename C>
@@ -758,38 +1000,70 @@ struct AutoReg : NonCopyable {
}; \
} \
void TestName::test()
- #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION( TestName, ... ) \
- template<typename TestType> \
- static void TestName()
- #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION( TestName, ClassName, ... ) \
+ #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION_2( TestName, TestFunc, Name, Tags, Signature, ... ) \
+ INTERNAL_CATCH_DEFINE_SIG_TEST(TestFunc, INTERNAL_CATCH_REMOVE_PARENS(Signature))
+ #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION_2( TestNameClass, TestName, ClassName, Name, Tags, Signature, ... ) \
namespace{ \
- template<typename TestType> \
- struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName <TestType>) { \
- void test(); \
- }; \
+ namespace INTERNAL_CATCH_MAKE_NAMESPACE(TestName) { \
+ INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD(TestName, ClassName, INTERNAL_CATCH_REMOVE_PARENS(Signature));\
} \
- template<typename TestType> \
- void TestName::test()
+ } \
+ INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD(TestName, INTERNAL_CATCH_REMOVE_PARENS(Signature))
+
+ #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
+ #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(Name, Tags, ...) \
+ INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), Name, Tags, typename TestType, __VA_ARGS__ )
+ #else
+ #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(Name, Tags, ...) \
+ INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), Name, Tags, typename TestType, __VA_ARGS__ ) )
+ #endif
+
+ #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
+ #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG_NO_REGISTRATION(Name, Tags, Signature, ...) \
+ INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), Name, Tags, Signature, __VA_ARGS__ )
+ #else
+ #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG_NO_REGISTRATION(Name, Tags, Signature, ...) \
+ INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), Name, Tags, Signature, __VA_ARGS__ ) )
+ #endif
+
+ #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
+ #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION( ClassName, Name, Tags,... ) \
+ INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_C_L_A_S_S_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ) , ClassName, Name, Tags, typename T, __VA_ARGS__ )
+ #else
+ #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION( ClassName, Name, Tags,... ) \
+ INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_C_L_A_S_S_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ) , ClassName, Name, Tags, typename T, __VA_ARGS__ ) )
+ #endif
+
+ #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
+ #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG_NO_REGISTRATION( ClassName, Name, Tags, Signature, ... ) \
+ INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_C_L_A_S_S_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ) , ClassName, Name, Tags, Signature, __VA_ARGS__ )
+ #else
+ #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG_NO_REGISTRATION( ClassName, Name, Tags, Signature, ... ) \
+ INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_C_L_A_S_S_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ) , ClassName, Name, Tags, Signature, __VA_ARGS__ ) )
+ #endif
#endif
///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_TESTCASE2( TestName, ... ) \
static void TestName(); \
+ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( Catch::makeTestInvoker( &TestName ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ __VA_ARGS__ } ); } /* NOLINT */ \
- CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS \
+ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
static void TestName()
#define INTERNAL_CATCH_TESTCASE( ... ) \
- INTERNAL_CATCH_TESTCASE2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), __VA_ARGS__ )
+ INTERNAL_CATCH_TESTCASE2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_S_T_ ), __VA_ARGS__ )
///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, ... ) \
+ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( Catch::makeTestInvoker( &QualifiedMethod ), CATCH_INTERNAL_LINEINFO, "&" #QualifiedMethod, Catch::NameAndTags{ __VA_ARGS__ } ); } /* NOLINT */ \
- CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS
+ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_TEST_CASE_METHOD2( TestName, ClassName, ... )\
+ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
namespace{ \
struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName) { \
@@ -797,88 +1071,273 @@ struct AutoReg : NonCopyable {
}; \
Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( Catch::makeTestInvoker( &TestName::test ), CATCH_INTERNAL_LINEINFO, #ClassName, Catch::NameAndTags{ __VA_ARGS__ } ); /* NOLINT */ \
} \
- CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS \
+ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
void TestName::test()
#define INTERNAL_CATCH_TEST_CASE_METHOD( ClassName, ... ) \
- INTERNAL_CATCH_TEST_CASE_METHOD2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), ClassName, __VA_ARGS__ )
+ INTERNAL_CATCH_TEST_CASE_METHOD2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_S_T_ ), ClassName, __VA_ARGS__ )
///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_REGISTER_TESTCASE( Function, ... ) \
+ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( Catch::makeTestInvoker( Function ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ __VA_ARGS__ } ); /* NOLINT */ \
- CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS
+ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
///////////////////////////////////////////////////////////////////////////////
- #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_2(TestName, TestFunc, Name, Tags, ... )\
+ #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_2(TestName, TestFunc, Name, Tags, Signature, ... )\
+ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
- template<typename TestType> \
- static void TestFunc();\
+ CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS \
+ CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \
+ INTERNAL_CATCH_DECLARE_SIG_TEST(TestFunc, INTERNAL_CATCH_REMOVE_PARENS(Signature));\
namespace {\
+ namespace INTERNAL_CATCH_MAKE_NAMESPACE(TestName){\
+ INTERNAL_CATCH_TYPE_GEN\
+ INTERNAL_CATCH_NTTP_GEN(INTERNAL_CATCH_REMOVE_PARENS(Signature))\
+ INTERNAL_CATCH_NTTP_REG_GEN(TestFunc,INTERNAL_CATCH_REMOVE_PARENS(Signature))\
template<typename...Types> \
struct TestName{\
- template<typename...Ts> \
- TestName(Ts...names){\
- CATCH_INTERNAL_CHECK_UNIQUE_TYPES(CATCH_REC_LIST(INTERNAL_CATCH_REMOVE_PARENS, __VA_ARGS__)) \
+ TestName(){\
+ int index = 0; \
+ constexpr char const* tmpl_types[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, __VA_ARGS__)};\
using expander = int[];\
- (void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestFunc<Types> ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ names, Tags } ), 0)... };/* NOLINT */ \
+ (void)expander{(reg_test(Types{}, Catch::NameAndTags{ Name " - " + std::string(tmpl_types[index]), Tags } ), index++)... };/* NOLINT */ \
}\
};\
- INTERNAL_CATCH_TEMPLATE_REGISTRY_INITIATE(TestName, Name, __VA_ARGS__) \
+ static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){\
+ TestName<INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES(__VA_ARGS__)>();\
+ return 0;\
+ }();\
}\
- CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS \
- template<typename TestType> \
- static void TestFunc()
+ }\
+ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
+ INTERNAL_CATCH_DEFINE_SIG_TEST(TestFunc,INTERNAL_CATCH_REMOVE_PARENS(Signature))
-#if defined(CATCH_CPP17_OR_GREATER)
-#define CATCH_INTERNAL_CHECK_UNIQUE_TYPES(...) static_assert(Catch::is_unique<__VA_ARGS__>,"Duplicate type detected in declaration of template test case");
+#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
+ #define INTERNAL_CATCH_TEMPLATE_TEST_CASE(Name, Tags, ...) \
+ INTERNAL_CATCH_TEMPLATE_TEST_CASE_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), Name, Tags, typename TestType, __VA_ARGS__ )
#else
-#define CATCH_INTERNAL_CHECK_UNIQUE_TYPES(...) static_assert(Catch::is_unique<__VA_ARGS__>::value,"Duplicate type detected in declaration of template test case");
+ #define INTERNAL_CATCH_TEMPLATE_TEST_CASE(Name, Tags, ...) \
+ INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), Name, Tags, typename TestType, __VA_ARGS__ ) )
#endif
#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
- #define INTERNAL_CATCH_TEMPLATE_TEST_CASE(Name, Tags, ...) \
- INTERNAL_CATCH_TEMPLATE_TEST_CASE_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, __VA_ARGS__ )
+ #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG(Name, Tags, Signature, ...) \
+ INTERNAL_CATCH_TEMPLATE_TEST_CASE_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), Name, Tags, Signature, __VA_ARGS__ )
#else
- #define INTERNAL_CATCH_TEMPLATE_TEST_CASE(Name, Tags, ...) \
- INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, __VA_ARGS__ ) )
+ #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG(Name, Tags, Signature, ...) \
+ INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), Name, Tags, Signature, __VA_ARGS__ ) )
#endif
- #define INTERNAL_CATCH_TEMPLATE_REGISTRY_INITIATE(TestName, Name, ...)\
- static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){\
- TestName<CATCH_REC_LIST(INTERNAL_CATCH_REMOVE_PARENS, __VA_ARGS__)>(CATCH_REC_LIST_UD(INTERNAL_CATCH_TEMPLATE_UNIQUE_NAME,Name, __VA_ARGS__));\
- return 0;\
- }();
+ #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE2(TestName, TestFuncName, Name, Tags, Signature, TmplTypes, TypesList) \
+ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
+ CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
+ CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS \
+ CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \
+ template<typename TestType> static void TestFuncName(); \
+ namespace {\
+ namespace INTERNAL_CATCH_MAKE_NAMESPACE(TestName) { \
+ INTERNAL_CATCH_TYPE_GEN \
+ INTERNAL_CATCH_NTTP_GEN(INTERNAL_CATCH_REMOVE_PARENS(Signature)) \
+ template<typename... Types> \
+ struct TestName { \
+ void reg_tests() { \
+ int index = 0; \
+ using expander = int[]; \
+ constexpr char const* tmpl_types[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, INTERNAL_CATCH_REMOVE_PARENS(TmplTypes))};\
+ constexpr char const* types_list[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, INTERNAL_CATCH_REMOVE_PARENS(TypesList))};\
+ constexpr auto num_types = sizeof(types_list) / sizeof(types_list[0]);\
+ (void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestFuncName<Types> ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ Name " - " + std::string(tmpl_types[index / num_types]) + "<" + std::string(types_list[index % num_types]) + ">", Tags } ), index++)... };/* NOLINT */\
+ } \
+ }; \
+ static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){ \
+ using TestInit = typename create<TestName, decltype(get_wrapper<INTERNAL_CATCH_REMOVE_PARENS(TmplTypes)>()), TypeList<INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES(INTERNAL_CATCH_REMOVE_PARENS(TypesList))>>::type; \
+ TestInit t; \
+ t.reg_tests(); \
+ return 0; \
+ }(); \
+ } \
+ } \
+ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
+ template<typename TestType> \
+ static void TestFuncName()
+
+#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
+ #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE(Name, Tags, ...)\
+ INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE2(INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), Name, Tags, typename T,__VA_ARGS__)
+#else
+ #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE(Name, Tags, ...)\
+ INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), Name, Tags, typename T, __VA_ARGS__ ) )
+#endif
+
+#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
+ #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG(Name, Tags, Signature, ...)\
+ INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE2(INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), Name, Tags, Signature, __VA_ARGS__)
+#else
+ #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG(Name, Tags, Signature, ...)\
+ INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), Name, Tags, Signature, __VA_ARGS__ ) )
+#endif
- #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_2( TestNameClass, TestName, ClassName, Name, Tags, ... ) \
+ #define INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_2(TestName, TestFunc, Name, Tags, TmplList)\
+ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
- namespace{ \
- template<typename TestType> \
+ CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \
+ template<typename TestType> static void TestFunc(); \
+ namespace {\
+ namespace INTERNAL_CATCH_MAKE_NAMESPACE(TestName){\
+ INTERNAL_CATCH_TYPE_GEN\
+ template<typename... Types> \
+ struct TestName { \
+ void reg_tests() { \
+ int index = 0; \
+ using expander = int[]; \
+ (void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestFunc<Types> ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ Name " - " + std::string(INTERNAL_CATCH_STRINGIZE(TmplList)) + " - " + std::to_string(index), Tags } ), index++)... };/* NOLINT */\
+ } \
+ };\
+ static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){ \
+ using TestInit = typename convert<TestName, TmplList>::type; \
+ TestInit t; \
+ t.reg_tests(); \
+ return 0; \
+ }(); \
+ }}\
+ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
+ template<typename TestType> \
+ static void TestFunc()
+
+ #define INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE(Name, Tags, TmplList) \
+ INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), Name, Tags, TmplList )
+
+ #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_2( TestNameClass, TestName, ClassName, Name, Tags, Signature, ... ) \
+ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
+ CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
+ CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS \
+ CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \
+ namespace {\
+ namespace INTERNAL_CATCH_MAKE_NAMESPACE(TestName){ \
+ INTERNAL_CATCH_TYPE_GEN\
+ INTERNAL_CATCH_NTTP_GEN(INTERNAL_CATCH_REMOVE_PARENS(Signature))\
+ INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD(TestName, ClassName, INTERNAL_CATCH_REMOVE_PARENS(Signature));\
+ INTERNAL_CATCH_NTTP_REG_METHOD_GEN(TestName, INTERNAL_CATCH_REMOVE_PARENS(Signature))\
+ template<typename...Types> \
+ struct TestNameClass{\
+ TestNameClass(){\
+ int index = 0; \
+ constexpr char const* tmpl_types[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, __VA_ARGS__)};\
+ using expander = int[];\
+ (void)expander{(reg_test(Types{}, #ClassName, Catch::NameAndTags{ Name " - " + std::string(tmpl_types[index]), Tags } ), index++)... };/* NOLINT */ \
+ }\
+ };\
+ static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){\
+ TestNameClass<INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES(__VA_ARGS__)>();\
+ return 0;\
+ }();\
+ }\
+ }\
+ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
+ INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD(TestName, INTERNAL_CATCH_REMOVE_PARENS(Signature))
+
+#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
+ #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( ClassName, Name, Tags,... ) \
+ INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_C_L_A_S_S_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ) , ClassName, Name, Tags, typename T, __VA_ARGS__ )
+#else
+ #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( ClassName, Name, Tags,... ) \
+ INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_C_L_A_S_S_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ) , ClassName, Name, Tags, typename T, __VA_ARGS__ ) )
+#endif
+
+#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
+ #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( ClassName, Name, Tags, Signature, ... ) \
+ INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_C_L_A_S_S_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ) , ClassName, Name, Tags, Signature, __VA_ARGS__ )
+#else
+ #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( ClassName, Name, Tags, Signature, ... ) \
+ INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_C_L_A_S_S_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ) , ClassName, Name, Tags, Signature, __VA_ARGS__ ) )
+#endif
+
+ #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_2(TestNameClass, TestName, ClassName, Name, Tags, Signature, TmplTypes, TypesList)\
+ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
+ CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
+ CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS \
+ CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \
+ template<typename TestType> \
struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName <TestType>) { \
void test();\
};\
- template<typename...Types> \
+ namespace {\
+ namespace INTERNAL_CATCH_MAKE_NAMESPACE(TestNameClass) {\
+ INTERNAL_CATCH_TYPE_GEN \
+ INTERNAL_CATCH_NTTP_GEN(INTERNAL_CATCH_REMOVE_PARENS(Signature))\
+ template<typename...Types>\
struct TestNameClass{\
- template<typename...Ts> \
- TestNameClass(Ts...names){\
- CATCH_INTERNAL_CHECK_UNIQUE_TYPES(CATCH_REC_LIST(INTERNAL_CATCH_REMOVE_PARENS, __VA_ARGS__)) \
+ void reg_tests(){\
+ int index = 0;\
using expander = int[];\
- (void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestName<Types>::test ), CATCH_INTERNAL_LINEINFO, #ClassName, Catch::NameAndTags{ names, Tags } ), 0)... };/* NOLINT */ \
+ constexpr char const* tmpl_types[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, INTERNAL_CATCH_REMOVE_PARENS(TmplTypes))};\
+ constexpr char const* types_list[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, INTERNAL_CATCH_REMOVE_PARENS(TypesList))};\
+ constexpr auto num_types = sizeof(types_list) / sizeof(types_list[0]);\
+ (void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestName<Types>::test ), CATCH_INTERNAL_LINEINFO, #ClassName, Catch::NameAndTags{ Name " - " + std::string(tmpl_types[index / num_types]) + "<" + std::string(types_list[index % num_types]) + ">", Tags } ), index++)... };/* NOLINT */ \
}\
};\
- INTERNAL_CATCH_TEMPLATE_REGISTRY_INITIATE(TestNameClass, Name, __VA_ARGS__)\
+ static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){\
+ using TestInit = typename create<TestNameClass, decltype(get_wrapper<INTERNAL_CATCH_REMOVE_PARENS(TmplTypes)>()), TypeList<INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES(INTERNAL_CATCH_REMOVE_PARENS(TypesList))>>::type;\
+ TestInit t;\
+ t.reg_tests();\
+ return 0;\
+ }(); \
}\
- CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS\
+ }\
+ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
template<typename TestType> \
void TestName<TestType>::test()
#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
- #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( ClassName, Name, Tags,... ) \
- INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____C_L_A_S_S____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ) , ClassName, Name, Tags, __VA_ARGS__ )
+ #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( ClassName, Name, Tags, ... )\
+ INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), ClassName, Name, Tags, typename T, __VA_ARGS__ )
#else
- #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( ClassName, Name, Tags,... ) \
- INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____C_L_A_S_S____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ) , ClassName, Name, Tags, __VA_ARGS__ ) )
+ #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( ClassName, Name, Tags, ... )\
+ INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), ClassName, Name, Tags, typename T,__VA_ARGS__ ) )
#endif
+#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
+ #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( ClassName, Name, Tags, Signature, ... )\
+ INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), ClassName, Name, Tags, Signature, __VA_ARGS__ )
+#else
+ #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( ClassName, Name, Tags, Signature, ... )\
+ INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), ClassName, Name, Tags, Signature,__VA_ARGS__ ) )
+#endif
+
+ #define INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_METHOD_2( TestNameClass, TestName, ClassName, Name, Tags, TmplList) \
+ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
+ CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
+ CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \
+ template<typename TestType> \
+ struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName <TestType>) { \
+ void test();\
+ };\
+ namespace {\
+ namespace INTERNAL_CATCH_MAKE_NAMESPACE(TestName){ \
+ INTERNAL_CATCH_TYPE_GEN\
+ template<typename...Types>\
+ struct TestNameClass{\
+ void reg_tests(){\
+ int index = 0;\
+ using expander = int[];\
+ (void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestName<Types>::test ), CATCH_INTERNAL_LINEINFO, #ClassName, Catch::NameAndTags{ Name " - " + std::string(INTERNAL_CATCH_STRINGIZE(TmplList)) + " - " + std::to_string(index), Tags } ), index++)... };/* NOLINT */ \
+ }\
+ };\
+ static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){\
+ using TestInit = typename convert<TestNameClass, TmplList>::type;\
+ TestInit t;\
+ t.reg_tests();\
+ return 0;\
+ }(); \
+ }}\
+ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
+ template<typename TestType> \
+ void TestName<TestType>::test()
+
+#define INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_METHOD(ClassName, Name, Tags, TmplList) \
+ INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), ClassName, Name, Tags, TmplList )
+
// end catch_test_registry.h
// start catch_capture.hpp
@@ -978,7 +1437,7 @@ namespace Catch {
auto makeStream( StringRef const &filename ) -> IStream const*;
- class ReusableStringStream {
+ class ReusableStringStream : NonCopyable {
std::size_t m_index;
std::ostream* m_oss;
public:
@@ -997,6 +1456,42 @@ namespace Catch {
}
// end catch_stream.h
+// start catch_interfaces_enum_values_registry.h
+
+#include <vector>
+
+namespace Catch {
+
+ namespace Detail {
+ struct EnumInfo {
+ StringRef m_name;
+ std::vector<std::pair<int, StringRef>> m_values;
+
+ ~EnumInfo();
+
+ StringRef lookup( int value ) const;
+ };
+ } // namespace Detail
+
+ struct IMutableEnumValuesRegistry {
+ virtual ~IMutableEnumValuesRegistry();
+
+ virtual Detail::EnumInfo const& registerEnum( StringRef enumName, StringRef allEnums, std::vector<int> const& values ) = 0;
+
+ template<typename E>
+ Detail::EnumInfo const& registerEnum( StringRef enumName, StringRef allEnums, std::initializer_list<E> values ) {
+ static_assert(sizeof(int) >= sizeof(E), "Cannot serialize enum to int");
+ std::vector<int> intValues;
+ intValues.reserve( values.size() );
+ for( auto enumValue : values )
+ intValues.push_back( static_cast<int>( enumValue ) );
+ return registerEnum( enumName, allEnums, intValues );
+ }
+ };
+
+} // Catch
+
+// end catch_interfaces_enum_values_registry.h
#ifdef CATCH_CONFIG_CPP17_STRING_VIEW
#include <string_view>
@@ -1067,9 +1562,9 @@ namespace Catch {
template<typename T>
class IsStreamInsertable {
- template<typename SS, typename TT>
+ template<typename Stream, typename U>
static auto test(int)
- -> decltype(std::declval<SS&>() << std::declval<TT>(), std::true_type());
+ -> decltype(std::declval<Stream&>() << std::declval<U>(), std::true_type());
template<typename, typename>
static auto test(...)->std::false_type;
@@ -1231,6 +1726,12 @@ namespace Catch {
}
};
+#if defined(CATCH_CONFIG_CPP17_BYTE)
+ template<>
+ struct StringMaker<std::byte> {
+ static std::string convert(std::byte value);
+ };
+#endif // defined(CATCH_CONFIG_CPP17_BYTE)
template<>
struct StringMaker<int> {
static std::string convert(int value);
@@ -1282,10 +1783,13 @@ namespace Catch {
template<>
struct StringMaker<float> {
static std::string convert(float value);
+ static int precision;
};
+
template<>
struct StringMaker<double> {
static std::string convert(double value);
+ static int precision;
};
template <typename T>
@@ -1321,8 +1825,8 @@ namespace Catch {
#endif
namespace Detail {
- template<typename InputIterator>
- std::string rangeToString(InputIterator first, InputIterator last) {
+ template<typename InputIterator, typename Sentinel = InputIterator>
+ std::string rangeToString(InputIterator first, Sentinel last) {
ReusableStringStream rss;
rss << "{ ";
if (first != last) {
@@ -1370,6 +1874,7 @@ namespace Catch {
# define CATCH_CONFIG_ENABLE_TUPLE_STRINGMAKER
# define CATCH_CONFIG_ENABLE_VARIANT_STRINGMAKER
# define CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER
+# define CATCH_CONFIG_ENABLE_OPTIONAL_STRINGMAKER
#endif
// Separate std::pair specialization
@@ -1391,6 +1896,24 @@ namespace Catch {
}
#endif // CATCH_CONFIG_ENABLE_PAIR_STRINGMAKER
+#if defined(CATCH_CONFIG_ENABLE_OPTIONAL_STRINGMAKER) && defined(CATCH_CONFIG_CPP17_OPTIONAL)
+#include <optional>
+namespace Catch {
+ template<typename T>
+ struct StringMaker<std::optional<T> > {
+ static std::string convert(const std::optional<T>& optional) {
+ ReusableStringStream rss;
+ if (optional.has_value()) {
+ rss << ::Catch::Detail::stringify(*optional);
+ } else {
+ rss << "{ }";
+ }
+ return rss.str();
+ }
+ };
+}
+#endif // CATCH_CONFIG_ENABLE_OPTIONAL_STRINGMAKER
+
// Separate std::tuple specialization
#if defined(CATCH_CONFIG_ENABLE_TUPLE_STRINGMAKER)
#include <tuple>
@@ -1461,20 +1984,27 @@ namespace Catch {
#endif // CATCH_CONFIG_ENABLE_VARIANT_STRINGMAKER
namespace Catch {
- struct not_this_one {}; // Tag type for detecting which begin/ end are being selected
-
- // Import begin/ end from std here so they are considered alongside the fallback (...) overloads in this namespace
+ // Import begin/ end from std here
using std::begin;
using std::end;
- not_this_one begin( ... );
- not_this_one end( ... );
+ namespace detail {
+ template <typename...>
+ struct void_type {
+ using type = void;
+ };
+
+ template <typename T, typename = void>
+ struct is_range_impl : std::false_type {
+ };
+
+ template <typename T>
+ struct is_range_impl<T, typename void_type<decltype(begin(std::declval<T>()))>::type> : std::true_type {
+ };
+ } // namespace detail
template <typename T>
- struct is_range {
- static const bool value =
- !std::is_same<decltype(begin(std::declval<T>())), not_this_one>::value &&
- !std::is_same<decltype(end(std::declval<T>())), not_this_one>::value;
+ struct is_range : detail::is_range_impl<T> {
};
#if defined(_MANAGED) // Managed types are never ranges
@@ -1639,6 +2169,18 @@ struct ratio_string<std::milli> {
}
#endif // CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER
+#define INTERNAL_CATCH_REGISTER_ENUM( enumName, ... ) \
+namespace Catch { \
+ template<> struct StringMaker<enumName> { \
+ static std::string convert( enumName value ) { \
+ static const auto& enumInfo = ::Catch::getMutableRegistryHub().getMutableEnumValuesRegistry().registerEnum( #enumName, #__VA_ARGS__, { __VA_ARGS__ } ); \
+ return static_cast<std::string>(enumInfo.lookup( static_cast<int>( value ) )); \
+ } \
+ }; \
+}
+
+#define CATCH_REGISTER_ENUM( enumName, ... ) INTERNAL_CATCH_REGISTER_ENUM( enumName, __VA_ARGS__ )
+
#ifdef _MSC_VER
#pragma warning(pop)
#endif
@@ -1652,6 +2194,7 @@ struct ratio_string<std::milli> {
#pragma warning(disable:4018) // more "signed/unsigned mismatch"
#pragma warning(disable:4312) // Converting int to T* using reinterpret_cast (issue on x64 platform)
#pragma warning(disable:4180) // qualifier applied to function type has no meaning
+#pragma warning(disable:4800) // Forcing result to true or false
#endif
namespace Catch {
@@ -1695,6 +2238,62 @@ namespace Catch {
m_op( op ),
m_rhs( rhs )
{}
+
+ template<typename T>
+ auto operator && ( T ) const -> BinaryExpr<LhsT, RhsT const&> const {
+ static_assert(always_false<T>::value,
+ "chained comparisons are not supported inside assertions, "
+ "wrap the expression inside parentheses, or decompose it");
+ }
+
+ template<typename T>
+ auto operator || ( T ) const -> BinaryExpr<LhsT, RhsT const&> const {
+ static_assert(always_false<T>::value,
+ "chained comparisons are not supported inside assertions, "
+ "wrap the expression inside parentheses, or decompose it");
+ }
+
+ template<typename T>
+ auto operator == ( T ) const -> BinaryExpr<LhsT, RhsT const&> const {
+ static_assert(always_false<T>::value,
+ "chained comparisons are not supported inside assertions, "
+ "wrap the expression inside parentheses, or decompose it");
+ }
+
+ template<typename T>
+ auto operator != ( T ) const -> BinaryExpr<LhsT, RhsT const&> const {
+ static_assert(always_false<T>::value,
+ "chained comparisons are not supported inside assertions, "
+ "wrap the expression inside parentheses, or decompose it");
+ }
+
+ template<typename T>
+ auto operator > ( T ) const -> BinaryExpr<LhsT, RhsT const&> const {
+ static_assert(always_false<T>::value,
+ "chained comparisons are not supported inside assertions, "
+ "wrap the expression inside parentheses, or decompose it");
+ }
+
+ template<typename T>
+ auto operator < ( T ) const -> BinaryExpr<LhsT, RhsT const&> const {
+ static_assert(always_false<T>::value,
+ "chained comparisons are not supported inside assertions, "
+ "wrap the expression inside parentheses, or decompose it");
+ }
+
+ template<typename T>
+ auto operator >= ( T ) const -> BinaryExpr<LhsT, RhsT const&> const {
+ static_assert(always_false<T>::value,
+ "chained comparisons are not supported inside assertions, "
+ "wrap the expression inside parentheses, or decompose it");
+ }
+
+ template<typename T>
+ auto operator <= ( T ) const -> BinaryExpr<LhsT, RhsT const&> const {
+ static_assert(always_false<T>::value,
+ "chained comparisons are not supported inside assertions, "
+ "wrap the expression inside parentheses, or decompose it");
+ }
};
template<typename LhsT>
@@ -1707,7 +2306,7 @@ namespace Catch {
public:
explicit UnaryExpr( LhsT lhs )
- : ITransientExpression{ false, lhs ? true : false },
+ : ITransientExpression{ false, static_cast<bool>(lhs) },
m_lhs( lhs )
{}
};
@@ -1773,6 +2372,32 @@ namespace Catch {
auto operator <= ( RhsT const& rhs ) -> BinaryExpr<LhsT, RhsT const&> const {
return { static_cast<bool>(m_lhs <= rhs), m_lhs, "<=", rhs };
}
+ template <typename RhsT>
+ auto operator | (RhsT const& rhs) -> BinaryExpr<LhsT, RhsT const&> const {
+ return { static_cast<bool>(m_lhs | rhs), m_lhs, "|", rhs };
+ }
+ template <typename RhsT>
+ auto operator & (RhsT const& rhs) -> BinaryExpr<LhsT, RhsT const&> const {
+ return { static_cast<bool>(m_lhs & rhs), m_lhs, "&", rhs };
+ }
+ template <typename RhsT>
+ auto operator ^ (RhsT const& rhs) -> BinaryExpr<LhsT, RhsT const&> const {
+ return { static_cast<bool>(m_lhs ^ rhs), m_lhs, "^", rhs };
+ }
+
+ template<typename RhsT>
+ auto operator && ( RhsT const& ) -> BinaryExpr<LhsT, RhsT const&> const {
+ static_assert(always_false<RhsT>::value,
+ "operator&& is not supported inside assertions, "
+ "wrap the expression inside parentheses, or decompose it");
+ }
+
+ template<typename RhsT>
+ auto operator || ( RhsT const& ) -> BinaryExpr<LhsT, RhsT const&> const {
+ static_assert(always_false<RhsT>::value,
+ "operator|| is not supported inside assertions, "
+ "wrap the expression inside parentheses, or decompose it");
+ }
auto makeUnaryExpr() const -> UnaryExpr<LhsT> {
return UnaryExpr<LhsT>{ m_lhs };
@@ -1807,6 +2432,7 @@ namespace Catch {
// start catch_interfaces_capture.h
#include <string>
+#include <chrono>
namespace Catch {
@@ -1815,15 +2441,20 @@ namespace Catch {
struct SectionInfo;
struct SectionEndInfo;
struct MessageInfo;
+ struct MessageBuilder;
struct Counts;
- struct BenchmarkInfo;
- struct BenchmarkStats;
struct AssertionReaction;
struct SourceLineInfo;
struct ITransientExpression;
struct IGeneratorTracker;
+#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)
+ struct BenchmarkInfo;
+ template <typename Duration = std::chrono::duration<double, std::nano>>
+ struct BenchmarkStats;
+#endif // CATCH_CONFIG_ENABLE_BENCHMARKING
+
struct IResultCapture {
virtual ~IResultCapture();
@@ -1833,14 +2464,20 @@ namespace Catch {
virtual void sectionEnded( SectionEndInfo const& endInfo ) = 0;
virtual void sectionEndedEarly( SectionEndInfo const& endInfo ) = 0;
- virtual auto acquireGeneratorTracker( SourceLineInfo const& lineInfo ) -> IGeneratorTracker& = 0;
+ virtual auto acquireGeneratorTracker( StringRef generatorName, SourceLineInfo const& lineInfo ) -> IGeneratorTracker& = 0;
+#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)
+ virtual void benchmarkPreparing( std::string const& name ) = 0;
virtual void benchmarkStarting( BenchmarkInfo const& info ) = 0;
- virtual void benchmarkEnded( BenchmarkStats const& stats ) = 0;
+ virtual void benchmarkEnded( BenchmarkStats<> const& stats ) = 0;
+ virtual void benchmarkFailed( std::string const& error ) = 0;
+#endif // CATCH_CONFIG_ENABLE_BENCHMARKING
virtual void pushScopedMessage( MessageInfo const& message ) = 0;
virtual void popScopedMessage( MessageInfo const& message ) = 0;
+ virtual void emplaceUnscopedMessage( MessageBuilder const& builder ) = 0;
+
virtual void handleFatalErrorCondition( StringRef message ) = 0;
virtual void handleExpr
@@ -2004,9 +2641,12 @@ namespace Catch {
class ScopedMessage {
public:
explicit ScopedMessage( MessageBuilder const& builder );
+ ScopedMessage( ScopedMessage& duplicate ) = delete;
+ ScopedMessage( ScopedMessage&& old );
~ScopedMessage();
MessageInfo m_info;
+ bool m_moved;
};
class Capturer {
@@ -2062,15 +2702,16 @@ namespace Catch {
///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_TEST( macroName, resultDisposition, ... ) \
do { \
+ CATCH_INTERNAL_IGNORE_BUT_WARN(__VA_ARGS__); \
Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__), resultDisposition ); \
INTERNAL_CATCH_TRY { \
+ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \
catchAssertionHandler.handleExpr( Catch::Decomposer() <= __VA_ARGS__ ); \
- CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS \
+ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
} INTERNAL_CATCH_CATCH( catchAssertionHandler ) \
INTERNAL_CATCH_REACT( catchAssertionHandler ) \
- } while( (void)0, false && static_cast<bool>( !!(__VA_ARGS__) ) ) // the expression here is never evaluated at runtime but it forces the compiler to give it a look
- // The double negation silences MSVC's C4800 warning, the static_cast forces short-circuit evaluation if the type has overloaded &&.
+ } while( (void)0, (false) && static_cast<bool>( !!(__VA_ARGS__) ) )
///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_IF( macroName, resultDisposition, ... ) \
@@ -2151,6 +2792,10 @@ namespace Catch {
Catch::ScopedMessage INTERNAL_CATCH_UNIQUE_NAME( scopedMessage )( Catch::MessageBuilder( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info ) << log );
///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CATCH_UNSCOPED_INFO( macroName, log ) \
+ Catch::getResultCapture().emplaceUnscopedMessage( Catch::MessageBuilder( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info ) << log )
+
+///////////////////////////////////////////////////////////////////////////////
// Although this is matcher-based, it can be used with just a string
#define INTERNAL_CATCH_THROWS_STR_MATCHES( macroName, resultDisposition, matcher, ... ) \
do { \
@@ -2283,62 +2928,18 @@ namespace Catch {
} // end namespace Catch
#define INTERNAL_CATCH_SECTION( ... ) \
+ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS \
if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::SectionInfo( CATCH_INTERNAL_LINEINFO, __VA_ARGS__ ) ) \
- CATCH_INTERNAL_UNSUPPRESS_UNUSED_WARNINGS
+ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
#define INTERNAL_CATCH_DYNAMIC_SECTION( ... ) \
+ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS \
if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::SectionInfo( CATCH_INTERNAL_LINEINFO, (Catch::ReusableStringStream() << __VA_ARGS__).str() ) ) \
- CATCH_INTERNAL_UNSUPPRESS_UNUSED_WARNINGS
+ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
// end catch_section.h
-// start catch_benchmark.h
-
-#include <cstdint>
-#include <string>
-
-namespace Catch {
-
- class BenchmarkLooper {
-
- std::string m_name;
- std::size_t m_count = 0;
- std::size_t m_iterationsToRun = 1;
- uint64_t m_resolution;
- Timer m_timer;
-
- static auto getResolution() -> uint64_t;
- public:
- // Keep most of this inline as it's on the code path that is being timed
- BenchmarkLooper( StringRef name )
- : m_name( name ),
- m_resolution( getResolution() )
- {
- reportStart();
- m_timer.start();
- }
-
- explicit operator bool() {
- if( m_count < m_iterationsToRun )
- return true;
- return needsMoreIterations();
- }
-
- void increment() {
- ++m_count;
- }
-
- void reportStart();
- auto needsMoreIterations() -> bool;
- };
-
-} // end namespace Catch
-
-#define BENCHMARK( name ) \
- for( Catch::BenchmarkLooper looper( name ); looper; looper.increment() )
-
-// end catch_benchmark.h
// start catch_interfaces_exception.h
// start catch_interfaces_registry_hub.h
@@ -2355,6 +2956,8 @@ namespace Catch {
struct IReporterRegistry;
struct IReporterFactory;
struct ITagAliasRegistry;
+ struct IMutableEnumValuesRegistry;
+
class StartupExceptionRegistry;
using IReporterFactoryPtr = std::shared_ptr<IReporterFactory>;
@@ -2365,7 +2968,6 @@ namespace Catch {
virtual IReporterRegistry const& getReporterRegistry() const = 0;
virtual ITestCaseRegistry const& getTestCaseRegistry() const = 0;
virtual ITagAliasRegistry const& getTagAliasRegistry() const = 0;
-
virtual IExceptionTranslatorRegistry const& getExceptionTranslatorRegistry() const = 0;
virtual StartupExceptionRegistry const& getStartupExceptionRegistry() const = 0;
@@ -2379,6 +2981,7 @@ namespace Catch {
virtual void registerTranslator( const IExceptionTranslator* translator ) = 0;
virtual void registerTagAlias( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ) = 0;
virtual void registerStartupException() noexcept = 0;
+ virtual IMutableEnumValuesRegistry& getMutableEnumValuesRegistry() = 0;
};
IRegistryHub const& getRegistryHub();
@@ -2425,6 +3028,9 @@ namespace Catch {
{}
std::string translate( ExceptionTranslators::const_iterator it, ExceptionTranslators::const_iterator itEnd ) const override {
+#if defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
+ return "";
+#else
try {
if( it == itEnd )
std::rethrow_exception(std::current_exception());
@@ -2434,6 +3040,7 @@ namespace Catch {
catch( T& ex ) {
return m_translateFunction( ex );
}
+#endif
}
protected:
@@ -2452,9 +3059,10 @@ namespace Catch {
///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_TRANSLATE_EXCEPTION2( translatorName, signature ) \
static std::string translatorName( signature ); \
+ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
namespace{ Catch::ExceptionTranslatorRegistrar INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionRegistrar )( &translatorName ); } \
- CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS \
+ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
static std::string translatorName( signature )
#define INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION2( INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator ), signature )
@@ -2485,7 +3093,7 @@ namespace Detail {
Approx operator-() const;
template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
- Approx operator()( T const& value ) {
+ Approx operator()( T const& value ) const {
Approx approx( static_cast<double>(value) );
approx.m_epsilon = m_epsilon;
approx.m_margin = m_margin;
@@ -2585,6 +3193,7 @@ struct StringMaker<Catch::Detail::Approx> {
#include <string>
#include <iosfwd>
+#include <vector>
namespace Catch {
@@ -2595,7 +3204,13 @@ namespace Catch {
bool contains( std::string const& s, std::string const& infix );
void toLowerInPlace( std::string& s );
std::string toLower( std::string const& s );
+ //! Returns a new string without whitespace at the start/end
std::string trim( std::string const& str );
+ //! Returns a substring of the original ref without whitespace. Beware lifetimes!
+ StringRef trim(StringRef ref);
+
+ // !!! Be aware, returns refs into original string - make sure original string outlives them
+ std::vector<StringRef> splitStringRef( StringRef str, char delimiter );
bool replaceInPlace( std::string& str, std::string const& replaceThis, std::string const& withThis );
struct pluralise {
@@ -2648,6 +3263,15 @@ namespace Matchers {
virtual bool match( ObjectT const& arg ) const = 0;
};
+#if defined(__OBJC__)
+ // Hack to fix Catch GH issue #1661. Could use id for generic Object support.
+ // use of const for Object pointers is very uncommon and under ARC it causes some kind of signature mismatch that breaks compilation
+ template<>
+ struct MatcherMethod<NSString*> {
+ virtual bool match( NSString* arg ) const = 0;
+ };
+#endif
+
#ifdef __clang__
# pragma clang diagnostic pop
#endif
@@ -2685,9 +3309,10 @@ namespace Matchers {
return description;
}
- MatchAllOf<ArgT>& operator && ( MatcherBase<ArgT> const& other ) {
- m_matchers.push_back( &other );
- return *this;
+ MatchAllOf<ArgT> operator && ( MatcherBase<ArgT> const& other ) {
+ auto copy(*this);
+ copy.m_matchers.push_back( &other );
+ return copy;
}
std::vector<MatcherBase<ArgT> const*> m_matchers;
@@ -2718,9 +3343,10 @@ namespace Matchers {
return description;
}
- MatchAnyOf<ArgT>& operator || ( MatcherBase<ArgT> const& other ) {
- m_matchers.push_back( &other );
- return *this;
+ MatchAnyOf<ArgT> operator || ( MatcherBase<ArgT> const& other ) {
+ auto copy(*this);
+ copy.m_matchers.push_back( &other );
+ return copy;
}
std::vector<MatcherBase<ArgT> const*> m_matchers;
@@ -2764,10 +3390,34 @@ using Matchers::Impl::MatcherBase;
} // namespace Catch
// end catch_matchers.h
-// start catch_matchers_floating.h
+// start catch_matchers_exception.hpp
-#include <type_traits>
-#include <cmath>
+namespace Catch {
+namespace Matchers {
+namespace Exception {
+
+class ExceptionMessageMatcher : public MatcherBase<std::exception> {
+ std::string m_message;
+public:
+
+ ExceptionMessageMatcher(std::string const& message):
+ m_message(message)
+ {}
+
+ bool match(std::exception const& ex) const override;
+
+ std::string describe() const override;
+};
+
+} // namespace Exception
+
+Exception::ExceptionMessageMatcher Message(std::string const& message);
+
+} // namespace Matchers
+} // namespace Catch
+
+// end catch_matchers_exception.hpp
+// start catch_matchers_floating.h
namespace Catch {
namespace Matchers {
@@ -2786,22 +3436,43 @@ namespace Matchers {
};
struct WithinUlpsMatcher : MatcherBase<double> {
- WithinUlpsMatcher(double target, int ulps, FloatingPointKind baseType);
+ WithinUlpsMatcher(double target, uint64_t ulps, FloatingPointKind baseType);
bool match(double const& matchee) const override;
std::string describe() const override;
private:
double m_target;
- int m_ulps;
+ uint64_t m_ulps;
FloatingPointKind m_type;
};
+ // Given IEEE-754 format for floats and doubles, we can assume
+ // that float -> double promotion is lossless. Given this, we can
+ // assume that if we do the standard relative comparison of
+ // |lhs - rhs| <= epsilon * max(fabs(lhs), fabs(rhs)), then we get
+ // the same result if we do this for floats, as if we do this for
+ // doubles that were promoted from floats.
+ struct WithinRelMatcher : MatcherBase<double> {
+ WithinRelMatcher(double target, double epsilon);
+ bool match(double const& matchee) const override;
+ std::string describe() const override;
+ private:
+ double m_target;
+ double m_epsilon;
+ };
+
} // namespace Floating
// The following functions create the actual matcher objects.
// This allows the types to be inferred
- Floating::WithinUlpsMatcher WithinULP(double target, int maxUlpDiff);
- Floating::WithinUlpsMatcher WithinULP(float target, int maxUlpDiff);
+ Floating::WithinUlpsMatcher WithinULP(double target, uint64_t maxUlpDiff);
+ Floating::WithinUlpsMatcher WithinULP(float target, uint64_t maxUlpDiff);
Floating::WithinAbsMatcher WithinAbs(double target, double margin);
+ Floating::WithinRelMatcher WithinRel(double target, double eps);
+ // defaults epsilon to 100*numeric_limits<double>::epsilon()
+ Floating::WithinRelMatcher WithinRel(double target);
+ Floating::WithinRelMatcher WithinRel(float target, float eps);
+ // defaults epsilon to 100*numeric_limits<float>::epsilon()
+ Floating::WithinRelMatcher WithinRel(float target);
} // namespace Matchers
} // namespace Catch
@@ -2844,7 +3515,7 @@ public:
// The following functions create the actual matcher objects.
// The user has to explicitly specify type to the function, because
- // infering std::function<bool(T const&)> is hard (but possible) and
+ // inferring std::function<bool(T const&)> is hard (but possible) and
// requires a lot of TMP.
template<typename T>
Generic::PredicateMatcher<T> Predicate(std::function<bool(T const&)> const& predicate, std::string const& description = "") {
@@ -2932,34 +3603,12 @@ namespace Catch {
namespace Matchers {
namespace Vector {
- namespace Detail {
- template <typename InputIterator, typename T>
- size_t count(InputIterator first, InputIterator last, T const& item) {
- size_t cnt = 0;
- for (; first != last; ++first) {
- if (*first == item) {
- ++cnt;
- }
- }
- return cnt;
- }
- template <typename InputIterator, typename T>
- bool contains(InputIterator first, InputIterator last, T const& item) {
- for (; first != last; ++first) {
- if (*first == item) {
- return true;
- }
- }
- return false;
- }
- }
-
- template<typename T>
- struct ContainsElementMatcher : MatcherBase<std::vector<T>> {
+ template<typename T, typename Alloc>
+ struct ContainsElementMatcher : MatcherBase<std::vector<T, Alloc>> {
ContainsElementMatcher(T const &comparator) : m_comparator( comparator) {}
- bool match(std::vector<T> const &v) const override {
+ bool match(std::vector<T, Alloc> const &v) const override {
for (auto const& el : v) {
if (el == m_comparator) {
return true;
@@ -2975,12 +3624,12 @@ namespace Matchers {
T const& m_comparator;
};
- template<typename T>
- struct ContainsMatcher : MatcherBase<std::vector<T>> {
+ template<typename T, typename AllocComp, typename AllocMatch>
+ struct ContainsMatcher : MatcherBase<std::vector<T, AllocMatch>> {
- ContainsMatcher(std::vector<T> const &comparator) : m_comparator( comparator ) {}
+ ContainsMatcher(std::vector<T, AllocComp> const &comparator) : m_comparator( comparator ) {}
- bool match(std::vector<T> const &v) const override {
+ bool match(std::vector<T, AllocMatch> const &v) const override {
// !TBD: see note in EqualsMatcher
if (m_comparator.size() > v.size())
return false;
@@ -3002,18 +3651,18 @@ namespace Matchers {
return "Contains: " + ::Catch::Detail::stringify( m_comparator );
}
- std::vector<T> const& m_comparator;
+ std::vector<T, AllocComp> const& m_comparator;
};
- template<typename T>
- struct EqualsMatcher : MatcherBase<std::vector<T>> {
+ template<typename T, typename AllocComp, typename AllocMatch>
+ struct EqualsMatcher : MatcherBase<std::vector<T, AllocMatch>> {
- EqualsMatcher(std::vector<T> const &comparator) : m_comparator( comparator ) {}
+ EqualsMatcher(std::vector<T, AllocComp> const &comparator) : m_comparator( comparator ) {}
- bool match(std::vector<T> const &v) const override {
+ bool match(std::vector<T, AllocMatch> const &v) const override {
// !TBD: This currently works if all elements can be compared using !=
// - a more general approach would be via a compare template that defaults
- // to using !=. but could be specialised for, e.g. std::vector<T> etc
+ // to using !=. but could be specialised for, e.g. std::vector<T, Alloc> etc
// - then just call that directly
if (m_comparator.size() != v.size())
return false;
@@ -3025,47 +3674,60 @@ namespace Matchers {
std::string describe() const override {
return "Equals: " + ::Catch::Detail::stringify( m_comparator );
}
- std::vector<T> const& m_comparator;
+ std::vector<T, AllocComp> const& m_comparator;
};
- template<typename T>
- struct UnorderedEqualsMatcher : MatcherBase<std::vector<T>> {
- UnorderedEqualsMatcher(std::vector<T> const& target) : m_target(target) {}
- bool match(std::vector<T> const& vec) const override {
- // Note: This is a reimplementation of std::is_permutation,
- // because I don't want to include <algorithm> inside the common path
- if (m_target.size() != vec.size()) {
- return false;
- }
- auto lfirst = m_target.begin(), llast = m_target.end();
- auto rfirst = vec.begin(), rlast = vec.end();
- // Cut common prefix to optimize checking of permuted parts
- while (lfirst != llast && *lfirst == *rfirst) {
- ++lfirst; ++rfirst;
- }
- if (lfirst == llast) {
- return true;
- }
+ template<typename T, typename AllocComp, typename AllocMatch>
+ struct ApproxMatcher : MatcherBase<std::vector<T, AllocMatch>> {
- for (auto mid = lfirst; mid != llast; ++mid) {
- // Skip already counted items
- if (Detail::contains(lfirst, mid, *mid)) {
- continue;
- }
- size_t num_vec = Detail::count(rfirst, rlast, *mid);
- if (num_vec == 0 || Detail::count(lfirst, llast, *mid) != num_vec) {
- return false;
- }
- }
+ ApproxMatcher(std::vector<T, AllocComp> const& comparator) : m_comparator( comparator ) {}
+ bool match(std::vector<T, AllocMatch> const &v) const override {
+ if (m_comparator.size() != v.size())
+ return false;
+ for (std::size_t i = 0; i < v.size(); ++i)
+ if (m_comparator[i] != approx(v[i]))
+ return false;
return true;
}
+ std::string describe() const override {
+ return "is approx: " + ::Catch::Detail::stringify( m_comparator );
+ }
+ template <typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
+ ApproxMatcher& epsilon( T const& newEpsilon ) {
+ approx.epsilon(newEpsilon);
+ return *this;
+ }
+ template <typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
+ ApproxMatcher& margin( T const& newMargin ) {
+ approx.margin(newMargin);
+ return *this;
+ }
+ template <typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
+ ApproxMatcher& scale( T const& newScale ) {
+ approx.scale(newScale);
+ return *this;
+ }
+
+ std::vector<T, AllocComp> const& m_comparator;
+ mutable Catch::Detail::Approx approx = Catch::Detail::Approx::custom();
+ };
+
+ template<typename T, typename AllocComp, typename AllocMatch>
+ struct UnorderedEqualsMatcher : MatcherBase<std::vector<T, AllocMatch>> {
+ UnorderedEqualsMatcher(std::vector<T, AllocComp> const& target) : m_target(target) {}
+ bool match(std::vector<T, AllocMatch> const& vec) const override {
+ if (m_target.size() != vec.size()) {
+ return false;
+ }
+ return std::is_permutation(m_target.begin(), m_target.end(), vec.begin());
+ }
std::string describe() const override {
return "UnorderedEquals: " + ::Catch::Detail::stringify(m_target);
}
private:
- std::vector<T> const& m_target;
+ std::vector<T, AllocComp> const& m_target;
};
} // namespace Vector
@@ -3073,24 +3735,29 @@ namespace Matchers {
// The following functions create the actual matcher objects.
// This allows the types to be inferred
- template<typename T>
- Vector::ContainsMatcher<T> Contains( std::vector<T> const& comparator ) {
- return Vector::ContainsMatcher<T>( comparator );
+ template<typename T, typename AllocComp = std::allocator<T>, typename AllocMatch = AllocComp>
+ Vector::ContainsMatcher<T, AllocComp, AllocMatch> Contains( std::vector<T, AllocComp> const& comparator ) {
+ return Vector::ContainsMatcher<T, AllocComp, AllocMatch>( comparator );
}
- template<typename T>
- Vector::ContainsElementMatcher<T> VectorContains( T const& comparator ) {
- return Vector::ContainsElementMatcher<T>( comparator );
+ template<typename T, typename Alloc = std::allocator<T>>
+ Vector::ContainsElementMatcher<T, Alloc> VectorContains( T const& comparator ) {
+ return Vector::ContainsElementMatcher<T, Alloc>( comparator );
}
- template<typename T>
- Vector::EqualsMatcher<T> Equals( std::vector<T> const& comparator ) {
- return Vector::EqualsMatcher<T>( comparator );
+ template<typename T, typename AllocComp = std::allocator<T>, typename AllocMatch = AllocComp>
+ Vector::EqualsMatcher<T, AllocComp, AllocMatch> Equals( std::vector<T, AllocComp> const& comparator ) {
+ return Vector::EqualsMatcher<T, AllocComp, AllocMatch>( comparator );
}
- template<typename T>
- Vector::UnorderedEqualsMatcher<T> UnorderedEquals(std::vector<T> const& target) {
- return Vector::UnorderedEqualsMatcher<T>(target);
+ template<typename T, typename AllocComp = std::allocator<T>, typename AllocMatch = AllocComp>
+ Vector::ApproxMatcher<T, AllocComp, AllocMatch> Approx( std::vector<T, AllocComp> const& comparator ) {
+ return Vector::ApproxMatcher<T, AllocComp, AllocMatch>( comparator );
+ }
+
+ template<typename T, typename AllocComp = std::allocator<T>, typename AllocMatch = AllocComp>
+ Vector::UnorderedEqualsMatcher<T, AllocComp, AllocMatch> UnorderedEquals(std::vector<T, AllocComp> const& target) {
+ return Vector::UnorderedEqualsMatcher<T, AllocComp, AllocMatch>( target );
}
} // namespace Matchers
@@ -3175,16 +3842,17 @@ namespace Catch {
namespace Catch {
namespace Generators {
- class GeneratorBase {
- protected:
- size_t m_size = 0;
-
+ class GeneratorUntypedBase {
public:
- GeneratorBase( size_t size ) : m_size( size ) {}
- virtual ~GeneratorBase();
- auto size() const -> size_t { return m_size; }
+ GeneratorUntypedBase() = default;
+ virtual ~GeneratorUntypedBase();
+ // Attempts to move the generator to the next element
+ //
+ // Returns true iff the move succeeded (and a valid element
+ // can be retrieved).
+ virtual bool next() = 0;
};
- using GeneratorBasePtr = std::unique_ptr<GeneratorBase>;
+ using GeneratorBasePtr = std::unique_ptr<GeneratorUntypedBase>;
} // namespace Generators
@@ -3193,7 +3861,6 @@ namespace Catch {
virtual auto hasGenerator() const -> bool = 0;
virtual auto getGenerator() const -> Generators::GeneratorBasePtr const& = 0;
virtual void setGenerator( Generators::GeneratorBasePtr&& generator ) = 0;
- virtual auto getIndex() const -> std::size_t = 0;
};
} // namespace Catch
@@ -3201,7 +3868,7 @@ namespace Catch {
// end catch_interfaces_generatortracker.h
// start catch_enforce.h
-#include <stdexcept>
+#include <exception>
namespace Catch {
#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
@@ -3214,18 +3881,30 @@ namespace Catch {
[[noreturn]]
void throw_exception(std::exception const& e);
#endif
+
+ [[noreturn]]
+ void throw_logic_error(std::string const& msg);
+ [[noreturn]]
+ void throw_domain_error(std::string const& msg);
+ [[noreturn]]
+ void throw_runtime_error(std::string const& msg);
+
} // namespace Catch;
-#define CATCH_PREPARE_EXCEPTION( type, msg ) \
- type( ( Catch::ReusableStringStream() << msg ).str() )
-#define CATCH_INTERNAL_ERROR( msg ) \
- Catch::throw_exception(CATCH_PREPARE_EXCEPTION( std::logic_error, CATCH_INTERNAL_LINEINFO << ": Internal Catch error: " << msg))
-#define CATCH_ERROR( msg ) \
- Catch::throw_exception(CATCH_PREPARE_EXCEPTION( std::domain_error, msg ))
-#define CATCH_RUNTIME_ERROR( msg ) \
- Catch::throw_exception(CATCH_PREPARE_EXCEPTION( std::runtime_error, msg ))
-#define CATCH_ENFORCE( condition, msg ) \
- do{ if( !(condition) ) CATCH_ERROR( msg ); } while(false)
+#define CATCH_MAKE_MSG(...) \
+ (Catch::ReusableStringStream() << __VA_ARGS__).str()
+
+#define CATCH_INTERNAL_ERROR(...) \
+ Catch::throw_logic_error(CATCH_MAKE_MSG( CATCH_INTERNAL_LINEINFO << ": Internal Catch2 error: " << __VA_ARGS__))
+
+#define CATCH_ERROR(...) \
+ Catch::throw_domain_error(CATCH_MAKE_MSG( __VA_ARGS__ ))
+
+#define CATCH_RUNTIME_ERROR(...) \
+ Catch::throw_runtime_error(CATCH_MAKE_MSG( __VA_ARGS__ ))
+
+#define CATCH_ENFORCE( condition, ... ) \
+ do{ if( !(condition) ) CATCH_ERROR( __VA_ARGS__ ); } while(false)
// end catch_enforce.h
#include <memory>
@@ -3233,8 +3912,21 @@ namespace Catch {
#include <cassert>
#include <utility>
+#include <exception>
namespace Catch {
+
+class GeneratorException : public std::exception {
+ const char* const m_msg = "";
+
+public:
+ GeneratorException(const char* msg):
+ m_msg(msg)
+ {}
+
+ const char* what() const noexcept override final;
+};
+
namespace Generators {
// !TBD move this into its own location?
@@ -3246,223 +3938,819 @@ namespace Generators {
}
template<typename T>
- struct IGenerator {
- virtual ~IGenerator() {}
- virtual auto get( size_t index ) const -> T = 0;
+ struct IGenerator : GeneratorUntypedBase {
+ virtual ~IGenerator() = default;
+
+ // Returns the current element of the generator
+ //
+ // \Precondition The generator is either freshly constructed,
+ // or the last call to `next()` returned true
+ virtual T const& get() const = 0;
+ using type = T;
};
template<typename T>
- class SingleValueGenerator : public IGenerator<T> {
+ class SingleValueGenerator final : public IGenerator<T> {
T m_value;
public:
- SingleValueGenerator( T const& value ) : m_value( value ) {}
+ SingleValueGenerator(T&& value) : m_value(std::move(value)) {}
- auto get( size_t ) const -> T override {
+ T const& get() const override {
return m_value;
}
+ bool next() override {
+ return false;
+ }
};
template<typename T>
- class FixedValuesGenerator : public IGenerator<T> {
+ class FixedValuesGenerator final : public IGenerator<T> {
+ static_assert(!std::is_same<T, bool>::value,
+ "FixedValuesGenerator does not support bools because of std::vector<bool>"
+ "specialization, use SingleValue Generator instead.");
std::vector<T> m_values;
-
+ size_t m_idx = 0;
public:
FixedValuesGenerator( std::initializer_list<T> values ) : m_values( values ) {}
- auto get( size_t index ) const -> T override {
- return m_values[index];
+ T const& get() const override {
+ return m_values[m_idx];
+ }
+ bool next() override {
+ ++m_idx;
+ return m_idx < m_values.size();
+ }
+ };
+
+ template <typename T>
+ class GeneratorWrapper final {
+ std::unique_ptr<IGenerator<T>> m_generator;
+ public:
+ GeneratorWrapper(std::unique_ptr<IGenerator<T>> generator):
+ m_generator(std::move(generator))
+ {}
+ T const& get() const {
+ return m_generator->get();
+ }
+ bool next() {
+ return m_generator->next();
}
};
+ template <typename T>
+ GeneratorWrapper<T> value(T&& value) {
+ return GeneratorWrapper<T>(pf::make_unique<SingleValueGenerator<T>>(std::forward<T>(value)));
+ }
+ template <typename T>
+ GeneratorWrapper<T> values(std::initializer_list<T> values) {
+ return GeneratorWrapper<T>(pf::make_unique<FixedValuesGenerator<T>>(values));
+ }
+
template<typename T>
- class RangeGenerator : public IGenerator<T> {
- T const m_first;
- T const m_last;
+ class Generators : public IGenerator<T> {
+ std::vector<GeneratorWrapper<T>> m_generators;
+ size_t m_current = 0;
+
+ void populate(GeneratorWrapper<T>&& generator) {
+ m_generators.emplace_back(std::move(generator));
+ }
+ void populate(T&& val) {
+ m_generators.emplace_back(value(std::forward<T>(val)));
+ }
+ template<typename U>
+ void populate(U&& val) {
+ populate(T(std::forward<U>(val)));
+ }
+ template<typename U, typename... Gs>
+ void populate(U&& valueOrGenerator, Gs &&... moreGenerators) {
+ populate(std::forward<U>(valueOrGenerator));
+ populate(std::forward<Gs>(moreGenerators)...);
+ }
public:
- RangeGenerator( T const& first, T const& last ) : m_first( first ), m_last( last ) {
- assert( m_last > m_first );
+ template <typename... Gs>
+ Generators(Gs &&... moreGenerators) {
+ m_generators.reserve(sizeof...(Gs));
+ populate(std::forward<Gs>(moreGenerators)...);
}
- auto get( size_t index ) const -> T override {
- // ToDo:: introduce a safe cast to catch potential overflows
- return static_cast<T>(m_first+index);
+ T const& get() const override {
+ return m_generators[m_current].get();
}
- };
- template<typename T>
- struct NullGenerator : IGenerator<T> {
- auto get( size_t ) const -> T override {
- CATCH_INTERNAL_ERROR("A Null Generator is always empty");
+ bool next() override {
+ if (m_current >= m_generators.size()) {
+ return false;
+ }
+ const bool current_status = m_generators[m_current].next();
+ if (!current_status) {
+ ++m_current;
+ }
+ return m_current < m_generators.size();
}
};
+ template<typename... Ts>
+ GeneratorWrapper<std::tuple<Ts...>> table( std::initializer_list<std::tuple<typename std::decay<Ts>::type...>> tuples ) {
+ return values<std::tuple<Ts...>>( tuples );
+ }
+
+ // Tag type to signal that a generator sequence should convert arguments to a specific type
+ template <typename T>
+ struct as {};
+
+ template<typename T, typename... Gs>
+ auto makeGenerators( GeneratorWrapper<T>&& generator, Gs &&... moreGenerators ) -> Generators<T> {
+ return Generators<T>(std::move(generator), std::forward<Gs>(moreGenerators)...);
+ }
template<typename T>
- class Generator {
- std::unique_ptr<IGenerator<T>> m_generator;
- size_t m_size;
+ auto makeGenerators( GeneratorWrapper<T>&& generator ) -> Generators<T> {
+ return Generators<T>(std::move(generator));
+ }
+ template<typename T, typename... Gs>
+ auto makeGenerators( T&& val, Gs &&... moreGenerators ) -> Generators<T> {
+ return makeGenerators( value( std::forward<T>( val ) ), std::forward<Gs>( moreGenerators )... );
+ }
+ template<typename T, typename U, typename... Gs>
+ auto makeGenerators( as<T>, U&& val, Gs &&... moreGenerators ) -> Generators<T> {
+ return makeGenerators( value( T( std::forward<U>( val ) ) ), std::forward<Gs>( moreGenerators )... );
+ }
- public:
- Generator( size_t size, std::unique_ptr<IGenerator<T>> generator )
- : m_generator( std::move( generator ) ),
- m_size( size )
- {}
+ auto acquireGeneratorTracker( StringRef generatorName, SourceLineInfo const& lineInfo ) -> IGeneratorTracker&;
+
+ template<typename L>
+ // Note: The type after -> is weird, because VS2015 cannot parse
+ // the expression used in the typedef inside, when it is in
+ // return type. Yeah.
+ auto generate( StringRef generatorName, SourceLineInfo const& lineInfo, L const& generatorExpression ) -> decltype(std::declval<decltype(generatorExpression())>().get()) {
+ using UnderlyingType = typename decltype(generatorExpression())::type;
- auto size() const -> size_t { return m_size; }
- auto operator[]( size_t index ) const -> T {
- assert( index < m_size );
- return m_generator->get( index );
+ IGeneratorTracker& tracker = acquireGeneratorTracker( generatorName, lineInfo );
+ if (!tracker.hasGenerator()) {
+ tracker.setGenerator(pf::make_unique<Generators<UnderlyingType>>(generatorExpression()));
}
- };
- std::vector<size_t> randomiseIndices( size_t selectionSize, size_t sourceSize );
+ auto const& generator = static_cast<IGenerator<UnderlyingType> const&>( *tracker.getGenerator() );
+ return generator.get();
+ }
- template<typename T>
- class GeneratorRandomiser : public IGenerator<T> {
- Generator<T> m_baseGenerator;
+} // namespace Generators
+} // namespace Catch
+
+#define GENERATE( ... ) \
+ Catch::Generators::generate( INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_UNIQUE_NAME(generator)), \
+ CATCH_INTERNAL_LINEINFO, \
+ [ ]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } ) //NOLINT(google-build-using-namespace)
+#define GENERATE_COPY( ... ) \
+ Catch::Generators::generate( INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_UNIQUE_NAME(generator)), \
+ CATCH_INTERNAL_LINEINFO, \
+ [=]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } ) //NOLINT(google-build-using-namespace)
+#define GENERATE_REF( ... ) \
+ Catch::Generators::generate( INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_UNIQUE_NAME(generator)), \
+ CATCH_INTERNAL_LINEINFO, \
+ [&]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } ) //NOLINT(google-build-using-namespace)
- std::vector<size_t> m_indices;
+// end catch_generators.hpp
+// start catch_generators_generic.hpp
+
+namespace Catch {
+namespace Generators {
+
+ template <typename T>
+ class TakeGenerator : public IGenerator<T> {
+ GeneratorWrapper<T> m_generator;
+ size_t m_returned = 0;
+ size_t m_target;
public:
- GeneratorRandomiser( Generator<T>&& baseGenerator, size_t numberOfItems )
- : m_baseGenerator( std::move( baseGenerator ) ),
- m_indices( randomiseIndices( numberOfItems, m_baseGenerator.size() ) )
- {}
+ TakeGenerator(size_t target, GeneratorWrapper<T>&& generator):
+ m_generator(std::move(generator)),
+ m_target(target)
+ {
+ assert(target != 0 && "Empty generators are not allowed");
+ }
+ T const& get() const override {
+ return m_generator.get();
+ }
+ bool next() override {
+ ++m_returned;
+ if (m_returned >= m_target) {
+ return false;
+ }
- auto get( size_t index ) const -> T override {
- return m_baseGenerator[m_indices[index]];
+ const auto success = m_generator.next();
+ // If the underlying generator does not contain enough values
+ // then we cut short as well
+ if (!success) {
+ m_returned = m_target;
+ }
+ return success;
}
};
- template<typename T>
- struct RequiresASpecialisationFor;
+ template <typename T>
+ GeneratorWrapper<T> take(size_t target, GeneratorWrapper<T>&& generator) {
+ return GeneratorWrapper<T>(pf::make_unique<TakeGenerator<T>>(target, std::move(generator)));
+ }
- template<typename T>
- auto all() -> Generator<T> { return RequiresASpecialisationFor<T>(); }
+ template <typename T, typename Predicate>
+ class FilterGenerator : public IGenerator<T> {
+ GeneratorWrapper<T> m_generator;
+ Predicate m_predicate;
+ public:
+ template <typename P = Predicate>
+ FilterGenerator(P&& pred, GeneratorWrapper<T>&& generator):
+ m_generator(std::move(generator)),
+ m_predicate(std::forward<P>(pred))
+ {
+ if (!m_predicate(m_generator.get())) {
+ // It might happen that there are no values that pass the
+ // filter. In that case we throw an exception.
+ auto has_initial_value = nextImpl();
+ if (!has_initial_value) {
+ Catch::throw_exception(GeneratorException("No valid value found in filtered generator"));
+ }
+ }
+ }
- template<>
- auto all<int>() -> Generator<int>;
+ T const& get() const override {
+ return m_generator.get();
+ }
- template<typename T>
- auto range( T const& first, T const& last ) -> Generator<T> {
- return Generator<T>( (last-first), pf::make_unique<RangeGenerator<T>>( first, last ) );
+ bool next() override {
+ return nextImpl();
+ }
+
+ private:
+ bool nextImpl() {
+ bool success = m_generator.next();
+ if (!success) {
+ return false;
+ }
+ while (!m_predicate(m_generator.get()) && (success = m_generator.next()) == true);
+ return success;
+ }
+ };
+
+ template <typename T, typename Predicate>
+ GeneratorWrapper<T> filter(Predicate&& pred, GeneratorWrapper<T>&& generator) {
+ return GeneratorWrapper<T>(std::unique_ptr<IGenerator<T>>(pf::make_unique<FilterGenerator<T, Predicate>>(std::forward<Predicate>(pred), std::move(generator))));
}
- template<typename T>
- auto random( T const& first, T const& last ) -> Generator<T> {
- auto gen = range( first, last );
- auto size = gen.size();
+ template <typename T>
+ class RepeatGenerator : public IGenerator<T> {
+ static_assert(!std::is_same<T, bool>::value,
+ "RepeatGenerator currently does not support bools"
+ "because of std::vector<bool> specialization");
+ GeneratorWrapper<T> m_generator;
+ mutable std::vector<T> m_returned;
+ size_t m_target_repeats;
+ size_t m_current_repeat = 0;
+ size_t m_repeat_index = 0;
+ public:
+ RepeatGenerator(size_t repeats, GeneratorWrapper<T>&& generator):
+ m_generator(std::move(generator)),
+ m_target_repeats(repeats)
+ {
+ assert(m_target_repeats > 0 && "Repeat generator must repeat at least once");
+ }
+
+ T const& get() const override {
+ if (m_current_repeat == 0) {
+ m_returned.push_back(m_generator.get());
+ return m_returned.back();
+ }
+ return m_returned[m_repeat_index];
+ }
+
+ bool next() override {
+ // There are 2 basic cases:
+ // 1) We are still reading the generator
+ // 2) We are reading our own cache
- return Generator<T>( size, pf::make_unique<GeneratorRandomiser<T>>( std::move( gen ), size ) );
+ // In the first case, we need to poke the underlying generator.
+ // If it happily moves, we are left in that state, otherwise it is time to start reading from our cache
+ if (m_current_repeat == 0) {
+ const auto success = m_generator.next();
+ if (!success) {
+ ++m_current_repeat;
+ }
+ return m_current_repeat < m_target_repeats;
+ }
+
+ // In the second case, we need to move indices forward and check that we haven't run up against the end
+ ++m_repeat_index;
+ if (m_repeat_index == m_returned.size()) {
+ m_repeat_index = 0;
+ ++m_current_repeat;
+ }
+ return m_current_repeat < m_target_repeats;
+ }
+ };
+
+ template <typename T>
+ GeneratorWrapper<T> repeat(size_t repeats, GeneratorWrapper<T>&& generator) {
+ return GeneratorWrapper<T>(pf::make_unique<RepeatGenerator<T>>(repeats, std::move(generator)));
}
- template<typename T>
- auto random( size_t size ) -> Generator<T> {
- return Generator<T>( size, pf::make_unique<GeneratorRandomiser<T>>( all<T>(), size ) );
+
+ template <typename T, typename U, typename Func>
+ class MapGenerator : public IGenerator<T> {
+ // TBD: provide static assert for mapping function, for friendly error message
+ GeneratorWrapper<U> m_generator;
+ Func m_function;
+ // To avoid returning dangling reference, we have to save the values
+ T m_cache;
+ public:
+ template <typename F2 = Func>
+ MapGenerator(F2&& function, GeneratorWrapper<U>&& generator) :
+ m_generator(std::move(generator)),
+ m_function(std::forward<F2>(function)),
+ m_cache(m_function(m_generator.get()))
+ {}
+
+ T const& get() const override {
+ return m_cache;
+ }
+ bool next() override {
+ const auto success = m_generator.next();
+ if (success) {
+ m_cache = m_function(m_generator.get());
+ }
+ return success;
+ }
+ };
+
+ template <typename Func, typename U, typename T = FunctionReturnType<Func, U>>
+ GeneratorWrapper<T> map(Func&& function, GeneratorWrapper<U>&& generator) {
+ return GeneratorWrapper<T>(
+ pf::make_unique<MapGenerator<T, U, Func>>(std::forward<Func>(function), std::move(generator))
+ );
}
- template<typename T>
- auto values( std::initializer_list<T> values ) -> Generator<T> {
- return Generator<T>( values.size(), pf::make_unique<FixedValuesGenerator<T>>( values ) );
+ template <typename T, typename U, typename Func>
+ GeneratorWrapper<T> map(Func&& function, GeneratorWrapper<U>&& generator) {
+ return GeneratorWrapper<T>(
+ pf::make_unique<MapGenerator<T, U, Func>>(std::forward<Func>(function), std::move(generator))
+ );
}
- template<typename T>
- auto value( T const& val ) -> Generator<T> {
- return Generator<T>( 1, pf::make_unique<SingleValueGenerator<T>>( val ) );
+
+ template <typename T>
+ class ChunkGenerator final : public IGenerator<std::vector<T>> {
+ std::vector<T> m_chunk;
+ size_t m_chunk_size;
+ GeneratorWrapper<T> m_generator;
+ bool m_used_up = false;
+ public:
+ ChunkGenerator(size_t size, GeneratorWrapper<T> generator) :
+ m_chunk_size(size), m_generator(std::move(generator))
+ {
+ m_chunk.reserve(m_chunk_size);
+ if (m_chunk_size != 0) {
+ m_chunk.push_back(m_generator.get());
+ for (size_t i = 1; i < m_chunk_size; ++i) {
+ if (!m_generator.next()) {
+ Catch::throw_exception(GeneratorException("Not enough values to initialize the first chunk"));
+ }
+ m_chunk.push_back(m_generator.get());
+ }
+ }
+ }
+ std::vector<T> const& get() const override {
+ return m_chunk;
+ }
+ bool next() override {
+ m_chunk.clear();
+ for (size_t idx = 0; idx < m_chunk_size; ++idx) {
+ if (!m_generator.next()) {
+ return false;
+ }
+ m_chunk.push_back(m_generator.get());
+ }
+ return true;
+ }
+ };
+
+ template <typename T>
+ GeneratorWrapper<std::vector<T>> chunk(size_t size, GeneratorWrapper<T>&& generator) {
+ return GeneratorWrapper<std::vector<T>>(
+ pf::make_unique<ChunkGenerator<T>>(size, std::move(generator))
+ );
}
- template<typename T>
- auto as() -> Generator<T> {
- return Generator<T>( 0, pf::make_unique<NullGenerator<T>>() );
+} // namespace Generators
+} // namespace Catch
+
+// end catch_generators_generic.hpp
+// start catch_generators_specific.hpp
+
+// start catch_context.h
+
+#include <memory>
+
+namespace Catch {
+
+ struct IResultCapture;
+ struct IRunner;
+ struct IConfig;
+ struct IMutableContext;
+
+ using IConfigPtr = std::shared_ptr<IConfig const>;
+
+ struct IContext
+ {
+ virtual ~IContext();
+
+ virtual IResultCapture* getResultCapture() = 0;
+ virtual IRunner* getRunner() = 0;
+ virtual IConfigPtr const& getConfig() const = 0;
+ };
+
+ struct IMutableContext : IContext
+ {
+ virtual ~IMutableContext();
+ virtual void setResultCapture( IResultCapture* resultCapture ) = 0;
+ virtual void setRunner( IRunner* runner ) = 0;
+ virtual void setConfig( IConfigPtr const& config ) = 0;
+
+ private:
+ static IMutableContext *currentContext;
+ friend IMutableContext& getCurrentMutableContext();
+ friend void cleanUpContext();
+ static void createContext();
+ };
+
+ inline IMutableContext& getCurrentMutableContext()
+ {
+ if( !IMutableContext::currentContext )
+ IMutableContext::createContext();
+ // NOLINTNEXTLINE(clang-analyzer-core.uninitialized.UndefReturn)
+ return *IMutableContext::currentContext;
}
- template<typename... Ts>
- auto table( std::initializer_list<std::tuple<Ts...>>&& tuples ) -> Generator<std::tuple<Ts...>> {
- return values<std::tuple<Ts...>>( std::forward<std::initializer_list<std::tuple<Ts...>>>( tuples ) );
+ inline IContext& getCurrentContext()
+ {
+ return getCurrentMutableContext();
}
- template<typename T>
- struct Generators : GeneratorBase {
- std::vector<Generator<T>> m_generators;
+ void cleanUpContext();
- using type = T;
+ class SimplePcg32;
+ SimplePcg32& rng();
+}
+
+// end catch_context.h
+// start catch_interfaces_config.h
+
+// start catch_option.hpp
- Generators() : GeneratorBase( 0 ) {}
+namespace Catch {
- void populate( T&& val ) {
- m_size += 1;
- m_generators.emplace_back( value( std::move( val ) ) );
+ // An optional type
+ template<typename T>
+ class Option {
+ public:
+ Option() : nullableValue( nullptr ) {}
+ Option( T const& _value )
+ : nullableValue( new( storage ) T( _value ) )
+ {}
+ Option( Option const& _other )
+ : nullableValue( _other ? new( storage ) T( *_other ) : nullptr )
+ {}
+
+ ~Option() {
+ reset();
}
- template<typename U>
- void populate( U&& val ) {
- populate( T( std::move( val ) ) );
+
+ Option& operator= ( Option const& _other ) {
+ if( &_other != this ) {
+ reset();
+ if( _other )
+ nullableValue = new( storage ) T( *_other );
+ }
+ return *this;
+ }
+ Option& operator = ( T const& _value ) {
+ reset();
+ nullableValue = new( storage ) T( _value );
+ return *this;
}
- void populate( Generator<T>&& generator ) {
- m_size += generator.size();
- m_generators.emplace_back( std::move( generator ) );
+
+ void reset() {
+ if( nullableValue )
+ nullableValue->~T();
+ nullableValue = nullptr;
}
- template<typename U, typename... Gs>
- void populate( U&& valueOrGenerator, Gs... moreGenerators ) {
- populate( std::forward<U>( valueOrGenerator ) );
- populate( std::forward<Gs>( moreGenerators )... );
+ T& operator*() { return *nullableValue; }
+ T const& operator*() const { return *nullableValue; }
+ T* operator->() { return nullableValue; }
+ const T* operator->() const { return nullableValue; }
+
+ T valueOr( T const& defaultValue ) const {
+ return nullableValue ? *nullableValue : defaultValue;
}
- auto operator[]( size_t index ) const -> T {
- size_t sizes = 0;
- for( auto const& gen : m_generators ) {
- auto localIndex = index-sizes;
- sizes += gen.size();
- if( index < sizes )
- return gen[localIndex];
- }
- CATCH_INTERNAL_ERROR("Index '" << index << "' is out of range (" << sizes << ')');
+ bool some() const { return nullableValue != nullptr; }
+ bool none() const { return nullableValue == nullptr; }
+
+ bool operator !() const { return nullableValue == nullptr; }
+ explicit operator bool() const {
+ return some();
}
+
+ private:
+ T *nullableValue;
+ alignas(alignof(T)) char storage[sizeof(T)];
};
- template<typename T, typename... Gs>
- auto makeGenerators( Generator<T>&& generator, Gs... moreGenerators ) -> Generators<T> {
- Generators<T> generators;
- generators.m_generators.reserve( 1+sizeof...(Gs) );
- generators.populate( std::move( generator ), std::forward<Gs>( moreGenerators )... );
- return generators;
+} // end namespace Catch
+
+// end catch_option.hpp
+#include <chrono>
+#include <iosfwd>
+#include <string>
+#include <vector>
+#include <memory>
+
+namespace Catch {
+
+ enum class Verbosity {
+ Quiet = 0,
+ Normal,
+ High
+ };
+
+ struct WarnAbout { enum What {
+ Nothing = 0x00,
+ NoAssertions = 0x01,
+ NoTests = 0x02
+ }; };
+
+ struct ShowDurations { enum OrNot {
+ DefaultForReporter,
+ Always,
+ Never
+ }; };
+ struct RunTests { enum InWhatOrder {
+ InDeclarationOrder,
+ InLexicographicalOrder,
+ InRandomOrder
+ }; };
+ struct UseColour { enum YesOrNo {
+ Auto,
+ Yes,
+ No
+ }; };
+ struct WaitForKeypress { enum When {
+ Never,
+ BeforeStart = 1,
+ BeforeExit = 2,
+ BeforeStartAndExit = BeforeStart | BeforeExit
+ }; };
+
+ class TestSpec;
+
+ struct IConfig : NonCopyable {
+
+ virtual ~IConfig();
+
+ virtual bool allowThrows() const = 0;
+ virtual std::ostream& stream() const = 0;
+ virtual std::string name() const = 0;
+ virtual bool includeSuccessfulResults() const = 0;
+ virtual bool shouldDebugBreak() const = 0;
+ virtual bool warnAboutMissingAssertions() const = 0;
+ virtual bool warnAboutNoTests() const = 0;
+ virtual int abortAfter() const = 0;
+ virtual bool showInvisibles() const = 0;
+ virtual ShowDurations::OrNot showDurations() const = 0;
+ virtual double minDuration() const = 0;
+ virtual TestSpec const& testSpec() const = 0;
+ virtual bool hasTestFilters() const = 0;
+ virtual std::vector<std::string> const& getTestsOrTags() const = 0;
+ virtual RunTests::InWhatOrder runOrder() const = 0;
+ virtual unsigned int rngSeed() const = 0;
+ virtual UseColour::YesOrNo useColour() const = 0;
+ virtual std::vector<std::string> const& getSectionsToRun() const = 0;
+ virtual Verbosity verbosity() const = 0;
+
+ virtual bool benchmarkNoAnalysis() const = 0;
+ virtual int benchmarkSamples() const = 0;
+ virtual double benchmarkConfidenceInterval() const = 0;
+ virtual unsigned int benchmarkResamples() const = 0;
+ virtual std::chrono::milliseconds benchmarkWarmupTime() const = 0;
+ };
+
+ using IConfigPtr = std::shared_ptr<IConfig const>;
+}
+
+// end catch_interfaces_config.h
+// start catch_random_number_generator.h
+
+#include <cstdint>
+
+namespace Catch {
+
+ // This is a simple implementation of C++11 Uniform Random Number
+ // Generator. It does not provide all operators, because Catch2
+ // does not use it, but it should behave as expected inside stdlib's
+ // distributions.
+ // The implementation is based on the PCG family (http://pcg-random.org)
+ class SimplePcg32 {
+ using state_type = std::uint64_t;
+ public:
+ using result_type = std::uint32_t;
+ static constexpr result_type (min)() {
+ return 0;
+ }
+ static constexpr result_type (max)() {
+ return static_cast<result_type>(-1);
+ }
+
+ // Provide some default initial state for the default constructor
+ SimplePcg32():SimplePcg32(0xed743cc4U) {}
+
+ explicit SimplePcg32(result_type seed_);
+
+ void seed(result_type seed_);
+ void discard(uint64_t skip);
+
+ result_type operator()();
+
+ private:
+ friend bool operator==(SimplePcg32 const& lhs, SimplePcg32 const& rhs);
+ friend bool operator!=(SimplePcg32 const& lhs, SimplePcg32 const& rhs);
+
+ // In theory we also need operator<< and operator>>
+ // In practice we do not use them, so we will skip them for now
+
+ std::uint64_t m_state;
+ // This part of the state determines which "stream" of the numbers
+ // is chosen -- we take it as a constant for Catch2, so we only
+ // need to deal with seeding the main state.
+ // Picked by reading 8 bytes from `/dev/random` :-)
+ static const std::uint64_t s_inc = (0x13ed0cc53f939476ULL << 1ULL) | 1ULL;
+ };
+
+} // end namespace Catch
+
+// end catch_random_number_generator.h
+#include <random>
+
+namespace Catch {
+namespace Generators {
+
+template <typename Float>
+class RandomFloatingGenerator final : public IGenerator<Float> {
+ Catch::SimplePcg32& m_rng;
+ std::uniform_real_distribution<Float> m_dist;
+ Float m_current_number;
+public:
+
+ RandomFloatingGenerator(Float a, Float b):
+ m_rng(rng()),
+ m_dist(a, b) {
+ static_cast<void>(next());
}
- template<typename T>
- auto makeGenerators( Generator<T>&& generator ) -> Generators<T> {
- Generators<T> generators;
- generators.populate( std::move( generator ) );
- return generators;
+
+ Float const& get() const override {
+ return m_current_number;
}
- template<typename T, typename... Gs>
- auto makeGenerators( T&& val, Gs... moreGenerators ) -> Generators<T> {
- return makeGenerators( value( std::forward<T>( val ) ), std::forward<Gs>( moreGenerators )... );
+ bool next() override {
+ m_current_number = m_dist(m_rng);
+ return true;
}
- template<typename T, typename U, typename... Gs>
- auto makeGenerators( U&& val, Gs... moreGenerators ) -> Generators<T> {
- return makeGenerators( value( T( std::forward<U>( val ) ) ), std::forward<Gs>( moreGenerators )... );
+};
+
+template <typename Integer>
+class RandomIntegerGenerator final : public IGenerator<Integer> {
+ Catch::SimplePcg32& m_rng;
+ std::uniform_int_distribution<Integer> m_dist;
+ Integer m_current_number;
+public:
+
+ RandomIntegerGenerator(Integer a, Integer b):
+ m_rng(rng()),
+ m_dist(a, b) {
+ static_cast<void>(next());
}
- auto acquireGeneratorTracker( SourceLineInfo const& lineInfo ) -> IGeneratorTracker&;
+ Integer const& get() const override {
+ return m_current_number;
+ }
+ bool next() override {
+ m_current_number = m_dist(m_rng);
+ return true;
+ }
+};
- template<typename L>
- // Note: The type after -> is weird, because VS2015 cannot parse
- // the expression used in the typedef inside, when it is in
- // return type. Yeah, ¯\_(ツ)_/¯
- auto generate( SourceLineInfo const& lineInfo, L const& generatorExpression ) -> decltype(std::declval<decltype(generatorExpression())>()[0]) {
- using UnderlyingType = typename decltype(generatorExpression())::type;
+// TODO: Ideally this would be also constrained against the various char types,
+// but I don't expect users to run into that in practice.
+template <typename T>
+typename std::enable_if<std::is_integral<T>::value && !std::is_same<T, bool>::value,
+GeneratorWrapper<T>>::type
+random(T a, T b) {
+ return GeneratorWrapper<T>(
+ pf::make_unique<RandomIntegerGenerator<T>>(a, b)
+ );
+}
+
+template <typename T>
+typename std::enable_if<std::is_floating_point<T>::value,
+GeneratorWrapper<T>>::type
+random(T a, T b) {
+ return GeneratorWrapper<T>(
+ pf::make_unique<RandomFloatingGenerator<T>>(a, b)
+ );
+}
+
+template <typename T>
+class RangeGenerator final : public IGenerator<T> {
+ T m_current;
+ T m_end;
+ T m_step;
+ bool m_positive;
+
+public:
+ RangeGenerator(T const& start, T const& end, T const& step):
+ m_current(start),
+ m_end(end),
+ m_step(step),
+ m_positive(m_step > T(0))
+ {
+ assert(m_current != m_end && "Range start and end cannot be equal");
+ assert(m_step != T(0) && "Step size cannot be zero");
+ assert(((m_positive && m_current <= m_end) || (!m_positive && m_current >= m_end)) && "Step moves away from end");
+ }
+
+ RangeGenerator(T const& start, T const& end):
+ RangeGenerator(start, end, (start < end) ? T(1) : T(-1))
+ {}
+
+ T const& get() const override {
+ return m_current;
+ }
- IGeneratorTracker& tracker = acquireGeneratorTracker( lineInfo );
- if( !tracker.hasGenerator() )
- tracker.setGenerator( pf::make_unique<Generators<UnderlyingType>>( generatorExpression() ) );
+ bool next() override {
+ m_current += m_step;
+ return (m_positive) ? (m_current < m_end) : (m_current > m_end);
+ }
+};
+
+template <typename T>
+GeneratorWrapper<T> range(T const& start, T const& end, T const& step) {
+ static_assert(std::is_arithmetic<T>::value && !std::is_same<T, bool>::value, "Type must be numeric");
+ return GeneratorWrapper<T>(pf::make_unique<RangeGenerator<T>>(start, end, step));
+}
+
+template <typename T>
+GeneratorWrapper<T> range(T const& start, T const& end) {
+ static_assert(std::is_integral<T>::value && !std::is_same<T, bool>::value, "Type must be an integer");
+ return GeneratorWrapper<T>(pf::make_unique<RangeGenerator<T>>(start, end));
+}
+
+template <typename T>
+class IteratorGenerator final : public IGenerator<T> {
+ static_assert(!std::is_same<T, bool>::value,
+ "IteratorGenerator currently does not support bools"
+ "because of std::vector<bool> specialization");
- auto const& generator = static_cast<Generators<UnderlyingType> const&>( *tracker.getGenerator() );
- return generator[tracker.getIndex()];
+ std::vector<T> m_elems;
+ size_t m_current = 0;
+public:
+ template <typename InputIterator, typename InputSentinel>
+ IteratorGenerator(InputIterator first, InputSentinel last):m_elems(first, last) {
+ if (m_elems.empty()) {
+ Catch::throw_exception(GeneratorException("IteratorGenerator received no valid values"));
+ }
}
+ T const& get() const override {
+ return m_elems[m_current];
+ }
+
+ bool next() override {
+ ++m_current;
+ return m_current != m_elems.size();
+ }
+};
+
+template <typename InputIterator,
+ typename InputSentinel,
+ typename ResultType = typename std::iterator_traits<InputIterator>::value_type>
+GeneratorWrapper<ResultType> from_range(InputIterator from, InputSentinel to) {
+ return GeneratorWrapper<ResultType>(pf::make_unique<IteratorGenerator<ResultType>>(from, to));
+}
+
+template <typename Container,
+ typename ResultType = typename Container::value_type>
+GeneratorWrapper<ResultType> from_range(Container const& cnt) {
+ return GeneratorWrapper<ResultType>(pf::make_unique<IteratorGenerator<ResultType>>(cnt.begin(), cnt.end()));
+}
+
} // namespace Generators
} // namespace Catch
-#define GENERATE( ... ) \
- Catch::Generators::generate( CATCH_INTERNAL_LINEINFO, []{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } )
-
-// end catch_generators.hpp
+// end catch_generators_specific.hpp
// These files are included here so the single_include script doesn't put them
// in the conditionally compiled sections
@@ -3662,7 +4950,7 @@ namespace Catch {
arcSafeRelease( m_substr );
}
- bool match( NSString* arg ) const override {
+ bool match( NSString* str ) const override {
return false;
}
@@ -3685,7 +4973,7 @@ namespace Catch {
struct Contains : StringHolder {
Contains( NSString* substr ) : StringHolder( substr ){}
- bool match( NSString* str ) const {
+ bool match( NSString* str ) const override {
return (str != nil || m_substr == nil ) &&
[str rangeOfString:m_substr].location != NSNotFound;
}
@@ -3761,7 +5049,8 @@ return @ desc; \
// end catch_objc.hpp
#endif
-#ifdef CATCH_CONFIG_EXTERNAL_INTERFACES
+// Benchmarking needs the externally-facing parts of reporters to work
+#if defined(CATCH_CONFIG_EXTERNAL_INTERFACES) || defined(CATCH_CONFIG_ENABLE_BENCHMARKING)
// start catch_external_interfaces.h
// start catch_reporter_bases.hpp
@@ -3803,7 +5092,7 @@ namespace Catch
virtual bool matches( std::string const& str ) const;
private:
- std::string adjustCase( std::string const& str ) const;
+ std::string normaliseString( std::string const& str ) const;
CaseSensitive::Choice m_caseSensitivity;
WildcardPosition m_wildcard = NoWildcard;
std::string m_pattern;
@@ -3817,36 +5106,40 @@ namespace Catch
namespace Catch {
+ struct IConfig;
+
class TestSpec {
- struct Pattern {
+ class Pattern {
+ public:
+ explicit Pattern( std::string const& name );
virtual ~Pattern();
virtual bool matches( TestCaseInfo const& testCase ) const = 0;
+ std::string const& name() const;
+ private:
+ std::string const m_name;
};
using PatternPtr = std::shared_ptr<Pattern>;
class NamePattern : public Pattern {
public:
- NamePattern( std::string const& name );
- virtual ~NamePattern();
- virtual bool matches( TestCaseInfo const& testCase ) const override;
+ explicit NamePattern( std::string const& name, std::string const& filterString );
+ bool matches( TestCaseInfo const& testCase ) const override;
private:
WildcardPattern m_wildcardPattern;
};
class TagPattern : public Pattern {
public:
- TagPattern( std::string const& tag );
- virtual ~TagPattern();
- virtual bool matches( TestCaseInfo const& testCase ) const override;
+ explicit TagPattern( std::string const& tag, std::string const& filterString );
+ bool matches( TestCaseInfo const& testCase ) const override;
private:
std::string m_tag;
};
class ExcludedPattern : public Pattern {
public:
- ExcludedPattern( PatternPtr const& underlyingPattern );
- virtual ~ExcludedPattern();
- virtual bool matches( TestCaseInfo const& testCase ) const override;
+ explicit ExcludedPattern( PatternPtr const& underlyingPattern );
+ bool matches( TestCaseInfo const& testCase ) const override;
private:
PatternPtr m_underlyingPattern;
};
@@ -3855,15 +5148,25 @@ namespace Catch {
std::vector<PatternPtr> m_patterns;
bool matches( TestCaseInfo const& testCase ) const;
+ std::string name() const;
};
public:
+ struct FilterMatch {
+ std::string name;
+ std::vector<TestCase const*> tests;
+ };
+ using Matches = std::vector<FilterMatch>;
+ using vectorStrings = std::vector<std::string>;
+
bool hasFilters() const;
bool matches( TestCaseInfo const& testCase ) const;
+ Matches matchesByFilter( std::vector<TestCase> const& testCases, IConfig const& config ) const;
+ const vectorStrings & getInvalidArgs() const;
private:
std::vector<Filter> m_filters;
-
+ std::vector<std::string> m_invalidArgs;
friend class TestSpecParser;
};
}
@@ -3898,9 +5201,13 @@ namespace Catch {
class TestSpecParser {
enum Mode{ None, Name, QuotedName, Tag, EscapedName };
Mode m_mode = None;
+ Mode lastMode = None;
bool m_exclusion = false;
- std::size_t m_start = std::string::npos, m_pos = 0;
+ std::size_t m_pos = 0;
+ std::size_t m_realPatternPos = 0;
std::string m_arg;
+ std::string m_substring;
+ std::string m_patternName;
std::vector<std::size_t> m_escapeChars;
TestSpec::Filter m_currentFilter;
TestSpec m_testSpec;
@@ -3913,32 +5220,32 @@ namespace Catch {
TestSpec testSpec();
private:
- void visitChar( char c );
- void startNewMode( Mode mode, std::size_t start );
+ bool visitChar( char c );
+ void startNewMode( Mode mode );
+ bool processNoneChar( char c );
+ void processNameChar( char c );
+ bool processOtherChar( char c );
+ void endMode();
void escape();
- std::string subString() const;
+ bool isControlChar( char c ) const;
+ void saveLastMode();
+ void revertBackToLastMode();
+ void addFilter();
+ bool separate();
- template<typename T>
- void addPattern() {
- std::string token = subString();
- for( std::size_t i = 0; i < m_escapeChars.size(); ++i )
- token = token.substr( 0, m_escapeChars[i]-m_start-i ) + token.substr( m_escapeChars[i]-m_start-i+1 );
- m_escapeChars.clear();
- if( startsWith( token, "exclude:" ) ) {
- m_exclusion = true;
- token = token.substr( 8 );
- }
- if( !token.empty() ) {
- TestSpec::PatternPtr pattern = std::make_shared<T>( token );
- if( m_exclusion )
- pattern = std::make_shared<TestSpec::ExcludedPattern>( pattern );
- m_currentFilter.m_patterns.push_back( pattern );
- }
- m_exclusion = false;
- m_mode = None;
+ // Handles common preprocessing of the pattern for name/tag patterns
+ std::string preprocessPattern();
+ // Adds the current pattern as a test name
+ void addNamePattern();
+ // Adds the current pattern as a tag
+ void addTagPattern();
+
+ inline void addCharToPattern(char c) {
+ m_substring += c;
+ m_patternName += c;
+ m_realPatternPos++;
}
- void addFilter();
};
TestSpec parseTestSpec( std::string const& arg );
@@ -3949,79 +5256,6 @@ namespace Catch {
#endif
// end catch_test_spec_parser.h
-// start catch_interfaces_config.h
-
-#include <iosfwd>
-#include <string>
-#include <vector>
-#include <memory>
-
-namespace Catch {
-
- enum class Verbosity {
- Quiet = 0,
- Normal,
- High
- };
-
- struct WarnAbout { enum What {
- Nothing = 0x00,
- NoAssertions = 0x01,
- NoTests = 0x02
- }; };
-
- struct ShowDurations { enum OrNot {
- DefaultForReporter,
- Always,
- Never
- }; };
- struct RunTests { enum InWhatOrder {
- InDeclarationOrder,
- InLexicographicalOrder,
- InRandomOrder
- }; };
- struct UseColour { enum YesOrNo {
- Auto,
- Yes,
- No
- }; };
- struct WaitForKeypress { enum When {
- Never,
- BeforeStart = 1,
- BeforeExit = 2,
- BeforeStartAndExit = BeforeStart | BeforeExit
- }; };
-
- class TestSpec;
-
- struct IConfig : NonCopyable {
-
- virtual ~IConfig();
-
- virtual bool allowThrows() const = 0;
- virtual std::ostream& stream() const = 0;
- virtual std::string name() const = 0;
- virtual bool includeSuccessfulResults() const = 0;
- virtual bool shouldDebugBreak() const = 0;
- virtual bool warnAboutMissingAssertions() const = 0;
- virtual bool warnAboutNoTests() const = 0;
- virtual int abortAfter() const = 0;
- virtual bool showInvisibles() const = 0;
- virtual ShowDurations::OrNot showDurations() const = 0;
- virtual TestSpec const& testSpec() const = 0;
- virtual bool hasTestFilters() const = 0;
- virtual RunTests::InWhatOrder runOrder() const = 0;
- virtual unsigned int rngSeed() const = 0;
- virtual int benchmarkResolutionMultiple() const = 0;
- virtual UseColour::YesOrNo useColour() const = 0;
- virtual std::vector<std::string> const& getSectionsToRun() const = 0;
- virtual Verbosity verbosity() const = 0;
- };
-
- using IConfigPtr = std::shared_ptr<IConfig const>;
-}
-
-// end catch_interfaces_config.h
// Libstdc++ doesn't like incomplete classes for unique_ptr
#include <memory>
@@ -4052,11 +5286,17 @@ namespace Catch {
int abortAfter = -1;
unsigned int rngSeed = 0;
- int benchmarkResolutionMultiple = 100;
+
+ bool benchmarkNoAnalysis = false;
+ unsigned int benchmarkSamples = 100;
+ double benchmarkConfidenceInterval = 0.95;
+ unsigned int benchmarkResamples = 100000;
+ std::chrono::milliseconds::rep benchmarkWarmupTime = 100;
Verbosity verbosity = Verbosity::Normal;
WarnAbout::What warnings = WarnAbout::Nothing;
ShowDurations::OrNot showDurations = ShowDurations::DefaultForReporter;
+ double minDuration = -1;
RunTests::InWhatOrder runOrder = RunTests::InDeclarationOrder;
UseColour::YesOrNo useColour = UseColour::Auto;
WaitForKeypress::When waitForKeypress = WaitForKeypress::Never;
@@ -4091,10 +5331,10 @@ namespace Catch {
std::string getProcessName() const;
std::string const& getReporterName() const;
- std::vector<std::string> const& getTestsOrTags() const;
+ std::vector<std::string> const& getTestsOrTags() const override;
std::vector<std::string> const& getSectionsToRun() const override;
- virtual TestSpec const& testSpec() const override;
+ TestSpec const& testSpec() const override;
bool hasTestFilters() const override;
bool showHelp() const;
@@ -4107,14 +5347,19 @@ namespace Catch {
bool warnAboutMissingAssertions() const override;
bool warnAboutNoTests() const override;
ShowDurations::OrNot showDurations() const override;
+ double minDuration() const override;
RunTests::InWhatOrder runOrder() const override;
unsigned int rngSeed() const override;
- int benchmarkResolutionMultiple() const override;
UseColour::YesOrNo useColour() const override;
bool shouldDebugBreak() const override;
int abortAfter() const override;
bool showInvisibles() const override;
Verbosity verbosity() const override;
+ bool benchmarkNoAnalysis() const override;
+ int benchmarkSamples() const override;
+ double benchmarkConfidenceInterval() const override;
+ unsigned int benchmarkResamples() const override;
+ std::chrono::milliseconds benchmarkWarmupTime() const override;
private:
@@ -4175,76 +5420,61 @@ namespace Catch {
} // end namespace Catch
// end catch_assertionresult.h
-// start catch_option.hpp
+#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)
+// start catch_estimate.hpp
-namespace Catch {
-
- // An optional type
- template<typename T>
- class Option {
- public:
- Option() : nullableValue( nullptr ) {}
- Option( T const& _value )
- : nullableValue( new( storage ) T( _value ) )
- {}
- Option( Option const& _other )
- : nullableValue( _other ? new( storage ) T( *_other ) : nullptr )
- {}
+ // Statistics estimates
- ~Option() {
- reset();
- }
- Option& operator= ( Option const& _other ) {
- if( &_other != this ) {
- reset();
- if( _other )
- nullableValue = new( storage ) T( *_other );
+namespace Catch {
+ namespace Benchmark {
+ template <typename Duration>
+ struct Estimate {
+ Duration point;
+ Duration lower_bound;
+ Duration upper_bound;
+ double confidence_interval;
+
+ template <typename Duration2>
+ operator Estimate<Duration2>() const {
+ return { point, lower_bound, upper_bound, confidence_interval };
}
- return *this;
- }
- Option& operator = ( T const& _value ) {
- reset();
- nullableValue = new( storage ) T( _value );
- return *this;
- }
-
- void reset() {
- if( nullableValue )
- nullableValue->~T();
- nullableValue = nullptr;
- }
+ };
+ } // namespace Benchmark
+} // namespace Catch
- T& operator*() { return *nullableValue; }
- T const& operator*() const { return *nullableValue; }
- T* operator->() { return nullableValue; }
- const T* operator->() const { return nullableValue; }
+// end catch_estimate.hpp
+// start catch_outlier_classification.hpp
- T valueOr( T const& defaultValue ) const {
- return nullableValue ? *nullableValue : defaultValue;
- }
-
- bool some() const { return nullableValue != nullptr; }
- bool none() const { return nullableValue == nullptr; }
+// Outlier information
- bool operator !() const { return nullableValue == nullptr; }
- explicit operator bool() const {
- return some();
- }
+namespace Catch {
+ namespace Benchmark {
+ struct OutlierClassification {
+ int samples_seen = 0;
+ int low_severe = 0; // more than 3 times IQR below Q1
+ int low_mild = 0; // 1.5 to 3 times IQR below Q1
+ int high_mild = 0; // 1.5 to 3 times IQR above Q3
+ int high_severe = 0; // more than 3 times IQR above Q3
+
+ int total() const {
+ return low_severe + low_mild + high_mild + high_severe;
+ }
+ };
+ } // namespace Benchmark
+} // namespace Catch
- private:
- T *nullableValue;
- alignas(alignof(T)) char storage[sizeof(T)];
- };
+// end catch_outlier_classification.hpp
-} // end namespace Catch
+#include <iterator>
+#endif // CATCH_CONFIG_ENABLE_BENCHMARKING
-// end catch_option.hpp
#include <string>
#include <iosfwd>
#include <map>
#include <set>
#include <memory>
+#include <algorithm>
namespace Catch {
@@ -4301,8 +5531,8 @@ namespace Catch {
AssertionStats( AssertionStats const& ) = default;
AssertionStats( AssertionStats && ) = default;
- AssertionStats& operator = ( AssertionStats const& ) = default;
- AssertionStats& operator = ( AssertionStats && ) = default;
+ AssertionStats& operator = ( AssertionStats const& ) = delete;
+ AssertionStats& operator = ( AssertionStats && ) = delete;
virtual ~AssertionStats();
AssertionResult assertionResult;
@@ -4380,14 +5610,43 @@ namespace Catch {
bool aborting;
};
+#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)
struct BenchmarkInfo {
std::string name;
+ double estimatedDuration;
+ int iterations;
+ int samples;
+ unsigned int resamples;
+ double clockResolution;
+ double clockCost;
};
+
+ template <class Duration>
struct BenchmarkStats {
BenchmarkInfo info;
- std::size_t iterations;
- uint64_t elapsedTimeInNanoseconds;
+
+ std::vector<Duration> samples;
+ Benchmark::Estimate<Duration> mean;
+ Benchmark::Estimate<Duration> standardDeviation;
+ Benchmark::OutlierClassification outliers;
+ double outlierVariance;
+
+ template <typename Duration2>
+ operator BenchmarkStats<Duration2>() const {
+ std::vector<Duration2> samples2;
+ samples2.reserve(samples.size());
+ std::transform(samples.begin(), samples.end(), std::back_inserter(samples2), [](Duration d) { return Duration2(d); });
+ return {
+ info,
+ std::move(samples2),
+ mean,
+ standardDeviation,
+ outliers,
+ outlierVariance,
+ };
+ }
};
+#endif // CATCH_CONFIG_ENABLE_BENCHMARKING
struct IStreamingReporter {
virtual ~IStreamingReporter() = default;
@@ -4400,23 +5659,26 @@ namespace Catch {
virtual void noMatchingTestCases( std::string const& spec ) = 0;
+ virtual void reportInvalidArguments(std::string const&) {}
+
virtual void testRunStarting( TestRunInfo const& testRunInfo ) = 0;
virtual void testGroupStarting( GroupInfo const& groupInfo ) = 0;
virtual void testCaseStarting( TestCaseInfo const& testInfo ) = 0;
virtual void sectionStarting( SectionInfo const& sectionInfo ) = 0;
- // *** experimental ***
+#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)
+ virtual void benchmarkPreparing( std::string const& ) {}
virtual void benchmarkStarting( BenchmarkInfo const& ) {}
+ virtual void benchmarkEnded( BenchmarkStats<> const& ) {}
+ virtual void benchmarkFailed( std::string const& ) {}
+#endif // CATCH_CONFIG_ENABLE_BENCHMARKING
virtual void assertionStarting( AssertionInfo const& assertionInfo ) = 0;
// The return value indicates if the messages buffer should be cleared:
virtual bool assertionEnded( AssertionStats const& assertionStats ) = 0;
- // *** experimental ***
- virtual void benchmarkEnded( BenchmarkStats const& ) {}
-
virtual void sectionEnded( SectionStats const& sectionStats ) = 0;
virtual void testCaseEnded( TestCaseStats const& testCaseStats ) = 0;
virtual void testGroupEnded( TestGroupStats const& testGroupStats ) = 0;
@@ -4465,6 +5727,11 @@ namespace Catch {
// Returns double formatted as %.3f (format expected on output)
std::string getFormattedDuration( double duration );
+ //! Should the reporter show
+ bool shouldShowDuration( IConfig const& config, double duration );
+
+ std::string serializeFilters( std::vector<std::string> const& container );
+
template<typename DerivedT>
struct StreamingReporterBase : IStreamingReporter {
@@ -4489,9 +5756,12 @@ namespace Catch {
void noMatchingTestCases(std::string const&) override {}
+ void reportInvalidArguments(std::string const&) override {}
+
void testRunStarting(TestRunInfo const& _testRunInfo) override {
currentTestRunInfo = _testRunInfo;
}
+
void testGroupStarting(GroupInfo const& _groupInfo) override {
currentGroupInfo = _groupInfo;
}
@@ -4782,11 +6052,11 @@ namespace Catch {
class ReporterFactory : public IReporterFactory {
- virtual IStreamingReporterPtr create( ReporterConfig const& config ) const override {
+ IStreamingReporterPtr create( ReporterConfig const& config ) const override {
return std::unique_ptr<T>( new T( config ) );
}
- virtual std::string getDescription() const override {
+ std::string getDescription() const override {
return T::getDescription();
}
};
@@ -4803,10 +6073,10 @@ namespace Catch {
class ListenerFactory : public IReporterFactory {
- virtual IStreamingReporterPtr create( ReporterConfig const& config ) const override {
+ IStreamingReporterPtr create( ReporterConfig const& config ) const override {
return std::unique_ptr<T>( new T( config ) );
}
- virtual std::string getDescription() const override {
+ std::string getDescription() const override {
return std::string();
}
};
@@ -4822,14 +6092,16 @@ namespace Catch {
#if !defined(CATCH_CONFIG_DISABLE)
#define CATCH_REGISTER_REPORTER( name, reporterType ) \
+ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
namespace{ Catch::ReporterRegistrar<reporterType> catch_internal_RegistrarFor##reporterType( name ); } \
- CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS
+ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
#define CATCH_REGISTER_LISTENER( listenerType ) \
- CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
- namespace{ Catch::ListenerRegistrar<listenerType> catch_internal_RegistrarFor##listenerType; } \
- CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS
+ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
+ CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
+ namespace{ Catch::ListenerRegistrar<listenerType> catch_internal_RegistrarFor##listenerType; } \
+ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
#else // CATCH_CONFIG_DISABLE
#define CATCH_REGISTER_REPORTER(name, reporterType)
@@ -4851,8 +6123,6 @@ namespace Catch {
static std::string getDescription();
- ReporterPreferences getPreferences() const override;
-
void noMatchingTestCases(std::string const& spec) override;
void assertionStarting(AssertionInfo const&) override;
@@ -4891,6 +6161,8 @@ namespace Catch {
void noMatchingTestCases(std::string const& spec) override;
+ void reportInvalidArguments(std::string const&arg) override;
+
void assertionStarting(AssertionInfo const&) override;
bool assertionEnded(AssertionStats const& _assertionStats) override;
@@ -4898,13 +6170,17 @@ namespace Catch {
void sectionStarting(SectionInfo const& _sectionInfo) override;
void sectionEnded(SectionStats const& _sectionStats) override;
+#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)
+ void benchmarkPreparing(std::string const& name) override;
void benchmarkStarting(BenchmarkInfo const& info) override;
- void benchmarkEnded(BenchmarkStats const& stats) override;
+ void benchmarkEnded(BenchmarkStats<> const& stats) override;
+ void benchmarkFailed(std::string const& error) override;
+#endif // CATCH_CONFIG_ENABLE_BENCHMARKING
void testCaseEnded(TestCaseStats const& _testCaseStats) override;
void testGroupEnded(TestGroupStats const& _testGroupStats) override;
void testRunEnded(TestRunStats const& _testRunStats) override;
-
+ void testRunStarting(TestRunInfo const& _testRunInfo) override;
private:
void lazyPrint();
@@ -4926,6 +6202,7 @@ namespace Catch {
void printTotalsDivider(Totals const& totals);
void printSummaryDivider();
+ void printTestFilters();
private:
bool m_headerPrinted = false;
@@ -4945,6 +6222,14 @@ namespace Catch {
#include <vector>
namespace Catch {
+ enum class XmlFormatting {
+ None = 0x00,
+ Indent = 0x01,
+ Newline = 0x02,
+ };
+
+ XmlFormatting operator | (XmlFormatting lhs, XmlFormatting rhs);
+ XmlFormatting operator & (XmlFormatting lhs, XmlFormatting rhs);
class XmlEncode {
public:
@@ -4966,14 +6251,14 @@ namespace Catch {
class ScopedElement {
public:
- ScopedElement( XmlWriter* writer );
+ ScopedElement( XmlWriter* writer, XmlFormatting fmt );
ScopedElement( ScopedElement&& other ) noexcept;
ScopedElement& operator=( ScopedElement&& other ) noexcept;
~ScopedElement();
- ScopedElement& writeText( std::string const& text, bool indent = true );
+ ScopedElement& writeText( std::string const& text, XmlFormatting fmt = XmlFormatting::Newline | XmlFormatting::Indent );
template<typename T>
ScopedElement& writeAttribute( std::string const& name, T const& attribute ) {
@@ -4983,6 +6268,7 @@ namespace Catch {
private:
mutable XmlWriter* m_writer = nullptr;
+ XmlFormatting m_fmt;
};
XmlWriter( std::ostream& os = Catch::cout() );
@@ -4991,11 +6277,11 @@ namespace Catch {
XmlWriter( XmlWriter const& ) = delete;
XmlWriter& operator=( XmlWriter const& ) = delete;
- XmlWriter& startElement( std::string const& name );
+ XmlWriter& startElement( std::string const& name, XmlFormatting fmt = XmlFormatting::Newline | XmlFormatting::Indent);
- ScopedElement scopedElement( std::string const& name );
+ ScopedElement scopedElement( std::string const& name, XmlFormatting fmt = XmlFormatting::Newline | XmlFormatting::Indent);
- XmlWriter& endElement();
+ XmlWriter& endElement(XmlFormatting fmt = XmlFormatting::Newline | XmlFormatting::Indent);
XmlWriter& writeAttribute( std::string const& name, std::string const& attribute );
@@ -5008,9 +6294,9 @@ namespace Catch {
return writeAttribute( name, rss.str() );
}
- XmlWriter& writeText( std::string const& text, bool indent = true );
+ XmlWriter& writeText( std::string const& text, XmlFormatting fmt = XmlFormatting::Newline | XmlFormatting::Indent);
- XmlWriter& writeComment( std::string const& text );
+ XmlWriter& writeComment(std::string const& text, XmlFormatting fmt = XmlFormatting::Newline | XmlFormatting::Indent);
void writeStylesheetRef( std::string const& url );
@@ -5020,6 +6306,8 @@ namespace Catch {
private:
+ void applyFormatting(XmlFormatting fmt);
+
void writeDeclaration();
void newlineIfNecessary();
@@ -5063,9 +6351,10 @@ namespace Catch {
void writeTestCase(TestCaseNode const& testCaseNode);
- void writeSection(std::string const& className,
- std::string const& rootName,
- SectionNode const& sectionNode);
+ void writeSection( std::string const& className,
+ std::string const& rootName,
+ SectionNode const& sectionNode,
+ bool testOkToFail );
void writeAssertions(SectionNode const& sectionNode);
void writeAssertion(AssertionStats const& stats);
@@ -5120,6 +6409,13 @@ namespace Catch {
void testRunEnded(TestRunStats const& testRunStats) override;
+#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)
+ void benchmarkPreparing(std::string const& name) override;
+ void benchmarkStarting(BenchmarkInfo const&) override;
+ void benchmarkEnded(BenchmarkStats<> const&) override;
+ void benchmarkFailed(std::string const&) override;
+#endif // CATCH_CONFIG_ENABLE_BENCHMARKING
+
private:
Timer m_testCaseTimer;
XmlWriter m_xml;
@@ -5133,6 +6429,1032 @@ namespace Catch {
// end catch_external_interfaces.h
#endif
+#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)
+// start catch_benchmarking_all.hpp
+
+// A proxy header that includes all of the benchmarking headers to allow
+// concise include of the benchmarking features. You should prefer the
+// individual includes in standard use.
+
+// start catch_benchmark.hpp
+
+ // Benchmark
+
+// start catch_chronometer.hpp
+
+// User-facing chronometer
+
+
+// start catch_clock.hpp
+
+// Clocks
+
+
+#include <chrono>
+#include <ratio>
+
+namespace Catch {
+ namespace Benchmark {
+ template <typename Clock>
+ using ClockDuration = typename Clock::duration;
+ template <typename Clock>
+ using FloatDuration = std::chrono::duration<double, typename Clock::period>;
+
+ template <typename Clock>
+ using TimePoint = typename Clock::time_point;
+
+ using default_clock = std::chrono::steady_clock;
+
+ template <typename Clock>
+ struct now {
+ TimePoint<Clock> operator()() const {
+ return Clock::now();
+ }
+ };
+
+ using fp_seconds = std::chrono::duration<double, std::ratio<1>>;
+ } // namespace Benchmark
+} // namespace Catch
+
+// end catch_clock.hpp
+// start catch_optimizer.hpp
+
+ // Hinting the optimizer
+
+
+#if defined(_MSC_VER)
+# include <atomic> // atomic_thread_fence
+#endif
+
+namespace Catch {
+ namespace Benchmark {
+#if defined(__GNUC__) || defined(__clang__)
+ template <typename T>
+ inline void keep_memory(T* p) {
+ asm volatile("" : : "g"(p) : "memory");
+ }
+ inline void keep_memory() {
+ asm volatile("" : : : "memory");
+ }
+
+ namespace Detail {
+ inline void optimizer_barrier() { keep_memory(); }
+ } // namespace Detail
+#elif defined(_MSC_VER)
+
+#pragma optimize("", off)
+ template <typename T>
+ inline void keep_memory(T* p) {
+ // thanks @milleniumbug
+ *reinterpret_cast<char volatile*>(p) = *reinterpret_cast<char const volatile*>(p);
+ }
+ // TODO equivalent keep_memory()
+#pragma optimize("", on)
+
+ namespace Detail {
+ inline void optimizer_barrier() {
+ std::atomic_thread_fence(std::memory_order_seq_cst);
+ }
+ } // namespace Detail
+
+#endif
+
+ template <typename T>
+ inline void deoptimize_value(T&& x) {
+ keep_memory(&x);
+ }
+
+ template <typename Fn, typename... Args>
+ inline auto invoke_deoptimized(Fn&& fn, Args&&... args) -> typename std::enable_if<!std::is_same<void, decltype(fn(args...))>::value>::type {
+ deoptimize_value(std::forward<Fn>(fn) (std::forward<Args...>(args...)));
+ }
+
+ template <typename Fn, typename... Args>
+ inline auto invoke_deoptimized(Fn&& fn, Args&&... args) -> typename std::enable_if<std::is_same<void, decltype(fn(args...))>::value>::type {
+ std::forward<Fn>(fn) (std::forward<Args...>(args...));
+ }
+ } // namespace Benchmark
+} // namespace Catch
+
+// end catch_optimizer.hpp
+// start catch_complete_invoke.hpp
+
+// Invoke with a special case for void
+
+
+#include <type_traits>
+#include <utility>
+
+namespace Catch {
+ namespace Benchmark {
+ namespace Detail {
+ template <typename T>
+ struct CompleteType { using type = T; };
+ template <>
+ struct CompleteType<void> { struct type {}; };
+
+ template <typename T>
+ using CompleteType_t = typename CompleteType<T>::type;
+
+ template <typename Result>
+ struct CompleteInvoker {
+ template <typename Fun, typename... Args>
+ static Result invoke(Fun&& fun, Args&&... args) {
+ return std::forward<Fun>(fun)(std::forward<Args>(args)...);
+ }
+ };
+ template <>
+ struct CompleteInvoker<void> {
+ template <typename Fun, typename... Args>
+ static CompleteType_t<void> invoke(Fun&& fun, Args&&... args) {
+ std::forward<Fun>(fun)(std::forward<Args>(args)...);
+ return {};
+ }
+ };
+
+ // invoke and not return void :(
+ template <typename Fun, typename... Args>
+ CompleteType_t<FunctionReturnType<Fun, Args...>> complete_invoke(Fun&& fun, Args&&... args) {
+ return CompleteInvoker<FunctionReturnType<Fun, Args...>>::invoke(std::forward<Fun>(fun), std::forward<Args>(args)...);
+ }
+
+ const std::string benchmarkErrorMsg = "a benchmark failed to run successfully";
+ } // namespace Detail
+
+ template <typename Fun>
+ Detail::CompleteType_t<FunctionReturnType<Fun>> user_code(Fun&& fun) {
+ CATCH_TRY{
+ return Detail::complete_invoke(std::forward<Fun>(fun));
+ } CATCH_CATCH_ALL{
+ getResultCapture().benchmarkFailed(translateActiveException());
+ CATCH_RUNTIME_ERROR(Detail::benchmarkErrorMsg);
+ }
+ }
+ } // namespace Benchmark
+} // namespace Catch
+
+// end catch_complete_invoke.hpp
+namespace Catch {
+ namespace Benchmark {
+ namespace Detail {
+ struct ChronometerConcept {
+ virtual void start() = 0;
+ virtual void finish() = 0;
+ virtual ~ChronometerConcept() = default;
+ };
+ template <typename Clock>
+ struct ChronometerModel final : public ChronometerConcept {
+ void start() override { started = Clock::now(); }
+ void finish() override { finished = Clock::now(); }
+
+ ClockDuration<Clock> elapsed() const { return finished - started; }
+
+ TimePoint<Clock> started;
+ TimePoint<Clock> finished;
+ };
+ } // namespace Detail
+
+ struct Chronometer {
+ public:
+ template <typename Fun>
+ void measure(Fun&& fun) { measure(std::forward<Fun>(fun), is_callable<Fun(int)>()); }
+
+ int runs() const { return k; }
+
+ Chronometer(Detail::ChronometerConcept& meter, int k)
+ : impl(&meter)
+ , k(k) {}
+
+ private:
+ template <typename Fun>
+ void measure(Fun&& fun, std::false_type) {
+ measure([&fun](int) { return fun(); }, std::true_type());
+ }
+
+ template <typename Fun>
+ void measure(Fun&& fun, std::true_type) {
+ Detail::optimizer_barrier();
+ impl->start();
+ for (int i = 0; i < k; ++i) invoke_deoptimized(fun, i);
+ impl->finish();
+ Detail::optimizer_barrier();
+ }
+
+ Detail::ChronometerConcept* impl;
+ int k;
+ };
+ } // namespace Benchmark
+} // namespace Catch
+
+// end catch_chronometer.hpp
+// start catch_environment.hpp
+
+// Environment information
+
+
+namespace Catch {
+ namespace Benchmark {
+ template <typename Duration>
+ struct EnvironmentEstimate {
+ Duration mean;
+ OutlierClassification outliers;
+
+ template <typename Duration2>
+ operator EnvironmentEstimate<Duration2>() const {
+ return { mean, outliers };
+ }
+ };
+ template <typename Clock>
+ struct Environment {
+ using clock_type = Clock;
+ EnvironmentEstimate<FloatDuration<Clock>> clock_resolution;
+ EnvironmentEstimate<FloatDuration<Clock>> clock_cost;
+ };
+ } // namespace Benchmark
+} // namespace Catch
+
+// end catch_environment.hpp
+// start catch_execution_plan.hpp
+
+ // Execution plan
+
+
+// start catch_benchmark_function.hpp
+
+ // Dumb std::function implementation for consistent call overhead
+
+
+#include <cassert>
+#include <type_traits>
+#include <utility>
+#include <memory>
+
+namespace Catch {
+ namespace Benchmark {
+ namespace Detail {
+ template <typename T>
+ using Decay = typename std::decay<T>::type;
+ template <typename T, typename U>
+ struct is_related
+ : std::is_same<Decay<T>, Decay<U>> {};
+
+ /// We need to reinvent std::function because every piece of code that might add overhead
+ /// in a measurement context needs to have consistent performance characteristics so that we
+ /// can account for it in the measurement.
+ /// Implementations of std::function with optimizations that aren't always applicable, like
+ /// small buffer optimizations, are not uncommon.
+ /// This is effectively an implementation of std::function without any such optimizations;
+ /// it may be slow, but it is consistently slow.
+ struct BenchmarkFunction {
+ private:
+ struct callable {
+ virtual void call(Chronometer meter) const = 0;
+ virtual callable* clone() const = 0;
+ virtual ~callable() = default;
+ };
+ template <typename Fun>
+ struct model : public callable {
+ model(Fun&& fun) : fun(std::move(fun)) {}
+ model(Fun const& fun) : fun(fun) {}
+
+ model<Fun>* clone() const override { return new model<Fun>(*this); }
+
+ void call(Chronometer meter) const override {
+ call(meter, is_callable<Fun(Chronometer)>());
+ }
+ void call(Chronometer meter, std::true_type) const {
+ fun(meter);
+ }
+ void call(Chronometer meter, std::false_type) const {
+ meter.measure(fun);
+ }
+
+ Fun fun;
+ };
+
+ struct do_nothing { void operator()() const {} };
+
+ template <typename T>
+ BenchmarkFunction(model<T>* c) : f(c) {}
+
+ public:
+ BenchmarkFunction()
+ : f(new model<do_nothing>{ {} }) {}
+
+ template <typename Fun,
+ typename std::enable_if<!is_related<Fun, BenchmarkFunction>::value, int>::type = 0>
+ BenchmarkFunction(Fun&& fun)
+ : f(new model<typename std::decay<Fun>::type>(std::forward<Fun>(fun))) {}
+
+ BenchmarkFunction(BenchmarkFunction&& that)
+ : f(std::move(that.f)) {}
+
+ BenchmarkFunction(BenchmarkFunction const& that)
+ : f(that.f->clone()) {}
+
+ BenchmarkFunction& operator=(BenchmarkFunction&& that) {
+ f = std::move(that.f);
+ return *this;
+ }
+
+ BenchmarkFunction& operator=(BenchmarkFunction const& that) {
+ f.reset(that.f->clone());
+ return *this;
+ }
+
+ void operator()(Chronometer meter) const { f->call(meter); }
+
+ private:
+ std::unique_ptr<callable> f;
+ };
+ } // namespace Detail
+ } // namespace Benchmark
+} // namespace Catch
+
+// end catch_benchmark_function.hpp
+// start catch_repeat.hpp
+
+// repeat algorithm
+
+
+#include <type_traits>
+#include <utility>
+
+namespace Catch {
+ namespace Benchmark {
+ namespace Detail {
+ template <typename Fun>
+ struct repeater {
+ void operator()(int k) const {
+ for (int i = 0; i < k; ++i) {
+ fun();
+ }
+ }
+ Fun fun;
+ };
+ template <typename Fun>
+ repeater<typename std::decay<Fun>::type> repeat(Fun&& fun) {
+ return { std::forward<Fun>(fun) };
+ }
+ } // namespace Detail
+ } // namespace Benchmark
+} // namespace Catch
+
+// end catch_repeat.hpp
+// start catch_run_for_at_least.hpp
+
+// Run a function for a minimum amount of time
+
+
+// start catch_measure.hpp
+
+// Measure
+
+
+// start catch_timing.hpp
+
+// Timing
+
+
+#include <tuple>
+#include <type_traits>
+
+namespace Catch {
+ namespace Benchmark {
+ template <typename Duration, typename Result>
+ struct Timing {
+ Duration elapsed;
+ Result result;
+ int iterations;
+ };
+ template <typename Clock, typename Func, typename... Args>
+ using TimingOf = Timing<ClockDuration<Clock>, Detail::CompleteType_t<FunctionReturnType<Func, Args...>>>;
+ } // namespace Benchmark
+} // namespace Catch
+
+// end catch_timing.hpp
+#include <utility>
+
+namespace Catch {
+ namespace Benchmark {
+ namespace Detail {
+ template <typename Clock, typename Fun, typename... Args>
+ TimingOf<Clock, Fun, Args...> measure(Fun&& fun, Args&&... args) {
+ auto start = Clock::now();
+ auto&& r = Detail::complete_invoke(fun, std::forward<Args>(args)...);
+ auto end = Clock::now();
+ auto delta = end - start;
+ return { delta, std::forward<decltype(r)>(r), 1 };
+ }
+ } // namespace Detail
+ } // namespace Benchmark
+} // namespace Catch
+
+// end catch_measure.hpp
+#include <utility>
+#include <type_traits>
+
+namespace Catch {
+ namespace Benchmark {
+ namespace Detail {
+ template <typename Clock, typename Fun>
+ TimingOf<Clock, Fun, int> measure_one(Fun&& fun, int iters, std::false_type) {
+ return Detail::measure<Clock>(fun, iters);
+ }
+ template <typename Clock, typename Fun>
+ TimingOf<Clock, Fun, Chronometer> measure_one(Fun&& fun, int iters, std::true_type) {
+ Detail::ChronometerModel<Clock> meter;
+ auto&& result = Detail::complete_invoke(fun, Chronometer(meter, iters));
+
+ return { meter.elapsed(), std::move(result), iters };
+ }
+
+ template <typename Clock, typename Fun>
+ using run_for_at_least_argument_t = typename std::conditional<is_callable<Fun(Chronometer)>::value, Chronometer, int>::type;
+
+ struct optimized_away_error : std::exception {
+ const char* what() const noexcept override {
+ return "could not measure benchmark, maybe it was optimized away";
+ }
+ };
+
+ template <typename Clock, typename Fun>
+ TimingOf<Clock, Fun, run_for_at_least_argument_t<Clock, Fun>> run_for_at_least(ClockDuration<Clock> how_long, int seed, Fun&& fun) {
+ auto iters = seed;
+ while (iters < (1 << 30)) {
+ auto&& Timing = measure_one<Clock>(fun, iters, is_callable<Fun(Chronometer)>());
+
+ if (Timing.elapsed >= how_long) {
+ return { Timing.elapsed, std::move(Timing.result), iters };
+ }
+ iters *= 2;
+ }
+ Catch::throw_exception(optimized_away_error{});
+ }
+ } // namespace Detail
+ } // namespace Benchmark
+} // namespace Catch
+
+// end catch_run_for_at_least.hpp
+#include <algorithm>
+#include <iterator>
+
+namespace Catch {
+ namespace Benchmark {
+ template <typename Duration>
+ struct ExecutionPlan {
+ int iterations_per_sample;
+ Duration estimated_duration;
+ Detail::BenchmarkFunction benchmark;
+ Duration warmup_time;
+ int warmup_iterations;
+
+ template <typename Duration2>
+ operator ExecutionPlan<Duration2>() const {
+ return { iterations_per_sample, estimated_duration, benchmark, warmup_time, warmup_iterations };
+ }
+
+ template <typename Clock>
+ std::vector<FloatDuration<Clock>> run(const IConfig &cfg, Environment<FloatDuration<Clock>> env) const {
+ // warmup a bit
+ Detail::run_for_at_least<Clock>(std::chrono::duration_cast<ClockDuration<Clock>>(warmup_time), warmup_iterations, Detail::repeat(now<Clock>{}));
+
+ std::vector<FloatDuration<Clock>> times;
+ times.reserve(cfg.benchmarkSamples());
+ std::generate_n(std::back_inserter(times), cfg.benchmarkSamples(), [this, env] {
+ Detail::ChronometerModel<Clock> model;
+ this->benchmark(Chronometer(model, iterations_per_sample));
+ auto sample_time = model.elapsed() - env.clock_cost.mean;
+ if (sample_time < FloatDuration<Clock>::zero()) sample_time = FloatDuration<Clock>::zero();
+ return sample_time / iterations_per_sample;
+ });
+ return times;
+ }
+ };
+ } // namespace Benchmark
+} // namespace Catch
+
+// end catch_execution_plan.hpp
+// start catch_estimate_clock.hpp
+
+ // Environment measurement
+
+
+// start catch_stats.hpp
+
+// Statistical analysis tools
+
+
+#include <algorithm>
+#include <functional>
+#include <vector>
+#include <iterator>
+#include <numeric>
+#include <tuple>
+#include <cmath>
+#include <utility>
+#include <cstddef>
+#include <random>
+
+namespace Catch {
+ namespace Benchmark {
+ namespace Detail {
+ using sample = std::vector<double>;
+
+ double weighted_average_quantile(int k, int q, std::vector<double>::iterator first, std::vector<double>::iterator last);
+
+ template <typename Iterator>
+ OutlierClassification classify_outliers(Iterator first, Iterator last) {
+ std::vector<double> copy(first, last);
+
+ auto q1 = weighted_average_quantile(1, 4, copy.begin(), copy.end());
+ auto q3 = weighted_average_quantile(3, 4, copy.begin(), copy.end());
+ auto iqr = q3 - q1;
+ auto los = q1 - (iqr * 3.);
+ auto lom = q1 - (iqr * 1.5);
+ auto him = q3 + (iqr * 1.5);
+ auto his = q3 + (iqr * 3.);
+
+ OutlierClassification o;
+ for (; first != last; ++first) {
+ auto&& t = *first;
+ if (t < los) ++o.low_severe;
+ else if (t < lom) ++o.low_mild;
+ else if (t > his) ++o.high_severe;
+ else if (t > him) ++o.high_mild;
+ ++o.samples_seen;
+ }
+ return o;
+ }
+
+ template <typename Iterator>
+ double mean(Iterator first, Iterator last) {
+ auto count = last - first;
+ double sum = std::accumulate(first, last, 0.);
+ return sum / count;
+ }
+
+ template <typename URng, typename Iterator, typename Estimator>
+ sample resample(URng& rng, int resamples, Iterator first, Iterator last, Estimator& estimator) {
+ auto n = last - first;
+ std::uniform_int_distribution<decltype(n)> dist(0, n - 1);
+
+ sample out;
+ out.reserve(resamples);
+ std::generate_n(std::back_inserter(out), resamples, [n, first, &estimator, &dist, &rng] {
+ std::vector<double> resampled;
+ resampled.reserve(n);
+ std::generate_n(std::back_inserter(resampled), n, [first, &dist, &rng] { return first[dist(rng)]; });
+ return estimator(resampled.begin(), resampled.end());
+ });
+ std::sort(out.begin(), out.end());
+ return out;
+ }
+
+ template <typename Estimator, typename Iterator>
+ sample jackknife(Estimator&& estimator, Iterator first, Iterator last) {
+ auto n = last - first;
+ auto second = std::next(first);
+ sample results;
+ results.reserve(n);
+
+ for (auto it = first; it != last; ++it) {
+ std::iter_swap(it, first);
+ results.push_back(estimator(second, last));
+ }
+
+ return results;
+ }
+
+ inline double normal_cdf(double x) {
+ return std::erfc(-x / std::sqrt(2.0)) / 2.0;
+ }
+
+ double erfc_inv(double x);
+
+ double normal_quantile(double p);
+
+ template <typename Iterator, typename Estimator>
+ Estimate<double> bootstrap(double confidence_level, Iterator first, Iterator last, sample const& resample, Estimator&& estimator) {
+ auto n_samples = last - first;
+
+ double point = estimator(first, last);
+ // Degenerate case with a single sample
+ if (n_samples == 1) return { point, point, point, confidence_level };
+
+ sample jack = jackknife(estimator, first, last);
+ double jack_mean = mean(jack.begin(), jack.end());
+ double sum_squares, sum_cubes;
+ std::tie(sum_squares, sum_cubes) = std::accumulate(jack.begin(), jack.end(), std::make_pair(0., 0.), [jack_mean](std::pair<double, double> sqcb, double x) -> std::pair<double, double> {
+ auto d = jack_mean - x;
+ auto d2 = d * d;
+ auto d3 = d2 * d;
+ return { sqcb.first + d2, sqcb.second + d3 };
+ });
+
+ double accel = sum_cubes / (6 * std::pow(sum_squares, 1.5));
+ int n = static_cast<int>(resample.size());
+ double prob_n = std::count_if(resample.begin(), resample.end(), [point](double x) { return x < point; }) / (double)n;
+ // degenerate case with uniform samples
+ if (prob_n == 0) return { point, point, point, confidence_level };
+
+ double bias = normal_quantile(prob_n);
+ double z1 = normal_quantile((1. - confidence_level) / 2.);
+
+ auto cumn = [n](double x) -> int {
+ return std::lround(normal_cdf(x) * n); };
+ auto a = [bias, accel](double b) { return bias + b / (1. - accel * b); };
+ double b1 = bias + z1;
+ double b2 = bias - z1;
+ double a1 = a(b1);
+ double a2 = a(b2);
+ auto lo = (std::max)(cumn(a1), 0);
+ auto hi = (std::min)(cumn(a2), n - 1);
+
+ return { point, resample[lo], resample[hi], confidence_level };
+ }
+
+ double outlier_variance(Estimate<double> mean, Estimate<double> stddev, int n);
+
+ struct bootstrap_analysis {
+ Estimate<double> mean;
+ Estimate<double> standard_deviation;
+ double outlier_variance;
+ };
+
+ bootstrap_analysis analyse_samples(double confidence_level, int n_resamples, std::vector<double>::iterator first, std::vector<double>::iterator last);
+ } // namespace Detail
+ } // namespace Benchmark
+} // namespace Catch
+
+// end catch_stats.hpp
+#include <algorithm>
+#include <iterator>
+#include <tuple>
+#include <vector>
+#include <cmath>
+
+namespace Catch {
+ namespace Benchmark {
+ namespace Detail {
+ template <typename Clock>
+ std::vector<double> resolution(int k) {
+ std::vector<TimePoint<Clock>> times;
+ times.reserve(k + 1);
+ std::generate_n(std::back_inserter(times), k + 1, now<Clock>{});
+
+ std::vector<double> deltas;
+ deltas.reserve(k);
+ std::transform(std::next(times.begin()), times.end(), times.begin(),
+ std::back_inserter(deltas),
+ [](TimePoint<Clock> a, TimePoint<Clock> b) { return static_cast<double>((a - b).count()); });
+
+ return deltas;
+ }
+
+ const auto warmup_iterations = 10000;
+ const auto warmup_time = std::chrono::milliseconds(100);
+ const auto minimum_ticks = 1000;
+ const auto warmup_seed = 10000;
+ const auto clock_resolution_estimation_time = std::chrono::milliseconds(500);
+ const auto clock_cost_estimation_time_limit = std::chrono::seconds(1);
+ const auto clock_cost_estimation_tick_limit = 100000;
+ const auto clock_cost_estimation_time = std::chrono::milliseconds(10);
+ const auto clock_cost_estimation_iterations = 10000;
+
+ template <typename Clock>
+ int warmup() {
+ return run_for_at_least<Clock>(std::chrono::duration_cast<ClockDuration<Clock>>(warmup_time), warmup_seed, &resolution<Clock>)
+ .iterations;
+ }
+ template <typename Clock>
+ EnvironmentEstimate<FloatDuration<Clock>> estimate_clock_resolution(int iterations) {
+ auto r = run_for_at_least<Clock>(std::chrono::duration_cast<ClockDuration<Clock>>(clock_resolution_estimation_time), iterations, &resolution<Clock>)
+ .result;
+ return {
+ FloatDuration<Clock>(mean(r.begin(), r.end())),
+ classify_outliers(r.begin(), r.end()),
+ };
+ }
+ template <typename Clock>
+ EnvironmentEstimate<FloatDuration<Clock>> estimate_clock_cost(FloatDuration<Clock> resolution) {
+ auto time_limit = (std::min)(
+ resolution * clock_cost_estimation_tick_limit,
+ FloatDuration<Clock>(clock_cost_estimation_time_limit));
+ auto time_clock = [](int k) {
+ return Detail::measure<Clock>([k] {
+ for (int i = 0; i < k; ++i) {
+ volatile auto ignored = Clock::now();
+ (void)ignored;
+ }
+ }).elapsed;
+ };
+ time_clock(1);
+ int iters = clock_cost_estimation_iterations;
+ auto&& r = run_for_at_least<Clock>(std::chrono::duration_cast<ClockDuration<Clock>>(clock_cost_estimation_time), iters, time_clock);
+ std::vector<double> times;
+ int nsamples = static_cast<int>(std::ceil(time_limit / r.elapsed));
+ times.reserve(nsamples);
+ std::generate_n(std::back_inserter(times), nsamples, [time_clock, &r] {
+ return static_cast<double>((time_clock(r.iterations) / r.iterations).count());
+ });
+ return {
+ FloatDuration<Clock>(mean(times.begin(), times.end())),
+ classify_outliers(times.begin(), times.end()),
+ };
+ }
+
+ template <typename Clock>
+ Environment<FloatDuration<Clock>> measure_environment() {
+ static Environment<FloatDuration<Clock>>* env = nullptr;
+ if (env) {
+ return *env;
+ }
+
+ auto iters = Detail::warmup<Clock>();
+ auto resolution = Detail::estimate_clock_resolution<Clock>(iters);
+ auto cost = Detail::estimate_clock_cost<Clock>(resolution.mean);
+
+ env = new Environment<FloatDuration<Clock>>{ resolution, cost };
+ return *env;
+ }
+ } // namespace Detail
+ } // namespace Benchmark
+} // namespace Catch
+
+// end catch_estimate_clock.hpp
+// start catch_analyse.hpp
+
+ // Run and analyse one benchmark
+
+
+// start catch_sample_analysis.hpp
+
+// Benchmark results
+
+
+#include <algorithm>
+#include <vector>
+#include <string>
+#include <iterator>
+
+namespace Catch {
+ namespace Benchmark {
+ template <typename Duration>
+ struct SampleAnalysis {
+ std::vector<Duration> samples;
+ Estimate<Duration> mean;
+ Estimate<Duration> standard_deviation;
+ OutlierClassification outliers;
+ double outlier_variance;
+
+ template <typename Duration2>
+ operator SampleAnalysis<Duration2>() const {
+ std::vector<Duration2> samples2;
+ samples2.reserve(samples.size());
+ std::transform(samples.begin(), samples.end(), std::back_inserter(samples2), [](Duration d) { return Duration2(d); });
+ return {
+ std::move(samples2),
+ mean,
+ standard_deviation,
+ outliers,
+ outlier_variance,
+ };
+ }
+ };
+ } // namespace Benchmark
+} // namespace Catch
+
+// end catch_sample_analysis.hpp
+#include <algorithm>
+#include <iterator>
+#include <vector>
+
+namespace Catch {
+ namespace Benchmark {
+ namespace Detail {
+ template <typename Duration, typename Iterator>
+ SampleAnalysis<Duration> analyse(const IConfig &cfg, Environment<Duration>, Iterator first, Iterator last) {
+ if (!cfg.benchmarkNoAnalysis()) {
+ std::vector<double> samples;
+ samples.reserve(last - first);
+ std::transform(first, last, std::back_inserter(samples), [](Duration d) { return d.count(); });
+
+ auto analysis = Catch::Benchmark::Detail::analyse_samples(cfg.benchmarkConfidenceInterval(), cfg.benchmarkResamples(), samples.begin(), samples.end());
+ auto outliers = Catch::Benchmark::Detail::classify_outliers(samples.begin(), samples.end());
+
+ auto wrap_estimate = [](Estimate<double> e) {
+ return Estimate<Duration> {
+ Duration(e.point),
+ Duration(e.lower_bound),
+ Duration(e.upper_bound),
+ e.confidence_interval,
+ };
+ };
+ std::vector<Duration> samples2;
+ samples2.reserve(samples.size());
+ std::transform(samples.begin(), samples.end(), std::back_inserter(samples2), [](double d) { return Duration(d); });
+ return {
+ std::move(samples2),
+ wrap_estimate(analysis.mean),
+ wrap_estimate(analysis.standard_deviation),
+ outliers,
+ analysis.outlier_variance,
+ };
+ } else {
+ std::vector<Duration> samples;
+ samples.reserve(last - first);
+
+ Duration mean = Duration(0);
+ int i = 0;
+ for (auto it = first; it < last; ++it, ++i) {
+ samples.push_back(Duration(*it));
+ mean += Duration(*it);
+ }
+ mean /= i;
+
+ return {
+ std::move(samples),
+ Estimate<Duration>{mean, mean, mean, 0.0},
+ Estimate<Duration>{Duration(0), Duration(0), Duration(0), 0.0},
+ OutlierClassification{},
+ 0.0
+ };
+ }
+ }
+ } // namespace Detail
+ } // namespace Benchmark
+} // namespace Catch
+
+// end catch_analyse.hpp
+#include <algorithm>
+#include <functional>
+#include <string>
+#include <vector>
+#include <cmath>
+
+namespace Catch {
+ namespace Benchmark {
+ struct Benchmark {
+ Benchmark(std::string &&name)
+ : name(std::move(name)) {}
+
+ template <class FUN>
+ Benchmark(std::string &&name, FUN &&func)
+ : fun(std::move(func)), name(std::move(name)) {}
+
+ template <typename Clock>
+ ExecutionPlan<FloatDuration<Clock>> prepare(const IConfig &cfg, Environment<FloatDuration<Clock>> env) const {
+ auto min_time = env.clock_resolution.mean * Detail::minimum_ticks;
+ auto run_time = std::max(min_time, std::chrono::duration_cast<decltype(min_time)>(cfg.benchmarkWarmupTime()));
+ auto&& test = Detail::run_for_at_least<Clock>(std::chrono::duration_cast<ClockDuration<Clock>>(run_time), 1, fun);
+ int new_iters = static_cast<int>(std::ceil(min_time * test.iterations / test.elapsed));
+ return { new_iters, test.elapsed / test.iterations * new_iters * cfg.benchmarkSamples(), fun, std::chrono::duration_cast<FloatDuration<Clock>>(cfg.benchmarkWarmupTime()), Detail::warmup_iterations };
+ }
+
+ template <typename Clock = default_clock>
+ void run() {
+ IConfigPtr cfg = getCurrentContext().getConfig();
+
+ auto env = Detail::measure_environment<Clock>();
+
+ getResultCapture().benchmarkPreparing(name);
+ CATCH_TRY{
+ auto plan = user_code([&] {
+ return prepare<Clock>(*cfg, env);
+ });
+
+ BenchmarkInfo info {
+ name,
+ plan.estimated_duration.count(),
+ plan.iterations_per_sample,
+ cfg->benchmarkSamples(),
+ cfg->benchmarkResamples(),
+ env.clock_resolution.mean.count(),
+ env.clock_cost.mean.count()
+ };
+
+ getResultCapture().benchmarkStarting(info);
+
+ auto samples = user_code([&] {
+ return plan.template run<Clock>(*cfg, env);
+ });
+
+ auto analysis = Detail::analyse(*cfg, env, samples.begin(), samples.end());
+ BenchmarkStats<FloatDuration<Clock>> stats{ info, analysis.samples, analysis.mean, analysis.standard_deviation, analysis.outliers, analysis.outlier_variance };
+ getResultCapture().benchmarkEnded(stats);
+
+ } CATCH_CATCH_ALL{
+ if (translateActiveException() != Detail::benchmarkErrorMsg) // benchmark errors have been reported, otherwise rethrow.
+ std::rethrow_exception(std::current_exception());
+ }
+ }
+
+ // sets lambda to be used in fun *and* executes benchmark!
+ template <typename Fun,
+ typename std::enable_if<!Detail::is_related<Fun, Benchmark>::value, int>::type = 0>
+ Benchmark & operator=(Fun func) {
+ fun = Detail::BenchmarkFunction(func);
+ run();
+ return *this;
+ }
+
+ explicit operator bool() {
+ return true;
+ }
+
+ private:
+ Detail::BenchmarkFunction fun;
+ std::string name;
+ };
+ }
+} // namespace Catch
+
+#define INTERNAL_CATCH_GET_1_ARG(arg1, arg2, ...) arg1
+#define INTERNAL_CATCH_GET_2_ARG(arg1, arg2, ...) arg2
+
+#define INTERNAL_CATCH_BENCHMARK(BenchmarkName, name, benchmarkIndex)\
+ if( Catch::Benchmark::Benchmark BenchmarkName{name} ) \
+ BenchmarkName = [&](int benchmarkIndex)
+
+#define INTERNAL_CATCH_BENCHMARK_ADVANCED(BenchmarkName, name)\
+ if( Catch::Benchmark::Benchmark BenchmarkName{name} ) \
+ BenchmarkName = [&]
+
+// end catch_benchmark.hpp
+// start catch_constructor.hpp
+
+// Constructor and destructor helpers
+
+
+#include <type_traits>
+
+namespace Catch {
+ namespace Benchmark {
+ namespace Detail {
+ template <typename T, bool Destruct>
+ struct ObjectStorage
+ {
+ using TStorage = typename std::aligned_storage<sizeof(T), std::alignment_of<T>::value>::type;
+
+ ObjectStorage() : data() {}
+
+ ObjectStorage(const ObjectStorage& other)
+ {
+ new(&data) T(other.stored_object());
+ }
+
+ ObjectStorage(ObjectStorage&& other)
+ {
+ new(&data) T(std::move(other.stored_object()));
+ }
+
+ ~ObjectStorage() { destruct_on_exit<T>(); }
+
+ template <typename... Args>
+ void construct(Args&&... args)
+ {
+ new (&data) T(std::forward<Args>(args)...);
+ }
+
+ template <bool AllowManualDestruction = !Destruct>
+ typename std::enable_if<AllowManualDestruction>::type destruct()
+ {
+ stored_object().~T();
+ }
+
+ private:
+ // If this is a constructor benchmark, destruct the underlying object
+ template <typename U>
+ void destruct_on_exit(typename std::enable_if<Destruct, U>::type* = 0) { destruct<true>(); }
+ // Otherwise, don't
+ template <typename U>
+ void destruct_on_exit(typename std::enable_if<!Destruct, U>::type* = 0) { }
+
+ T& stored_object() {
+ return *static_cast<T*>(static_cast<void*>(&data));
+ }
+
+ T const& stored_object() const {
+ return *static_cast<T*>(static_cast<void*>(&data));
+ }
+
+ TStorage data;
+ };
+ }
+
+ template <typename T>
+ using storage_for = Detail::ObjectStorage<T, true>;
+
+ template <typename T>
+ using destructable_object = Detail::ObjectStorage<T, false>;
+ }
+}
+
+// end catch_constructor.hpp
+// end catch_benchmarking_all.hpp
+#endif
+
#endif // ! CATCH_CONFIG_IMPL_ONLY
#ifdef CATCH_IMPL
@@ -5158,23 +7480,37 @@ namespace TestCaseTracking {
SourceLineInfo location;
NameAndLocation( std::string const& _name, SourceLineInfo const& _location );
+ friend bool operator==(NameAndLocation const& lhs, NameAndLocation const& rhs) {
+ return lhs.name == rhs.name
+ && lhs.location == rhs.location;
+ }
};
- struct ITracker;
+ class ITracker;
using ITrackerPtr = std::shared_ptr<ITracker>;
- struct ITracker {
- virtual ~ITracker();
+ class ITracker {
+ NameAndLocation m_nameAndLocation;
+
+ public:
+ ITracker(NameAndLocation const& nameAndLoc) :
+ m_nameAndLocation(nameAndLoc)
+ {}
// static queries
- virtual NameAndLocation const& nameAndLocation() const = 0;
+ NameAndLocation const& nameAndLocation() const {
+ return m_nameAndLocation;
+ }
+
+ virtual ~ITracker();
// dynamic queries
virtual bool isComplete() const = 0; // Successfully completed or failed
virtual bool isSuccessfullyCompleted() const = 0;
virtual bool isOpen() const = 0; // Started but not complete
virtual bool hasChildren() const = 0;
+ virtual bool hasStarted() const = 0;
virtual ITracker& parent() = 0;
@@ -5189,7 +7525,7 @@ namespace TestCaseTracking {
// Debug/ checking
virtual bool isSectionTracker() const = 0;
- virtual bool isIndexTracker() const = 0;
+ virtual bool isGeneratorTracker() const = 0;
};
class TrackerContext {
@@ -5206,8 +7542,6 @@ namespace TestCaseTracking {
public:
- static TrackerContext& instance();
-
ITracker& startRun();
void endRun();
@@ -5231,7 +7565,6 @@ namespace TestCaseTracking {
};
using Children = std::vector<ITrackerPtr>;
- NameAndLocation m_nameAndLocation;
TrackerContext& m_ctx;
ITracker* m_parent;
Children m_children;
@@ -5240,11 +7573,13 @@ namespace TestCaseTracking {
public:
TrackerBase( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent );
- NameAndLocation const& nameAndLocation() const override;
bool isComplete() const override;
bool isSuccessfullyCompleted() const override;
bool isOpen() const override;
bool hasChildren() const override;
+ bool hasStarted() const override {
+ return m_runState != NotStarted;
+ }
void addChild( ITrackerPtr const& child ) override;
@@ -5254,7 +7589,7 @@ namespace TestCaseTracking {
void openChild() override;
bool isSectionTracker() const override;
- bool isIndexTracker() const override;
+ bool isGeneratorTracker() const override;
void open();
@@ -5269,33 +7604,24 @@ namespace TestCaseTracking {
class SectionTracker : public TrackerBase {
std::vector<std::string> m_filters;
+ std::string m_trimmed_name;
public:
SectionTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent );
bool isSectionTracker() const override;
+ bool isComplete() const override;
+
static SectionTracker& acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation );
void tryOpen();
void addInitialFilters( std::vector<std::string> const& filters );
void addNextFilters( std::vector<std::string> const& filters );
- };
-
- class IndexTracker : public TrackerBase {
- int m_size;
- int m_index = -1;
- public:
- IndexTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent, int size );
-
- bool isIndexTracker() const override;
- void close() override;
-
- static IndexTracker& acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation, int size );
-
- int index() const;
-
- void moveNext();
+ //! Returns filters active in this tracker
+ std::vector<std::string> const& getFilters() const;
+ //! Returns whitespace-trimmed name of the tracked section
+ std::string const& trimmedName() const;
};
} // namespace TestCaseTracking
@@ -5303,7 +7629,6 @@ namespace TestCaseTracking {
using TestCaseTracking::ITracker;
using TestCaseTracking::TrackerContext;
using TestCaseTracking::SectionTracker;
-using TestCaseTracking::IndexTracker;
} // namespace Catch
@@ -5321,6 +7646,217 @@ namespace Catch {
}
// end catch_leak_detector.h
// Cpp files will be included in the single-header file here
+// start catch_stats.cpp
+
+// Statistical analysis tools
+
+#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)
+
+#include <cassert>
+#include <random>
+
+#if defined(CATCH_CONFIG_USE_ASYNC)
+#include <future>
+#endif
+
+namespace {
+ double erf_inv(double x) {
+ // Code accompanying the article "Approximating the erfinv function" in GPU Computing Gems, Volume 2
+ double w, p;
+
+ w = -log((1.0 - x) * (1.0 + x));
+
+ if (w < 6.250000) {
+ w = w - 3.125000;
+ p = -3.6444120640178196996e-21;
+ p = -1.685059138182016589e-19 + p * w;
+ p = 1.2858480715256400167e-18 + p * w;
+ p = 1.115787767802518096e-17 + p * w;
+ p = -1.333171662854620906e-16 + p * w;
+ p = 2.0972767875968561637e-17 + p * w;
+ p = 6.6376381343583238325e-15 + p * w;
+ p = -4.0545662729752068639e-14 + p * w;
+ p = -8.1519341976054721522e-14 + p * w;
+ p = 2.6335093153082322977e-12 + p * w;
+ p = -1.2975133253453532498e-11 + p * w;
+ p = -5.4154120542946279317e-11 + p * w;
+ p = 1.051212273321532285e-09 + p * w;
+ p = -4.1126339803469836976e-09 + p * w;
+ p = -2.9070369957882005086e-08 + p * w;
+ p = 4.2347877827932403518e-07 + p * w;
+ p = -1.3654692000834678645e-06 + p * w;
+ p = -1.3882523362786468719e-05 + p * w;
+ p = 0.0001867342080340571352 + p * w;
+ p = -0.00074070253416626697512 + p * w;
+ p = -0.0060336708714301490533 + p * w;
+ p = 0.24015818242558961693 + p * w;
+ p = 1.6536545626831027356 + p * w;
+ } else if (w < 16.000000) {
+ w = sqrt(w) - 3.250000;
+ p = 2.2137376921775787049e-09;
+ p = 9.0756561938885390979e-08 + p * w;
+ p = -2.7517406297064545428e-07 + p * w;
+ p = 1.8239629214389227755e-08 + p * w;
+ p = 1.5027403968909827627e-06 + p * w;
+ p = -4.013867526981545969e-06 + p * w;
+ p = 2.9234449089955446044e-06 + p * w;
+ p = 1.2475304481671778723e-05 + p * w;
+ p = -4.7318229009055733981e-05 + p * w;
+ p = 6.8284851459573175448e-05 + p * w;
+ p = 2.4031110387097893999e-05 + p * w;
+ p = -0.0003550375203628474796 + p * w;
+ p = 0.00095328937973738049703 + p * w;
+ p = -0.0016882755560235047313 + p * w;
+ p = 0.0024914420961078508066 + p * w;
+ p = -0.0037512085075692412107 + p * w;
+ p = 0.005370914553590063617 + p * w;
+ p = 1.0052589676941592334 + p * w;
+ p = 3.0838856104922207635 + p * w;
+ } else {
+ w = sqrt(w) - 5.000000;
+ p = -2.7109920616438573243e-11;
+ p = -2.5556418169965252055e-10 + p * w;
+ p = 1.5076572693500548083e-09 + p * w;
+ p = -3.7894654401267369937e-09 + p * w;
+ p = 7.6157012080783393804e-09 + p * w;
+ p = -1.4960026627149240478e-08 + p * w;
+ p = 2.9147953450901080826e-08 + p * w;
+ p = -6.7711997758452339498e-08 + p * w;
+ p = 2.2900482228026654717e-07 + p * w;
+ p = -9.9298272942317002539e-07 + p * w;
+ p = 4.5260625972231537039e-06 + p * w;
+ p = -1.9681778105531670567e-05 + p * w;
+ p = 7.5995277030017761139e-05 + p * w;
+ p = -0.00021503011930044477347 + p * w;
+ p = -0.00013871931833623122026 + p * w;
+ p = 1.0103004648645343977 + p * w;
+ p = 4.8499064014085844221 + p * w;
+ }
+ return p * x;
+ }
+
+ double standard_deviation(std::vector<double>::iterator first, std::vector<double>::iterator last) {
+ auto m = Catch::Benchmark::Detail::mean(first, last);
+ double variance = std::accumulate(first, last, 0., [m](double a, double b) {
+ double diff = b - m;
+ return a + diff * diff;
+ }) / (last - first);
+ return std::sqrt(variance);
+ }
+
+}
+
+namespace Catch {
+ namespace Benchmark {
+ namespace Detail {
+
+ double weighted_average_quantile(int k, int q, std::vector<double>::iterator first, std::vector<double>::iterator last) {
+ auto count = last - first;
+ double idx = (count - 1) * k / static_cast<double>(q);
+ int j = static_cast<int>(idx);
+ double g = idx - j;
+ std::nth_element(first, first + j, last);
+ auto xj = first[j];
+ if (g == 0) return xj;
+
+ auto xj1 = *std::min_element(first + (j + 1), last);
+ return xj + g * (xj1 - xj);
+ }
+
+ double erfc_inv(double x) {
+ return erf_inv(1.0 - x);
+ }
+
+ double normal_quantile(double p) {
+ static const double ROOT_TWO = std::sqrt(2.0);
+
+ double result = 0.0;
+ assert(p >= 0 && p <= 1);
+ if (p < 0 || p > 1) {
+ return result;
+ }
+
+ result = -erfc_inv(2.0 * p);
+ // result *= normal distribution standard deviation (1.0) * sqrt(2)
+ result *= /*sd * */ ROOT_TWO;
+ // result += normal disttribution mean (0)
+ return result;
+ }
+
+ double outlier_variance(Estimate<double> mean, Estimate<double> stddev, int n) {
+ double sb = stddev.point;
+ double mn = mean.point / n;
+ double mg_min = mn / 2.;
+ double sg = (std::min)(mg_min / 4., sb / std::sqrt(n));
+ double sg2 = sg * sg;
+ double sb2 = sb * sb;
+
+ auto c_max = [n, mn, sb2, sg2](double x) -> double {
+ double k = mn - x;
+ double d = k * k;
+ double nd = n * d;
+ double k0 = -n * nd;
+ double k1 = sb2 - n * sg2 + nd;
+ double det = k1 * k1 - 4 * sg2 * k0;
+ return (int)(-2. * k0 / (k1 + std::sqrt(det)));
+ };
+
+ auto var_out = [n, sb2, sg2](double c) {
+ double nc = n - c;
+ return (nc / n) * (sb2 - nc * sg2);
+ };
+
+ return (std::min)(var_out(1), var_out((std::min)(c_max(0.), c_max(mg_min)))) / sb2;
+ }
+
+ bootstrap_analysis analyse_samples(double confidence_level, int n_resamples, std::vector<double>::iterator first, std::vector<double>::iterator last) {
+ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION
+ CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS
+ static std::random_device entropy;
+ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
+
+ auto n = static_cast<int>(last - first); // seriously, one can't use integral types without hell in C++
+
+ auto mean = &Detail::mean<std::vector<double>::iterator>;
+ auto stddev = &standard_deviation;
+
+#if defined(CATCH_CONFIG_USE_ASYNC)
+ auto Estimate = [=](double(*f)(std::vector<double>::iterator, std::vector<double>::iterator)) {
+ auto seed = entropy();
+ return std::async(std::launch::async, [=] {
+ std::mt19937 rng(seed);
+ auto resampled = resample(rng, n_resamples, first, last, f);
+ return bootstrap(confidence_level, first, last, resampled, f);
+ });
+ };
+
+ auto mean_future = Estimate(mean);
+ auto stddev_future = Estimate(stddev);
+
+ auto mean_estimate = mean_future.get();
+ auto stddev_estimate = stddev_future.get();
+#else
+ auto Estimate = [=](double(*f)(std::vector<double>::iterator, std::vector<double>::iterator)) {
+ auto seed = entropy();
+ std::mt19937 rng(seed);
+ auto resampled = resample(rng, n_resamples, first, last, f);
+ return bootstrap(confidence_level, first, last, resampled, f);
+ };
+
+ auto mean_estimate = Estimate(mean);
+ auto stddev_estimate = Estimate(stddev);
+#endif // CATCH_USE_ASYNC
+
+ double outlier_variance = Detail::outlier_variance(mean_estimate, stddev_estimate, n);
+
+ return { mean_estimate, stddev_estimate, outlier_variance };
+ }
+ } // namespace Detail
+ } // namespace Benchmark
+} // namespace Catch
+
+#endif // CATCH_CONFIG_ENABLE_BENCHMARKING
+// end catch_stats.cpp
// start catch_approx.cpp
#include <cmath>
@@ -5365,21 +7901,22 @@ namespace Detail {
bool Approx::equalityComparisonImpl(const double other) const {
// First try with fixed margin, then compute margin based on epsilon, scale and Approx's value
// Thanks to Richard Harris for his help refining the scaled margin value
- return marginComparison(m_value, other, m_margin) || marginComparison(m_value, other, m_epsilon * (m_scale + std::fabs(m_value)));
+ return marginComparison(m_value, other, m_margin)
+ || marginComparison(m_value, other, m_epsilon * (m_scale + std::fabs(std::isinf(m_value)? 0 : m_value)));
}
- void Approx::setMargin(double margin) {
- CATCH_ENFORCE(margin >= 0,
- "Invalid Approx::margin: " << margin << '.'
+ void Approx::setMargin(double newMargin) {
+ CATCH_ENFORCE(newMargin >= 0,
+ "Invalid Approx::margin: " << newMargin << '.'
<< " Approx::Margin has to be non-negative.");
- m_margin = margin;
+ m_margin = newMargin;
}
- void Approx::setEpsilon(double epsilon) {
- CATCH_ENFORCE(epsilon >= 0 && epsilon <= 1.0,
- "Invalid Approx::epsilon: " << epsilon << '.'
+ void Approx::setEpsilon(double newEpsilon) {
+ CATCH_ENFORCE(newEpsilon >= 0 && newEpsilon <= 1.0,
+ "Invalid Approx::epsilon: " << newEpsilon << '.'
<< " Approx::epsilon has to be in [0, 1]");
- m_epsilon = epsilon;
+ m_epsilon = newEpsilon;
}
} // end namespace Detail
@@ -5401,58 +7938,6 @@ std::string StringMaker<Catch::Detail::Approx>::convert(Catch::Detail::Approx co
// end catch_approx.cpp
// start catch_assertionhandler.cpp
-// start catch_context.h
-
-#include <memory>
-
-namespace Catch {
-
- struct IResultCapture;
- struct IRunner;
- struct IConfig;
- struct IMutableContext;
-
- using IConfigPtr = std::shared_ptr<IConfig const>;
-
- struct IContext
- {
- virtual ~IContext();
-
- virtual IResultCapture* getResultCapture() = 0;
- virtual IRunner* getRunner() = 0;
- virtual IConfigPtr const& getConfig() const = 0;
- };
-
- struct IMutableContext : IContext
- {
- virtual ~IMutableContext();
- virtual void setResultCapture( IResultCapture* resultCapture ) = 0;
- virtual void setRunner( IRunner* runner ) = 0;
- virtual void setConfig( IConfigPtr const& config ) = 0;
-
- private:
- static IMutableContext *currentContext;
- friend IMutableContext& getCurrentMutableContext();
- friend void cleanUpContext();
- static void createContext();
- };
-
- inline IMutableContext& getCurrentMutableContext()
- {
- if( !IMutableContext::currentContext )
- IMutableContext::createContext();
- return *IMutableContext::currentContext;
- }
-
- inline IContext& getCurrentContext()
- {
- return getCurrentMutableContext();
- }
-
- void cleanUpContext();
-}
-
-// end catch_context.h
// start catch_debugger.h
namespace Catch {
@@ -5461,7 +7946,24 @@ namespace Catch {
#ifdef CATCH_PLATFORM_MAC
- #define CATCH_TRAP() __asm__("int $3\n" : : ) /* NOLINT */
+ #if defined(__i386__) || defined(__x86_64__)
+ #define CATCH_TRAP() __asm__("int $3\n" : : ) /* NOLINT */
+ #elif defined(__aarch64__)
+ #define CATCH_TRAP() __asm__(".inst 0xd4200000")
+ #endif
+
+#elif defined(CATCH_PLATFORM_IPHONE)
+
+ // use inline assembler
+ #if defined(__i386__) || defined(__x86_64__)
+ #define CATCH_TRAP() __asm__("int $3")
+ #elif defined(__aarch64__)
+ #define CATCH_TRAP() __asm__(".inst 0xd4200000")
+ #elif defined(__arm__) && !defined(__thumb__)
+ #define CATCH_TRAP() __asm__(".inst 0xe7f001f0")
+ #elif defined(__arm__) && defined(__thumb__)
+ #define CATCH_TRAP() __asm__(".inst 0xde01")
+ #endif
#elif defined(CATCH_PLATFORM_LINUX)
// If we can use inline assembler, do it because this allows us to break
@@ -5481,13 +7983,12 @@ namespace Catch {
#define CATCH_TRAP() DebugBreak()
#endif
-#ifdef CATCH_TRAP
- #define CATCH_BREAK_INTO_DEBUGGER() if( Catch::isDebuggerActive() ) { CATCH_TRAP(); }
-#else
- namespace Catch {
- inline void doNothing() {}
- }
- #define CATCH_BREAK_INTO_DEBUGGER() Catch::doNothing()
+#ifndef CATCH_BREAK_INTO_DEBUGGER
+ #ifdef CATCH_TRAP
+ #define CATCH_BREAK_INTO_DEBUGGER() []{ if( Catch::isDebuggerActive() ) { CATCH_TRAP(); } }()
+ #else
+ #define CATCH_BREAK_INTO_DEBUGGER() []{}()
+ #endif
#endif
// end catch_debugger.h
@@ -5495,86 +7996,58 @@ namespace Catch {
// start catch_fatal_condition.h
-// start catch_windows_h_proxy.h
-
-
-#if defined(CATCH_PLATFORM_WINDOWS)
-
-#if !defined(NOMINMAX) && !defined(CATCH_CONFIG_NO_NOMINMAX)
-# define CATCH_DEFINED_NOMINMAX
-# define NOMINMAX
-#endif
-#if !defined(WIN32_LEAN_AND_MEAN) && !defined(CATCH_CONFIG_NO_WIN32_LEAN_AND_MEAN)
-# define CATCH_DEFINED_WIN32_LEAN_AND_MEAN
-# define WIN32_LEAN_AND_MEAN
-#endif
-
-#ifdef __AFXDLL
-#include <AfxWin.h>
-#else
-#include <windows.h>
-#endif
-
-#ifdef CATCH_DEFINED_NOMINMAX
-# undef NOMINMAX
-#endif
-#ifdef CATCH_DEFINED_WIN32_LEAN_AND_MEAN
-# undef WIN32_LEAN_AND_MEAN
-#endif
-
-#endif // defined(CATCH_PLATFORM_WINDOWS)
-
-// end catch_windows_h_proxy.h
-#if defined( CATCH_CONFIG_WINDOWS_SEH )
+#include <cassert>
namespace Catch {
- struct FatalConditionHandler {
-
- static LONG CALLBACK handleVectoredException(PEXCEPTION_POINTERS ExceptionInfo);
+ // Wrapper for platform-specific fatal error (signals/SEH) handlers
+ //
+ // Tries to be cooperative with other handlers, and not step over
+ // other handlers. This means that unknown structured exceptions
+ // are passed on, previous signal handlers are called, and so on.
+ //
+ // Can only be instantiated once, and assumes that once a signal
+ // is caught, the binary will end up terminating. Thus, there
+ class FatalConditionHandler {
+ bool m_started = false;
+
+ // Install/disengage implementation for specific platform.
+ // Should be if-defed to work on current platform, can assume
+ // engage-disengage 1:1 pairing.
+ void engage_platform();
+ void disengage_platform();
+ public:
+ // Should also have platform-specific implementations as needed
FatalConditionHandler();
- static void reset();
~FatalConditionHandler();
- private:
- static bool isSet;
- static ULONG guaranteeSize;
- static PVOID exceptionHandlerHandle;
- };
-
-} // namespace Catch
-
-#elif defined ( CATCH_CONFIG_POSIX_SIGNALS )
-
-#include <signal.h>
-
-namespace Catch {
-
- struct FatalConditionHandler {
-
- static bool isSet;
- static struct sigaction oldSigActions[];
- static stack_t oldSigStack;
- static char altStackMem[];
-
- static void handleSignal( int sig );
+ void engage() {
+ assert(!m_started && "Handler cannot be installed twice.");
+ m_started = true;
+ engage_platform();
+ }
- FatalConditionHandler();
- ~FatalConditionHandler();
- static void reset();
+ void disengage() {
+ assert(m_started && "Handler cannot be uninstalled without being installed first");
+ m_started = false;
+ disengage_platform();
+ }
};
-} // namespace Catch
-
-#else
-
-namespace Catch {
- struct FatalConditionHandler {
- void reset();
+ //! Simple RAII guard for (dis)engaging the FatalConditionHandler
+ class FatalConditionHandlerGuard {
+ FatalConditionHandler* m_handler;
+ public:
+ FatalConditionHandlerGuard(FatalConditionHandler* handler):
+ m_handler(handler) {
+ m_handler->engage();
+ }
+ ~FatalConditionHandlerGuard() {
+ m_handler->disengage();
+ }
};
-}
-#endif
+} // end namespace Catch
// end catch_fatal_condition.h
#include <string>
@@ -5634,14 +8107,20 @@ namespace Catch {
void sectionEnded( SectionEndInfo const& endInfo ) override;
void sectionEndedEarly( SectionEndInfo const& endInfo ) override;
- auto acquireGeneratorTracker( SourceLineInfo const& lineInfo ) -> IGeneratorTracker& override;
+ auto acquireGeneratorTracker( StringRef generatorName, SourceLineInfo const& lineInfo ) -> IGeneratorTracker& override;
+#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)
+ void benchmarkPreparing( std::string const& name ) override;
void benchmarkStarting( BenchmarkInfo const& info ) override;
- void benchmarkEnded( BenchmarkStats const& stats ) override;
+ void benchmarkEnded( BenchmarkStats<> const& stats ) override;
+ void benchmarkFailed( std::string const& error ) override;
+#endif // CATCH_CONFIG_ENABLE_BENCHMARKING
void pushScopedMessage( MessageInfo const& message ) override;
void popScopedMessage( MessageInfo const& message ) override;
+ void emplaceUnscopedMessage( MessageBuilder const& builder ) override;
+
std::string getCurrentTestName() const override;
const AssertionResult* getLastResult() const override;
@@ -5682,22 +8161,26 @@ namespace Catch {
TestRunInfo m_runInfo;
IMutableContext& m_context;
TestCase const* m_activeTestCase = nullptr;
- ITracker* m_testCaseTracker;
+ ITracker* m_testCaseTracker = nullptr;
Option<AssertionResult> m_lastResult;
IConfigPtr m_config;
Totals m_totals;
IStreamingReporterPtr m_reporter;
std::vector<MessageInfo> m_messages;
+ std::vector<ScopedMessage> m_messageScopes; /* Keeps owners of so-called unscoped messages. */
AssertionInfo m_lastAssertionInfo;
std::vector<SectionEndInfo> m_unfinishedSections;
std::vector<ITracker*> m_activeSections;
TrackerContext m_trackerContext;
+ FatalConditionHandler m_fatalConditionhandler;
bool m_lastAssertionPassed = false;
bool m_shouldReportUnexpected = true;
bool m_includeSuccessfulResults;
};
+ void seedRng(IConfig const& config);
+ unsigned int rngSeed();
} // end namespace Catch
// end catch_run_context.h
@@ -5844,7 +8327,7 @@ namespace Catch {
}
bool AssertionResult::hasExpression() const {
- return m_info.capturedExpression[0] != 0;
+ return !m_info.capturedExpression.empty();
}
bool AssertionResult::hasMessage() const {
@@ -5852,16 +8335,22 @@ namespace Catch {
}
std::string AssertionResult::getExpression() const {
- if( isFalseTest( m_info.resultDisposition ) )
- return "!(" + m_info.capturedExpression + ")";
- else
- return m_info.capturedExpression;
+ // Possibly overallocating by 3 characters should be basically free
+ std::string expr; expr.reserve(m_info.capturedExpression.size() + 3);
+ if (isFalseTest(m_info.resultDisposition)) {
+ expr += "!(";
+ }
+ expr += m_info.capturedExpression;
+ if (isFalseTest(m_info.resultDisposition)) {
+ expr += ')';
+ }
+ return expr;
}
std::string AssertionResult::getExpressionInMacro() const {
std::string expr;
- if( m_info.macroName[0] == 0 )
- expr = m_info.capturedExpression;
+ if( m_info.macroName.empty() )
+ expr = static_cast<std::string>(m_info.capturedExpression);
else {
expr.reserve( m_info.macroName.size() + m_info.capturedExpression.size() + 4 );
expr += m_info.macroName;
@@ -5896,32 +8385,6 @@ namespace Catch {
} // end namespace Catch
// end catch_assertionresult.cpp
-// start catch_benchmark.cpp
-
-namespace Catch {
-
- auto BenchmarkLooper::getResolution() -> uint64_t {
- return getEstimatedClockResolution() * getCurrentContext().getConfig()->benchmarkResolutionMultiple();
- }
-
- void BenchmarkLooper::reportStart() {
- getResultCapture().benchmarkStarting( { m_name } );
- }
- auto BenchmarkLooper::needsMoreIterations() -> bool {
- auto elapsed = m_timer.getElapsedNanoseconds();
-
- // Exponentially increasing iterations until we're confident in our timer resolution
- if( elapsed < m_resolution ) {
- m_iterationsToRun *= 10;
- return true;
- }
-
- getResultCapture().benchmarkEnded( { { m_name }, m_count, elapsed } );
- return false;
- }
-
-} // end namespace Catch
-// end catch_benchmark.cpp
// start catch_capture_matchers.cpp
namespace Catch {
@@ -6067,6 +8530,9 @@ public:
m_suffix = false;
auto width = m_column.m_width - indent();
m_end = m_pos;
+ if (line()[m_pos] == '\n') {
+ ++m_end;
+ }
while (m_end < line().size() && line()[m_end] != '\n')
++m_end;
@@ -6325,6 +8791,7 @@ inline auto Column::operator + (Column const& other) -> Columns {
// ----------- end of #include from clara_textflow.hpp -----------
// ........... back in clara.hpp
+#include <cctype>
#include <string>
#include <memory>
#include <set>
@@ -6617,7 +9084,7 @@ namespace detail {
}
inline auto convertInto( std::string const &source, bool &target ) -> ParserResult {
std::string srcLC = source;
- std::transform( srcLC.begin(), srcLC.end(), srcLC.begin(), []( char c ) { return static_cast<char>( ::tolower(c) ); } );
+ std::transform( srcLC.begin(), srcLC.end(), srcLC.begin(), []( unsigned char c ) { return static_cast<char>( std::tolower(c) ); } );
if (srcLC == "y" || srcLC == "1" || srcLC == "true" || srcLC == "yes" || srcLC == "on")
target = true;
else if (srcLC == "n" || srcLC == "0" || srcLC == "false" || srcLC == "no" || srcLC == "off")
@@ -7265,9 +9732,14 @@ namespace Catch {
if( !line.empty() && !startsWith( line, '#' ) ) {
if( !startsWith( line, '"' ) )
line = '"' + line + '"';
- config.testsOrTags.push_back( line + ',' );
+ config.testsOrTags.push_back( line );
+ config.testsOrTags.emplace_back( "," );
}
}
+ //Remove comma in the end
+ if(!config.testsOrTags.empty())
+ config.testsOrTags.erase( config.testsOrTags.end()-1 );
+
return ParserResult::ok( ParseResultType::Matched );
};
auto const setTestOrder = [&]( std::string const& order ) {
@@ -7302,14 +9774,16 @@ namespace Catch {
};
auto const setWaitForKeypress = [&]( std::string const& keypress ) {
auto keypressLc = toLower( keypress );
- if( keypressLc == "start" )
+ if (keypressLc == "never")
+ config.waitForKeypress = WaitForKeypress::Never;
+ else if( keypressLc == "start" )
config.waitForKeypress = WaitForKeypress::BeforeStart;
else if( keypressLc == "exit" )
config.waitForKeypress = WaitForKeypress::BeforeExit;
else if( keypressLc == "both" )
config.waitForKeypress = WaitForKeypress::BeforeStartAndExit;
else
- return ParserResult::runtimeError( "keypress argument must be one of: start, exit or both. '" + keypress + "' not recognised" );
+ return ParserResult::runtimeError( "keypress argument must be one of: never, start, exit or both. '" + keypress + "' not recognised" );
return ParserResult::ok( ParseResultType::Matched );
};
auto const setVerbosity = [&]( std::string const& verbosity ) {
@@ -7379,6 +9853,9 @@ namespace Catch {
| Opt( [&]( bool flag ) { config.showDurations = flag ? ShowDurations::Always : ShowDurations::Never; }, "yes|no" )
["-d"]["--durations"]
( "show test durations" )
+ | Opt( config.minDuration, "seconds" )
+ ["-D"]["--min-duration"]
+ ( "show test durations for tests taking at least the given number of seconds" )
| Opt( loadTestNamesFromFile, "filename" )
["-f"]["--input-file"]
( "load test names to run from a file" )
@@ -7409,13 +9886,24 @@ namespace Catch {
| Opt( config.libIdentify )
["--libidentify"]
( "report name and version according to libidentify standard" )
- | Opt( setWaitForKeypress, "start|exit|both" )
+ | Opt( setWaitForKeypress, "never|start|exit|both" )
["--wait-for-keypress"]
( "waits for a keypress before exiting" )
- | Opt( config.benchmarkResolutionMultiple, "multiplier" )
- ["--benchmark-resolution-multiple"]
- ( "multiple of clock resolution to run benchmarks" )
-
+ | Opt( config.benchmarkSamples, "samples" )
+ ["--benchmark-samples"]
+ ( "number of samples to collect (default: 100)" )
+ | Opt( config.benchmarkResamples, "resamples" )
+ ["--benchmark-resamples"]
+ ( "number of resamples for the bootstrap (default: 100000)" )
+ | Opt( config.benchmarkConfidenceInterval, "confidence interval" )
+ ["--benchmark-confidence-interval"]
+ ( "confidence interval for the bootstrap (between 0 and 1, default: 0.95)" )
+ | Opt( config.benchmarkNoAnalysis )
+ ["--benchmark-no-analysis"]
+ ( "perform only measurements; do not perform any analysis" )
+ | Opt( config.benchmarkWarmupTime, "benchmarkWarmupTime" )
+ ["--benchmark-warmup-time"]
+ ( "amount of time in milliseconds spent on warming up each test (default: 100)" )
| Arg( config.testsOrTags, "test name|pattern|tags" )
( "which test or tests to use" );
@@ -7431,9 +9919,6 @@ namespace Catch {
namespace Catch {
- bool SourceLineInfo::empty() const noexcept {
- return file[0] == '\0';
- }
bool SourceLineInfo::operator == ( SourceLineInfo const& other ) const noexcept {
return line == other.line && (file == other.file || std::strcmp(file, other.file) == 0);
}
@@ -7469,14 +9954,23 @@ namespace Catch {
: m_data( data ),
m_stream( openStream() )
{
- TestSpecParser parser(ITagAliasRegistry::get());
- if (data.testsOrTags.empty()) {
- parser.parse("~[.]"); // All not hidden tests
+ // We need to trim filter specs to avoid trouble with superfluous
+ // whitespace (esp. important for bdd macros, as those are manually
+ // aligned with whitespace).
+
+ for (auto& elem : m_data.testsOrTags) {
+ elem = trim(elem);
}
- else {
+ for (auto& elem : m_data.sectionsToRun) {
+ elem = trim(elem);
+ }
+
+ TestSpecParser parser(ITagAliasRegistry::get());
+ if (!m_data.testsOrTags.empty()) {
m_hasTestFilters = true;
- for( auto const& testOrTags : data.testsOrTags )
- parser.parse( testOrTags );
+ for (auto const& testOrTags : m_data.testsOrTags) {
+ parser.parse(testOrTags);
+ }
}
m_testSpec = parser.testSpec();
}
@@ -7509,15 +10003,21 @@ namespace Catch {
bool Config::warnAboutMissingAssertions() const { return !!(m_data.warnings & WarnAbout::NoAssertions); }
bool Config::warnAboutNoTests() const { return !!(m_data.warnings & WarnAbout::NoTests); }
ShowDurations::OrNot Config::showDurations() const { return m_data.showDurations; }
+ double Config::minDuration() const { return m_data.minDuration; }
RunTests::InWhatOrder Config::runOrder() const { return m_data.runOrder; }
unsigned int Config::rngSeed() const { return m_data.rngSeed; }
- int Config::benchmarkResolutionMultiple() const { return m_data.benchmarkResolutionMultiple; }
UseColour::YesOrNo Config::useColour() const { return m_data.useColour; }
bool Config::shouldDebugBreak() const { return m_data.shouldDebugBreak; }
int Config::abortAfter() const { return m_data.abortAfter; }
bool Config::showInvisibles() const { return m_data.showInvisibles; }
Verbosity Config::verbosity() const { return m_data.verbosity; }
+ bool Config::benchmarkNoAnalysis() const { return m_data.benchmarkNoAnalysis; }
+ int Config::benchmarkSamples() const { return m_data.benchmarkSamples; }
+ double Config::benchmarkConfidenceInterval() const { return m_data.benchmarkConfidenceInterval; }
+ unsigned int Config::benchmarkResamples() const { return m_data.benchmarkResamples; }
+ std::chrono::milliseconds Config::benchmarkWarmupTime() const { return std::chrono::milliseconds(m_data.benchmarkWarmupTime); }
+
IStream const* Config::openStream() {
return Catch::makeStream(m_data.outputFilename);
}
@@ -7546,6 +10046,36 @@ namespace Catch {
}
// end catch_errno_guard.h
+// start catch_windows_h_proxy.h
+
+
+#if defined(CATCH_PLATFORM_WINDOWS)
+
+#if !defined(NOMINMAX) && !defined(CATCH_CONFIG_NO_NOMINMAX)
+# define CATCH_DEFINED_NOMINMAX
+# define NOMINMAX
+#endif
+#if !defined(WIN32_LEAN_AND_MEAN) && !defined(CATCH_CONFIG_NO_WIN32_LEAN_AND_MEAN)
+# define CATCH_DEFINED_WIN32_LEAN_AND_MEAN
+# define WIN32_LEAN_AND_MEAN
+#endif
+
+#ifdef __AFXDLL
+#include <AfxWin.h>
+#else
+#include <windows.h>
+#endif
+
+#ifdef CATCH_DEFINED_NOMINMAX
+# undef NOMINMAX
+#endif
+#ifdef CATCH_DEFINED_WIN32_LEAN_AND_MEAN
+# undef WIN32_LEAN_AND_MEAN
+#endif
+
+#endif // defined(CATCH_PLATFORM_WINDOWS)
+
+// end catch_windows_h_proxy.h
#include <sstream>
namespace Catch {
@@ -7557,7 +10087,7 @@ namespace Catch {
};
struct NoColourImpl : IColourImpl {
- void use( Colour::Code ) {}
+ void use( Colour::Code ) override {}
static IColourImpl* instance() {
static NoColourImpl s_instance;
@@ -7591,7 +10121,7 @@ namespace {
originalBackgroundAttributes = csbiInfo.wAttributes & ~( FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_INTENSITY );
}
- virtual void use( Colour::Code _colourCode ) override {
+ void use( Colour::Code _colourCode ) override {
switch( _colourCode ) {
case Colour::None: return setTextAttribute( originalForegroundAttributes );
case Colour::White: return setTextAttribute( FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE );
@@ -7654,7 +10184,7 @@ namespace {
// https://github.com/philsquared/Catch/pull/131
class PosixColourImpl : public IColourImpl {
public:
- virtual void use( Colour::Code _colourCode ) override {
+ void use( Colour::Code _colourCode ) override {
switch( _colourCode ) {
case Colour::None:
case Colour::White: return setColour( "[0m" );
@@ -7682,13 +10212,14 @@ namespace {
private:
void setColour( const char* _escapeCode ) {
- Catch::cout() << '\033' << _escapeCode;
+ getCurrentContext().getConfig()->stream()
+ << '\033' << _escapeCode;
}
};
bool useColourOnPlatform() {
return
-#ifdef CATCH_PLATFORM_MAC
+#if defined(CATCH_PLATFORM_MAC) || defined(CATCH_PLATFORM_IPHONE)
!isDebuggerActive() &&
#endif
#if !(defined(__DJGPP__) && defined(__STRICT_ANSI__))
@@ -7729,13 +10260,13 @@ namespace Catch {
namespace Catch {
Colour::Colour( Code _colourCode ) { use( _colourCode ); }
- Colour::Colour( Colour&& rhs ) noexcept {
- m_moved = rhs.m_moved;
- rhs.m_moved = true;
+ Colour::Colour( Colour&& other ) noexcept {
+ m_moved = other.m_moved;
+ other.m_moved = true;
}
- Colour& Colour::operator=( Colour&& rhs ) noexcept {
- m_moved = rhs.m_moved;
- rhs.m_moved = true;
+ Colour& Colour::operator=( Colour&& other ) noexcept {
+ m_moved = other.m_moved;
+ other.m_moved = true;
return *this;
}
@@ -7743,7 +10274,13 @@ namespace Catch {
void Colour::use( Code _colourCode ) {
static IColourImpl* impl = platformColourInstance();
- impl->use( _colourCode );
+ // Strictly speaking, this cannot possibly happen.
+ // However, under some conditions it does happen (see #1626),
+ // and this change is small enough that we can let practicality
+ // triumph over purity in this case.
+ if (impl != nullptr) {
+ impl->use( _colourCode );
+ }
}
std::ostream& operator << ( std::ostream& os, Colour const& ) {
@@ -7764,27 +10301,27 @@ namespace Catch {
class Context : public IMutableContext, NonCopyable {
public: // IContext
- virtual IResultCapture* getResultCapture() override {
+ IResultCapture* getResultCapture() override {
return m_resultCapture;
}
- virtual IRunner* getRunner() override {
+ IRunner* getRunner() override {
return m_runner;
}
- virtual IConfigPtr const& getConfig() const override {
+ IConfigPtr const& getConfig() const override {
return m_config;
}
- virtual ~Context() override;
+ ~Context() override;
public: // IMutableContext
- virtual void setResultCapture( IResultCapture* resultCapture ) override {
+ void setResultCapture( IResultCapture* resultCapture ) override {
m_resultCapture = resultCapture;
}
- virtual void setRunner( IRunner* runner ) override {
+ void setRunner( IRunner* runner ) override {
m_runner = runner;
}
- virtual void setConfig( IConfigPtr const& config ) override {
+ void setConfig( IConfigPtr const& config ) override {
m_config = config;
}
@@ -7810,6 +10347,12 @@ namespace Catch {
IContext::~IContext() = default;
IMutableContext::~IMutableContext() = default;
Context::~Context() = default;
+
+ SimplePcg32& rng() {
+ static SimplePcg32 s_rng;
+ return s_rng;
+ }
+
}
// end catch_context.cpp
// start catch_debug_console.cpp
@@ -7823,7 +10366,16 @@ namespace Catch {
}
// end catch_debug_console.h
-#ifdef CATCH_PLATFORM_WINDOWS
+#if defined(CATCH_CONFIG_ANDROID_LOGWRITE)
+#include <android/log.h>
+
+ namespace Catch {
+ void writeToDebugConsole( std::string const& text ) {
+ __android_log_write( ANDROID_LOG_DEBUG, "Catch", text.c_str() );
+ }
+ }
+
+#elif defined(CATCH_PLATFORM_WINDOWS)
namespace Catch {
void writeToDebugConsole( std::string const& text ) {
@@ -7844,25 +10396,28 @@ namespace Catch {
// end catch_debug_console.cpp
// start catch_debugger.cpp
-#ifdef CATCH_PLATFORM_MAC
+#if defined(CATCH_PLATFORM_MAC) || defined(CATCH_PLATFORM_IPHONE)
-# include <assert.h>
-# include <stdbool.h>
+# include <cassert>
# include <sys/types.h>
# include <unistd.h>
-# include <sys/sysctl.h>
# include <cstddef>
# include <ostream>
-namespace Catch {
+#ifdef __apple_build_version__
+ // These headers will only compile with AppleClang (XCode)
+ // For other compilers (Clang, GCC, ... ) we need to exclude them
+# include <sys/sysctl.h>
+#endif
+ namespace Catch {
+ #ifdef __apple_build_version__
// The following function is taken directly from the following technical note:
- // http://developer.apple.com/library/mac/#qa/qa2004/qa1361.html
+ // https://developer.apple.com/library/archive/qa/qa1361/_index.html
// Returns true if the current process is being debugged (either
// running under the debugger or has a debugger attached post facto).
bool isDebuggerActive(){
-
int mib[4];
struct kinfo_proc info;
std::size_t size;
@@ -7892,6 +10447,12 @@ namespace Catch {
return ( (info.kp_proc.p_flag & P_TRACED) != 0 );
}
+ #else
+ bool isDebuggerActive() {
+ // We need to find another way to determine this for non-appleclang compilers on macOS
+ return false;
+ }
+ #endif
} // namespace Catch
#elif defined(CATCH_PLATFORM_LINUX)
@@ -7962,6 +10523,8 @@ namespace Catch {
// end catch_decomposer.cpp
// start catch_enforce.cpp
+#include <stdexcept>
+
namespace Catch {
#if defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) && !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS_CUSTOM_HANDLER)
[[noreturn]]
@@ -7971,8 +10534,116 @@ namespace Catch {
std::terminate();
}
#endif
+
+ [[noreturn]]
+ void throw_logic_error(std::string const& msg) {
+ throw_exception(std::logic_error(msg));
+ }
+
+ [[noreturn]]
+ void throw_domain_error(std::string const& msg) {
+ throw_exception(std::domain_error(msg));
+ }
+
+ [[noreturn]]
+ void throw_runtime_error(std::string const& msg) {
+ throw_exception(std::runtime_error(msg));
+ }
+
} // namespace Catch;
// end catch_enforce.cpp
+// start catch_enum_values_registry.cpp
+// start catch_enum_values_registry.h
+
+#include <vector>
+#include <memory>
+
+namespace Catch {
+
+ namespace Detail {
+
+ std::unique_ptr<EnumInfo> makeEnumInfo( StringRef enumName, StringRef allValueNames, std::vector<int> const& values );
+
+ class EnumValuesRegistry : public IMutableEnumValuesRegistry {
+
+ std::vector<std::unique_ptr<EnumInfo>> m_enumInfos;
+
+ EnumInfo const& registerEnum( StringRef enumName, StringRef allEnums, std::vector<int> const& values) override;
+ };
+
+ std::vector<StringRef> parseEnums( StringRef enums );
+
+ } // Detail
+
+} // Catch
+
+// end catch_enum_values_registry.h
+
+#include <map>
+#include <cassert>
+
+namespace Catch {
+
+ IMutableEnumValuesRegistry::~IMutableEnumValuesRegistry() {}
+
+ namespace Detail {
+
+ namespace {
+ // Extracts the actual name part of an enum instance
+ // In other words, it returns the Blue part of Bikeshed::Colour::Blue
+ StringRef extractInstanceName(StringRef enumInstance) {
+ // Find last occurrence of ":"
+ size_t name_start = enumInstance.size();
+ while (name_start > 0 && enumInstance[name_start - 1] != ':') {
+ --name_start;
+ }
+ return enumInstance.substr(name_start, enumInstance.size() - name_start);
+ }
+ }
+
+ std::vector<StringRef> parseEnums( StringRef enums ) {
+ auto enumValues = splitStringRef( enums, ',' );
+ std::vector<StringRef> parsed;
+ parsed.reserve( enumValues.size() );
+ for( auto const& enumValue : enumValues ) {
+ parsed.push_back(trim(extractInstanceName(enumValue)));
+ }
+ return parsed;
+ }
+
+ EnumInfo::~EnumInfo() {}
+
+ StringRef EnumInfo::lookup( int value ) const {
+ for( auto const& valueToName : m_values ) {
+ if( valueToName.first == value )
+ return valueToName.second;
+ }
+ return "{** unexpected enum value **}"_sr;
+ }
+
+ std::unique_ptr<EnumInfo> makeEnumInfo( StringRef enumName, StringRef allValueNames, std::vector<int> const& values ) {
+ std::unique_ptr<EnumInfo> enumInfo( new EnumInfo );
+ enumInfo->m_name = enumName;
+ enumInfo->m_values.reserve( values.size() );
+
+ const auto valueNames = Catch::Detail::parseEnums( allValueNames );
+ assert( valueNames.size() == values.size() );
+ std::size_t i = 0;
+ for( auto value : values )
+ enumInfo->m_values.emplace_back(value, valueNames[i++]);
+
+ return enumInfo;
+ }
+
+ EnumInfo const& EnumValuesRegistry::registerEnum( StringRef enumName, StringRef allValueNames, std::vector<int> const& values ) {
+ m_enumInfos.push_back(makeEnumInfo(enumName, allValueNames, values));
+ return *m_enumInfos.back();
+ }
+
+ } // Detail
+} // Catch
+
+// end catch_enum_values_registry.cpp
// start catch_errno_guard.cpp
#include <cerrno>
@@ -7996,7 +10667,7 @@ namespace Catch {
public:
~ExceptionTranslatorRegistry();
virtual void registerTranslator( const IExceptionTranslator* translator );
- virtual std::string translateActiveException() const override;
+ std::string translateActiveException() const override;
std::string tryTranslators() const;
private:
@@ -8061,54 +10732,82 @@ namespace Catch {
}
}
+ std::string ExceptionTranslatorRegistry::tryTranslators() const {
+ if (m_translators.empty()) {
+ std::rethrow_exception(std::current_exception());
+ } else {
+ return m_translators[0]->translate(m_translators.begin() + 1, m_translators.end());
+ }
+ }
+
#else // ^^ Exceptions are enabled // Exceptions are disabled vv
std::string ExceptionTranslatorRegistry::translateActiveException() const {
CATCH_INTERNAL_ERROR("Attempted to translate active exception under CATCH_CONFIG_DISABLE_EXCEPTIONS!");
}
-#endif
std::string ExceptionTranslatorRegistry::tryTranslators() const {
- if( m_translators.empty() )
- std::rethrow_exception(std::current_exception());
- else
- return m_translators[0]->translate( m_translators.begin()+1, m_translators.end() );
+ CATCH_INTERNAL_ERROR("Attempted to use exception translators under CATCH_CONFIG_DISABLE_EXCEPTIONS!");
}
+#endif
+
}
// end catch_exception_translator_registry.cpp
// start catch_fatal_condition.cpp
-#if defined(__GNUC__)
-# pragma GCC diagnostic push
-# pragma GCC diagnostic ignored "-Wmissing-field-initializers"
-#endif
+#include <algorithm>
+
+#if !defined( CATCH_CONFIG_WINDOWS_SEH ) && !defined( CATCH_CONFIG_POSIX_SIGNALS )
+
+namespace Catch {
+
+ // If neither SEH nor signal handling is required, the handler impls
+ // do not have to do anything, and can be empty.
+ void FatalConditionHandler::engage_platform() {}
+ void FatalConditionHandler::disengage_platform() {}
+ FatalConditionHandler::FatalConditionHandler() = default;
+ FatalConditionHandler::~FatalConditionHandler() = default;
+
+} // end namespace Catch
+
+#endif // !CATCH_CONFIG_WINDOWS_SEH && !CATCH_CONFIG_POSIX_SIGNALS
+
+#if defined( CATCH_CONFIG_WINDOWS_SEH ) && defined( CATCH_CONFIG_POSIX_SIGNALS )
+#error "Inconsistent configuration: Windows' SEH handling and POSIX signals cannot be enabled at the same time"
+#endif // CATCH_CONFIG_WINDOWS_SEH && CATCH_CONFIG_POSIX_SIGNALS
#if defined( CATCH_CONFIG_WINDOWS_SEH ) || defined( CATCH_CONFIG_POSIX_SIGNALS )
namespace {
- // Report the error condition
+ //! Signals fatal error message to the run context
void reportFatal( char const * const message ) {
Catch::getCurrentContext().getResultCapture()->handleFatalErrorCondition( message );
}
-}
-#endif // signals/SEH handling
+ //! Minimal size Catch2 needs for its own fatal error handling.
+ //! Picked anecdotally, so it might not be sufficient on all
+ //! platforms, and for all configurations.
+ constexpr std::size_t minStackSizeForErrors = 32 * 1024;
+} // end unnamed namespace
+
+#endif // CATCH_CONFIG_WINDOWS_SEH || CATCH_CONFIG_POSIX_SIGNALS
#if defined( CATCH_CONFIG_WINDOWS_SEH )
namespace Catch {
+
struct SignalDefs { DWORD id; const char* name; };
// There is no 1-1 mapping between signals and windows exceptions.
// Windows can easily distinguish between SO and SigSegV,
// but SigInt, SigTerm, etc are handled differently.
static SignalDefs signalDefs[] = {
- { EXCEPTION_ILLEGAL_INSTRUCTION, "SIGILL - Illegal instruction signal" },
- { EXCEPTION_STACK_OVERFLOW, "SIGSEGV - Stack overflow" },
- { EXCEPTION_ACCESS_VIOLATION, "SIGSEGV - Segmentation violation signal" },
- { EXCEPTION_INT_DIVIDE_BY_ZERO, "Divide by zero error" },
+ { static_cast<DWORD>(EXCEPTION_ILLEGAL_INSTRUCTION), "SIGILL - Illegal instruction signal" },
+ { static_cast<DWORD>(EXCEPTION_STACK_OVERFLOW), "SIGSEGV - Stack overflow" },
+ { static_cast<DWORD>(EXCEPTION_ACCESS_VIOLATION), "SIGSEGV - Segmentation violation signal" },
+ { static_cast<DWORD>(EXCEPTION_INT_DIVIDE_BY_ZERO), "Divide by zero error" },
};
- LONG CALLBACK FatalConditionHandler::handleVectoredException(PEXCEPTION_POINTERS ExceptionInfo) {
+ static LONG CALLBACK handleVectoredException(PEXCEPTION_POINTERS ExceptionInfo) {
for (auto const& def : signalDefs) {
if (ExceptionInfo->ExceptionRecord->ExceptionCode == def.id) {
reportFatal(def.name);
@@ -8119,38 +10818,50 @@ namespace Catch {
return EXCEPTION_CONTINUE_SEARCH;
}
+ // Since we do not support multiple instantiations, we put these
+ // into global variables and rely on cleaning them up in outlined
+ // constructors/destructors
+ static PVOID exceptionHandlerHandle = nullptr;
+
+ // For MSVC, we reserve part of the stack memory for handling
+ // memory overflow structured exception.
FatalConditionHandler::FatalConditionHandler() {
- isSet = true;
- // 32k seems enough for Catch to handle stack overflow,
- // but the value was found experimentally, so there is no strong guarantee
- guaranteeSize = 32 * 1024;
- exceptionHandlerHandle = nullptr;
+ ULONG guaranteeSize = static_cast<ULONG>(minStackSizeForErrors);
+ if (!SetThreadStackGuarantee(&guaranteeSize)) {
+ // We do not want to fully error out, because needing
+ // the stack reserve should be rare enough anyway.
+ Catch::cerr()
+ << "Failed to reserve piece of stack."
+ << " Stack overflows will not be reported successfully.";
+ }
+ }
+
+ // We do not attempt to unset the stack guarantee, because
+ // Windows does not support lowering the stack size guarantee.
+ FatalConditionHandler::~FatalConditionHandler() = default;
+
+ void FatalConditionHandler::engage_platform() {
// Register as first handler in current chain
exceptionHandlerHandle = AddVectoredExceptionHandler(1, handleVectoredException);
- // Pass in guarantee size to be filled
- SetThreadStackGuarantee(&guaranteeSize);
+ if (!exceptionHandlerHandle) {
+ CATCH_RUNTIME_ERROR("Could not register vectored exception handler");
+ }
}
- void FatalConditionHandler::reset() {
- if (isSet) {
- RemoveVectoredExceptionHandler(exceptionHandlerHandle);
- SetThreadStackGuarantee(&guaranteeSize);
- exceptionHandlerHandle = nullptr;
- isSet = false;
+ void FatalConditionHandler::disengage_platform() {
+ if (!RemoveVectoredExceptionHandler(exceptionHandlerHandle)) {
+ CATCH_RUNTIME_ERROR("Could not unregister vectored exception handler");
}
+ exceptionHandlerHandle = nullptr;
}
- FatalConditionHandler::~FatalConditionHandler() {
- reset();
- }
+} // end namespace Catch
-bool FatalConditionHandler::isSet = false;
-ULONG FatalConditionHandler::guaranteeSize = 0;
-PVOID FatalConditionHandler::exceptionHandlerHandle = nullptr;
+#endif // CATCH_CONFIG_WINDOWS_SEH
-} // namespace Catch
+#if defined( CATCH_CONFIG_POSIX_SIGNALS )
-#elif defined( CATCH_CONFIG_POSIX_SIGNALS )
+#include <signal.h>
namespace Catch {
@@ -8159,10 +10870,6 @@ namespace Catch {
const char* name;
};
- // 32kb for the alternate stack seems to be sufficient. However, this value
- // is experimentally determined, so that's not guaranteed.
- constexpr static std::size_t sigStackSize = 32768 >= MINSIGSTKSZ ? 32768 : MINSIGSTKSZ;
-
static SignalDefs signalDefs[] = {
{ SIGINT, "SIGINT - Terminal interrupt signal" },
{ SIGILL, "SIGILL - Illegal instruction signal" },
@@ -8172,7 +10879,32 @@ namespace Catch {
{ SIGABRT, "SIGABRT - Abort (abnormal termination) signal" }
};
- void FatalConditionHandler::handleSignal( int sig ) {
+// Older GCCs trigger -Wmissing-field-initializers for T foo = {}
+// which is zero initialization, but not explicit. We want to avoid
+// that.
+#if defined(__GNUC__)
+# pragma GCC diagnostic push
+# pragma GCC diagnostic ignored "-Wmissing-field-initializers"
+#endif
+
+ static char* altStackMem = nullptr;
+ static std::size_t altStackSize = 0;
+ static stack_t oldSigStack{};
+ static struct sigaction oldSigActions[sizeof(signalDefs) / sizeof(SignalDefs)]{};
+
+ static void restorePreviousSignalHandlers() {
+ // We set signal handlers back to the previous ones. Hopefully
+ // nobody overwrote them in the meantime, and doesn't expect
+ // their signal handlers to live past ours given that they
+ // installed them after ours..
+ for (std::size_t i = 0; i < sizeof(signalDefs) / sizeof(SignalDefs); ++i) {
+ sigaction(signalDefs[i].id, &oldSigActions[i], nullptr);
+ }
+ // Return the old stack
+ sigaltstack(&oldSigStack, nullptr);
+ }
+
+ static void handleSignal( int sig ) {
char const * name = "<unknown signal>";
for (auto const& def : signalDefs) {
if (sig == def.id) {
@@ -8180,16 +10912,33 @@ namespace Catch {
break;
}
}
- reset();
- reportFatal(name);
+ // We need to restore previous signal handlers and let them do
+ // their thing, so that the users can have the debugger break
+ // when a signal is raised, and so on.
+ restorePreviousSignalHandlers();
+ reportFatal( name );
raise( sig );
}
FatalConditionHandler::FatalConditionHandler() {
- isSet = true;
+ assert(!altStackMem && "Cannot initialize POSIX signal handler when one already exists");
+ if (altStackSize == 0) {
+ altStackSize = std::max(static_cast<size_t>(SIGSTKSZ), minStackSizeForErrors);
+ }
+ altStackMem = new char[altStackSize]();
+ }
+
+ FatalConditionHandler::~FatalConditionHandler() {
+ delete[] altStackMem;
+ // We signal that another instance can be constructed by zeroing
+ // out the pointer.
+ altStackMem = nullptr;
+ }
+
+ void FatalConditionHandler::engage_platform() {
stack_t sigStack;
sigStack.ss_sp = altStackMem;
- sigStack.ss_size = sigStackSize;
+ sigStack.ss_size = altStackSize;
sigStack.ss_flags = 0;
sigaltstack(&sigStack, &oldSigStack);
struct sigaction sa = { };
@@ -8201,59 +10950,20 @@ namespace Catch {
}
}
- FatalConditionHandler::~FatalConditionHandler() {
- reset();
- }
-
- void FatalConditionHandler::reset() {
- if( isSet ) {
- // Set signals back to previous values -- hopefully nobody overwrote them in the meantime
- for( std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i ) {
- sigaction(signalDefs[i].id, &oldSigActions[i], nullptr);
- }
- // Return the old stack
- sigaltstack(&oldSigStack, nullptr);
- isSet = false;
- }
- }
-
- bool FatalConditionHandler::isSet = false;
- struct sigaction FatalConditionHandler::oldSigActions[sizeof(signalDefs)/sizeof(SignalDefs)] = {};
- stack_t FatalConditionHandler::oldSigStack = {};
- char FatalConditionHandler::altStackMem[sigStackSize] = {};
-
-} // namespace Catch
-
-#else
-
-namespace Catch {
- void FatalConditionHandler::reset() {}
-}
-
-#endif // signals/SEH handling
-
#if defined(__GNUC__)
# pragma GCC diagnostic pop
#endif
-// end catch_fatal_condition.cpp
-// start catch_generators.cpp
-
-// start catch_random_number_generator.h
-
-#include <algorithm>
-#include <random>
-
-namespace Catch {
- struct IConfig;
+ void FatalConditionHandler::disengage_platform() {
+ restorePreviousSignalHandlers();
+ }
- std::mt19937& rng();
- void seedRng( IConfig const& config );
- unsigned int rngSeed();
+} // end namespace Catch
-}
+#endif // CATCH_CONFIG_POSIX_SIGNALS
+// end catch_fatal_condition.cpp
+// start catch_generators.cpp
-// end catch_random_number_generator.h
#include <limits>
#include <set>
@@ -8261,34 +10971,16 @@ namespace Catch {
IGeneratorTracker::~IGeneratorTracker() {}
-namespace Generators {
-
- GeneratorBase::~GeneratorBase() {}
-
- std::vector<size_t> randomiseIndices( size_t selectionSize, size_t sourceSize ) {
+const char* GeneratorException::what() const noexcept {
+ return m_msg;
+}
- assert( selectionSize <= sourceSize );
- std::vector<size_t> indices;
- indices.reserve( selectionSize );
- std::uniform_int_distribution<size_t> uid( 0, sourceSize-1 );
+namespace Generators {
- std::set<size_t> seen;
- // !TBD: improve this algorithm
- while( indices.size() < selectionSize ) {
- auto index = uid( rng() );
- if( seen.insert( index ).second )
- indices.push_back( index );
- }
- return indices;
- }
+ GeneratorUntypedBase::~GeneratorUntypedBase() {}
- auto acquireGeneratorTracker( SourceLineInfo const& lineInfo ) -> IGeneratorTracker& {
- return getResultCapture().acquireGeneratorTracker( lineInfo );
- }
-
- template<>
- auto all<int>() -> Generator<int> {
- return range( std::numeric_limits<int>::min(), std::numeric_limits<int>::max() );
+ auto acquireGeneratorTracker( StringRef generatorName, SourceLineInfo const& lineInfo ) -> IGeneratorTracker& {
+ return getResultCapture().acquireGeneratorTracker( generatorName, lineInfo );
}
} // namespace Generators
@@ -8344,10 +11036,16 @@ namespace Catch {
void noMatchingTestCases( std::string const& spec ) override;
+ void reportInvalidArguments(std::string const&arg) override;
+
static std::set<Verbosity> getSupportedVerbosities();
+#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)
+ void benchmarkPreparing(std::string const& name) override;
void benchmarkStarting( BenchmarkInfo const& benchmarkInfo ) override;
- void benchmarkEnded( BenchmarkStats const& benchmarkStats ) override;
+ void benchmarkEnded( BenchmarkStats<> const& benchmarkStats ) override;
+ void benchmarkFailed(std::string const&) override;
+#endif // CATCH_CONFIG_ENABLE_BENCHMARKING
void testRunStarting( TestRunInfo const& testRunInfo ) override;
void testGroupStarting( GroupInfo const& groupInfo ) override;
@@ -8538,7 +11236,7 @@ namespace Catch {
std::size_t listReporters();
- Option<std::size_t> list( Config const& config );
+ Option<std::size_t> list( std::shared_ptr<Config> const& config );
} // end namespace Catch
@@ -8557,7 +11255,7 @@ namespace Catch {
namespace Catch {
std::size_t listTests( Config const& config ) {
- TestSpec testSpec = config.testSpec();
+ TestSpec const& testSpec = config.testSpec();
if( config.hasTestFilters() )
Catch::cout() << "Matching test cases:\n";
else {
@@ -8591,7 +11289,7 @@ namespace Catch {
}
std::size_t listTestsNamesOnly( Config const& config ) {
- TestSpec testSpec = config.testSpec();
+ TestSpec const& testSpec = config.testSpec();
std::size_t matchedTests = 0;
std::vector<TestCase> matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config );
for( auto const& testCaseInfo : matchedTestCases ) {
@@ -8613,14 +11311,23 @@ namespace Catch {
}
std::string TagInfo::all() const {
- std::string out;
- for( auto const& spelling : spellings )
- out += "[" + spelling + "]";
+ size_t size = 0;
+ for (auto const& spelling : spellings) {
+ // Add 2 for the brackes
+ size += spelling.size() + 2;
+ }
+
+ std::string out; out.reserve(size);
+ for (auto const& spelling : spellings) {
+ out += '[';
+ out += spelling;
+ out += ']';
+ }
return out;
}
std::size_t listTags( Config const& config ) {
- TestSpec testSpec = config.testSpec();
+ TestSpec const& testSpec = config.testSpec();
if( config.hasTestFilters() )
Catch::cout() << "Tags for matching test cases:\n";
else {
@@ -8676,15 +11383,16 @@ namespace Catch {
return factories.size();
}
- Option<std::size_t> list( Config const& config ) {
+ Option<std::size_t> list( std::shared_ptr<Config> const& config ) {
Option<std::size_t> listedCount;
- if( config.listTests() )
- listedCount = listedCount.valueOr(0) + listTests( config );
- if( config.listTestNamesOnly() )
- listedCount = listedCount.valueOr(0) + listTestsNamesOnly( config );
- if( config.listTags() )
- listedCount = listedCount.valueOr(0) + listTags( config );
- if( config.listReporters() )
+ getCurrentMutableContext().setConfig( config );
+ if( config->listTests() )
+ listedCount = listedCount.valueOr(0) + listTests( *config );
+ if( config->listTestNamesOnly() )
+ listedCount = listedCount.valueOr(0) + listTestsNamesOnly( *config );
+ if( config->listTags() )
+ listedCount = listedCount.valueOr(0) + listTags( *config );
+ if( config->listReporters() )
listedCount = listedCount.valueOr(0) + listReporters();
return listedCount;
}
@@ -8713,6 +11421,29 @@ using Matchers::Impl::MatcherBase;
} // namespace Catch
// end catch_matchers.cpp
+// start catch_matchers_exception.cpp
+
+namespace Catch {
+namespace Matchers {
+namespace Exception {
+
+bool ExceptionMessageMatcher::match(std::exception const& ex) const {
+ return ex.what() == m_message;
+}
+
+std::string ExceptionMessageMatcher::describe() const {
+ return "exception message matches \"" + m_message + "\"";
+}
+
+}
+Exception::ExceptionMessageMatcher Message(std::string const& message) {
+ return Exception::ExceptionMessageMatcher(message);
+}
+
+// namespace Exception
+} // namespace Matchers
+} // namespace Catch
+// end catch_matchers_exception.cpp
// start catch_matchers_floating.cpp
// start catch_polyfills.hpp
@@ -8741,74 +11472,101 @@ namespace Catch {
} // end namespace Catch
// end catch_to_string.hpp
+#include <algorithm>
+#include <cmath>
#include <cstdlib>
#include <cstdint>
#include <cstring>
+#include <sstream>
+#include <type_traits>
+#include <iomanip>
+#include <limits>
namespace Catch {
-namespace Matchers {
-namespace Floating {
-enum class FloatingPointKind : uint8_t {
- Float,
- Double
-};
-}
-}
-}
-
namespace {
-template <typename T>
-struct Converter;
-
-template <>
-struct Converter<float> {
- static_assert(sizeof(float) == sizeof(int32_t), "Important ULP matcher assumption violated");
- Converter(float f) {
+ int32_t convert(float f) {
+ static_assert(sizeof(float) == sizeof(int32_t), "Important ULP matcher assumption violated");
+ int32_t i;
std::memcpy(&i, &f, sizeof(f));
+ return i;
}
- int32_t i;
-};
-template <>
-struct Converter<double> {
- static_assert(sizeof(double) == sizeof(int64_t), "Important ULP matcher assumption violated");
- Converter(double d) {
+ int64_t convert(double d) {
+ static_assert(sizeof(double) == sizeof(int64_t), "Important ULP matcher assumption violated");
+ int64_t i;
std::memcpy(&i, &d, sizeof(d));
+ return i;
}
- int64_t i;
-};
-template <typename T>
-auto convert(T t) -> Converter<T> {
- return Converter<T>(t);
-}
+ template <typename FP>
+ bool almostEqualUlps(FP lhs, FP rhs, uint64_t maxUlpDiff) {
+ // Comparison with NaN should always be false.
+ // This way we can rule it out before getting into the ugly details
+ if (Catch::isnan(lhs) || Catch::isnan(rhs)) {
+ return false;
+ }
-template <typename FP>
-bool almostEqualUlps(FP lhs, FP rhs, int maxUlpDiff) {
- // Comparison with NaN should always be false.
- // This way we can rule it out before getting into the ugly details
- if (Catch::isnan(lhs) || Catch::isnan(rhs)) {
- return false;
+ auto lc = convert(lhs);
+ auto rc = convert(rhs);
+
+ if ((lc < 0) != (rc < 0)) {
+ // Potentially we can have +0 and -0
+ return lhs == rhs;
+ }
+
+ // static cast as a workaround for IBM XLC
+ auto ulpDiff = std::abs(static_cast<FP>(lc - rc));
+ return static_cast<uint64_t>(ulpDiff) <= maxUlpDiff;
}
- auto lc = convert(lhs);
- auto rc = convert(rhs);
+#if defined(CATCH_CONFIG_GLOBAL_NEXTAFTER)
- if ((lc.i < 0) != (rc.i < 0)) {
- // Potentially we can have +0 and -0
- return lhs == rhs;
+ float nextafter(float x, float y) {
+ return ::nextafterf(x, y);
}
- auto ulpDiff = std::abs(lc.i - rc.i);
- return ulpDiff <= maxUlpDiff;
+ double nextafter(double x, double y) {
+ return ::nextafter(x, y);
+ }
+
+#endif // ^^^ CATCH_CONFIG_GLOBAL_NEXTAFTER ^^^
+
+template <typename FP>
+FP step(FP start, FP direction, uint64_t steps) {
+ for (uint64_t i = 0; i < steps; ++i) {
+#if defined(CATCH_CONFIG_GLOBAL_NEXTAFTER)
+ start = Catch::nextafter(start, direction);
+#else
+ start = std::nextafter(start, direction);
+#endif
+ }
+ return start;
}
+// Performs equivalent check of std::fabs(lhs - rhs) <= margin
+// But without the subtraction to allow for INFINITY in comparison
+bool marginComparison(double lhs, double rhs, double margin) {
+ return (lhs + margin >= rhs) && (rhs + margin >= lhs);
}
-namespace Catch {
+template <typename FloatingPoint>
+void write(std::ostream& out, FloatingPoint num) {
+ out << std::scientific
+ << std::setprecision(std::numeric_limits<FloatingPoint>::max_digits10 - 1)
+ << num;
+}
+
+} // end anonymous namespace
+
namespace Matchers {
namespace Floating {
+
+ enum class FloatingPointKind : uint8_t {
+ Float,
+ Double
+ };
+
WithinAbsMatcher::WithinAbsMatcher(double target, double margin)
:m_target{ target }, m_margin{ margin } {
CATCH_ENFORCE(margin >= 0, "Invalid margin: " << margin << '.'
@@ -8825,10 +11583,11 @@ namespace Floating {
return "is within " + ::Catch::Detail::stringify(m_margin) + " of " + ::Catch::Detail::stringify(m_target);
}
- WithinUlpsMatcher::WithinUlpsMatcher(double target, int ulps, FloatingPointKind baseType)
+ WithinUlpsMatcher::WithinUlpsMatcher(double target, uint64_t ulps, FloatingPointKind baseType)
:m_target{ target }, m_ulps{ ulps }, m_type{ baseType } {
- CATCH_ENFORCE(ulps >= 0, "Invalid ULP setting: " << ulps << '.'
- << " ULPs have to be non-negative.");
+ CATCH_ENFORCE(m_type == FloatingPointKind::Double
+ || m_ulps < (std::numeric_limits<uint32_t>::max)(),
+ "Provided ULP is impossibly large for a float comparison.");
}
#if defined(__clang__)
@@ -8853,16 +11612,59 @@ namespace Floating {
#endif
std::string WithinUlpsMatcher::describe() const {
- return "is within " + Catch::to_string(m_ulps) + " ULPs of " + ::Catch::Detail::stringify(m_target) + ((m_type == FloatingPointKind::Float)? "f" : "");
+ std::stringstream ret;
+
+ ret << "is within " << m_ulps << " ULPs of ";
+
+ if (m_type == FloatingPointKind::Float) {
+ write(ret, static_cast<float>(m_target));
+ ret << 'f';
+ } else {
+ write(ret, m_target);
+ }
+
+ ret << " ([";
+ if (m_type == FloatingPointKind::Double) {
+ write(ret, step(m_target, static_cast<double>(-INFINITY), m_ulps));
+ ret << ", ";
+ write(ret, step(m_target, static_cast<double>( INFINITY), m_ulps));
+ } else {
+ // We have to cast INFINITY to float because of MinGW, see #1782
+ write(ret, step(static_cast<float>(m_target), static_cast<float>(-INFINITY), m_ulps));
+ ret << ", ";
+ write(ret, step(static_cast<float>(m_target), static_cast<float>( INFINITY), m_ulps));
+ }
+ ret << "])";
+
+ return ret.str();
+ }
+
+ WithinRelMatcher::WithinRelMatcher(double target, double epsilon):
+ m_target(target),
+ m_epsilon(epsilon){
+ CATCH_ENFORCE(m_epsilon >= 0., "Relative comparison with epsilon < 0 does not make sense.");
+ CATCH_ENFORCE(m_epsilon < 1., "Relative comparison with epsilon >= 1 does not make sense.");
+ }
+
+ bool WithinRelMatcher::match(double const& matchee) const {
+ const auto relMargin = m_epsilon * (std::max)(std::fabs(matchee), std::fabs(m_target));
+ return marginComparison(matchee, m_target,
+ std::isinf(relMargin)? 0 : relMargin);
+ }
+
+ std::string WithinRelMatcher::describe() const {
+ Catch::ReusableStringStream sstr;
+ sstr << "and " << m_target << " are within " << m_epsilon * 100. << "% of each other";
+ return sstr.str();
}
}// namespace Floating
-Floating::WithinUlpsMatcher WithinULP(double target, int maxUlpDiff) {
+Floating::WithinUlpsMatcher WithinULP(double target, uint64_t maxUlpDiff) {
return Floating::WithinUlpsMatcher(target, maxUlpDiff, Floating::FloatingPointKind::Double);
}
-Floating::WithinUlpsMatcher WithinULP(float target, int maxUlpDiff) {
+Floating::WithinUlpsMatcher WithinULP(float target, uint64_t maxUlpDiff) {
return Floating::WithinUlpsMatcher(target, maxUlpDiff, Floating::FloatingPointKind::Float);
}
@@ -8870,9 +11672,24 @@ Floating::WithinAbsMatcher WithinAbs(double target, double margin) {
return Floating::WithinAbsMatcher(target, margin);
}
+Floating::WithinRelMatcher WithinRel(double target, double eps) {
+ return Floating::WithinRelMatcher(target, eps);
+}
+
+Floating::WithinRelMatcher WithinRel(double target) {
+ return Floating::WithinRelMatcher(target, std::numeric_limits<double>::epsilon() * 100);
+}
+
+Floating::WithinRelMatcher WithinRel(float target, float eps) {
+ return Floating::WithinRelMatcher(target, eps);
+}
+
+Floating::WithinRelMatcher WithinRel(float target) {
+ return Floating::WithinRelMatcher(target, std::numeric_limits<float>::epsilon() * 100);
+}
+
} // namespace Matchers
} // namespace Catch
-
// end catch_matchers_floating.cpp
// start catch_matchers_generic.cpp
@@ -9030,28 +11847,43 @@ namespace Catch {
////////////////////////////////////////////////////////////////////////////
ScopedMessage::ScopedMessage( MessageBuilder const& builder )
- : m_info( builder.m_info )
+ : m_info( builder.m_info ), m_moved()
{
m_info.message = builder.m_stream.str();
getResultCapture().pushScopedMessage( m_info );
}
+ ScopedMessage::ScopedMessage( ScopedMessage&& old )
+ : m_info( old.m_info ), m_moved()
+ {
+ old.m_moved = true;
+ }
+
ScopedMessage::~ScopedMessage() {
- if ( !uncaught_exceptions() ){
+ if ( !uncaught_exceptions() && !m_moved ){
getResultCapture().popScopedMessage(m_info);
}
}
Capturer::Capturer( StringRef macroName, SourceLineInfo const& lineInfo, ResultWas::OfType resultType, StringRef names ) {
auto trimmed = [&] (size_t start, size_t end) {
- while (names[start] == ',' || isspace(names[start])) {
+ while (names[start] == ',' || isspace(static_cast<unsigned char>(names[start]))) {
++start;
}
- while (names[end] == ',' || isspace(names[end])) {
+ while (names[end] == ',' || isspace(static_cast<unsigned char>(names[end]))) {
--end;
}
return names.substr(start, end - start + 1);
};
+ auto skipq = [&] (size_t start, char quote) {
+ for (auto i = start + 1; i < names.size() ; ++i) {
+ if (names[i] == quote)
+ return i;
+ if (names[i] == '\\')
+ ++i;
+ }
+ CATCH_INTERNAL_ERROR("CAPTURE parsing encountered unmatched quote");
+ };
size_t start = 0;
std::stack<char> openings;
@@ -9072,18 +11904,22 @@ namespace Catch {
// case '>':
openings.pop();
break;
+ case '"':
+ case '\'':
+ pos = skipq(pos, c);
+ break;
case ',':
- if (start != pos && openings.size() == 0) {
+ if (start != pos && openings.empty()) {
m_messages.emplace_back(macroName, lineInfo, resultType);
- m_messages.back().message = trimmed(start, pos);
+ m_messages.back().message = static_cast<std::string>(trimmed(start, pos));
m_messages.back().message += " := ";
start = pos;
}
}
}
- assert(openings.size() == 0 && "Mismatched openings");
+ assert(openings.empty() && "Mismatched openings");
m_messages.emplace_back(macroName, lineInfo, resultType);
- m_messages.back().message = trimmed(start, names.size() - 1);
+ m_messages.back().message = static_cast<std::string>(trimmed(start, names.size() - 1));
m_messages.back().message += " := ";
}
Capturer::~Capturer() {
@@ -9145,6 +11981,22 @@ namespace Catch {
auto str() const -> std::string;
};
+ class RedirectedStreams {
+ public:
+ RedirectedStreams(RedirectedStreams const&) = delete;
+ RedirectedStreams& operator=(RedirectedStreams const&) = delete;
+ RedirectedStreams(RedirectedStreams&&) = delete;
+ RedirectedStreams& operator=(RedirectedStreams&&) = delete;
+
+ RedirectedStreams(std::string& redirectedCout, std::string& redirectedCerr);
+ ~RedirectedStreams();
+ private:
+ std::string& m_redirectedCout;
+ std::string& m_redirectedCerr;
+ RedirectedStdOut m_redirectedStdOut;
+ RedirectedStdErr m_redirectedStdErr;
+ };
+
#if defined(CATCH_CONFIG_NEW_CAPTURE)
// Windows's implementation of std::tmpfile is terrible (it tries
@@ -9236,6 +12088,16 @@ namespace Catch {
{}
auto RedirectedStdErr::str() const -> std::string { return m_rss.str(); }
+ RedirectedStreams::RedirectedStreams(std::string& redirectedCout, std::string& redirectedCerr)
+ : m_redirectedCout(redirectedCout),
+ m_redirectedCerr(redirectedCerr)
+ {}
+
+ RedirectedStreams::~RedirectedStreams() {
+ m_redirectedCout += m_redirectedStdOut.str();
+ m_redirectedCerr += m_redirectedStdErr.str();
+ }
+
#if defined(CATCH_CONFIG_NEW_CAPTURE)
#if defined(_MSC_VER)
@@ -9243,12 +12105,12 @@ namespace Catch {
if (tmpnam_s(m_buffer)) {
CATCH_RUNTIME_ERROR("Could not get a temp filename");
}
- if (fopen_s(&m_file, m_buffer, "w")) {
+ if (fopen_s(&m_file, m_buffer, "w+")) {
char buffer[100];
if (strerror_s(buffer, errno)) {
CATCH_RUNTIME_ERROR("Could not translate errno to a string");
}
- CATCH_RUNTIME_ERROR("Coul dnot open the temp file: '" << m_buffer << "' because: " << buffer);
+ CATCH_RUNTIME_ERROR("Could not open the temp file: '" << m_buffer << "' because: " << buffer);
}
}
#else
@@ -9351,20 +12213,61 @@ namespace Catch {
namespace Catch {
- std::mt19937& rng() {
- static std::mt19937 s_rng;
- return s_rng;
+namespace {
+
+#if defined(_MSC_VER)
+#pragma warning(push)
+#pragma warning(disable:4146) // we negate uint32 during the rotate
+#endif
+ // Safe rotr implementation thanks to John Regehr
+ uint32_t rotate_right(uint32_t val, uint32_t count) {
+ const uint32_t mask = 31;
+ count &= mask;
+ return (val >> count) | (val << (-count & mask));
+ }
+
+#if defined(_MSC_VER)
+#pragma warning(pop)
+#endif
+
+}
+
+ SimplePcg32::SimplePcg32(result_type seed_) {
+ seed(seed_);
+ }
+
+ void SimplePcg32::seed(result_type seed_) {
+ m_state = 0;
+ (*this)();
+ m_state += seed_;
+ (*this)();
}
- void seedRng( IConfig const& config ) {
- if( config.rngSeed() != 0 ) {
- std::srand( config.rngSeed() );
- rng().seed( config.rngSeed() );
+ void SimplePcg32::discard(uint64_t skip) {
+ // We could implement this to run in O(log n) steps, but this
+ // should suffice for our use case.
+ for (uint64_t s = 0; s < skip; ++s) {
+ static_cast<void>((*this)());
}
}
- unsigned int rngSeed() {
- return getCurrentContext().getConfig()->rngSeed();
+ SimplePcg32::result_type SimplePcg32::operator()() {
+ // prepare the output value
+ const uint32_t xorshifted = static_cast<uint32_t>(((m_state >> 18u) ^ m_state) >> 27u);
+ const auto output = rotate_right(xorshifted, m_state >> 59u);
+
+ // advance state
+ m_state = m_state * 6364136223846793005ULL + s_inc;
+
+ return output;
+ }
+
+ bool operator==(SimplePcg32 const& lhs, SimplePcg32 const& rhs) {
+ return lhs.m_state == rhs.m_state;
+ }
+
+ bool operator!=(SimplePcg32 const& lhs, SimplePcg32 const& rhs) {
+ return lhs.m_state != rhs.m_state;
}
}
// end catch_random_number_generator.cpp
@@ -9383,6 +12286,8 @@ namespace Catch {
struct IConfig;
std::vector<TestCase> sortTests( IConfig const& config, std::vector<TestCase> const& unsortedTestCases );
+
+ bool isThrowSafe( TestCase const& testCase, IConfig const& config );
bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config );
void enforceNoDuplicateTestCases( std::vector<TestCase> const& functions );
@@ -9495,11 +12400,13 @@ namespace Catch {
namespace Catch {
class StartupExceptionRegistry {
+#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
public:
void add(std::exception_ptr const& exception) noexcept;
std::vector<std::exception_ptr> const& getExceptions() const noexcept;
private:
std::vector<std::exception_ptr> m_exceptions;
+#endif
};
} // end namespace Catch
@@ -9582,7 +12489,14 @@ namespace Catch {
m_tagAliasRegistry.add( alias, tag, lineInfo );
}
void registerStartupException() noexcept override {
+#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
m_exceptionRegistry.add(std::current_exception());
+#else
+ CATCH_INTERNAL_ERROR("Attempted to register active exception under CATCH_CONFIG_DISABLE_EXCEPTIONS!");
+#endif
+ }
+ IMutableEnumValuesRegistry& getMutableEnumValuesRegistry() override {
+ return m_enumValuesRegistry;
}
private:
@@ -9591,6 +12505,7 @@ namespace Catch {
ExceptionTranslatorRegistry m_exceptionTranslatorRegistry;
TagAliasRegistry m_tagAliasRegistry;
StartupExceptionRegistry m_exceptionRegistry;
+ Detail::EnumValuesRegistry m_enumValuesRegistry;
};
}
@@ -9671,7 +12586,6 @@ namespace Catch {
namespace Generators {
struct GeneratorTracker : TestCaseTracking::TrackerBase, IGeneratorTracker {
- size_t m_index = static_cast<size_t>( -1 );
GeneratorBasePtr m_generator;
GeneratorTracker( TestCaseTracking::NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent )
@@ -9683,39 +12597,110 @@ namespace Catch {
std::shared_ptr<GeneratorTracker> tracker;
ITracker& currentTracker = ctx.currentTracker();
- if( TestCaseTracking::ITrackerPtr childTracker = currentTracker.findChild( nameAndLocation ) ) {
+ // Under specific circumstances, the generator we want
+ // to acquire is also the current tracker. If this is
+ // the case, we have to avoid looking through current
+ // tracker's children, and instead return the current
+ // tracker.
+ // A case where this check is important is e.g.
+ // for (int i = 0; i < 5; ++i) {
+ // int n = GENERATE(1, 2);
+ // }
+ //
+ // without it, the code above creates 5 nested generators.
+ if (currentTracker.nameAndLocation() == nameAndLocation) {
+ auto thisTracker = currentTracker.parent().findChild(nameAndLocation);
+ assert(thisTracker);
+ assert(thisTracker->isGeneratorTracker());
+ tracker = std::static_pointer_cast<GeneratorTracker>(thisTracker);
+ } else if ( TestCaseTracking::ITrackerPtr childTracker = currentTracker.findChild( nameAndLocation ) ) {
assert( childTracker );
- assert( childTracker->isIndexTracker() );
+ assert( childTracker->isGeneratorTracker() );
tracker = std::static_pointer_cast<GeneratorTracker>( childTracker );
- }
- else {
+ } else {
tracker = std::make_shared<GeneratorTracker>( nameAndLocation, ctx, &currentTracker );
currentTracker.addChild( tracker );
}
- if( !ctx.completedCycle() && !tracker->isComplete() ) {
- if( tracker->m_runState != ExecutingChildren && tracker->m_runState != NeedsAnotherRun )
- tracker->moveNext();
+ if( !tracker->isComplete() ) {
tracker->open();
}
return *tracker;
}
- void moveNext() {
- m_index++;
- m_children.clear();
- }
-
// TrackerBase interface
- bool isIndexTracker() const override { return true; }
+ bool isGeneratorTracker() const override { return true; }
auto hasGenerator() const -> bool override {
return !!m_generator;
}
void close() override {
TrackerBase::close();
- if( m_runState == CompletedSuccessfully && m_index < m_generator->size()-1 )
+ // If a generator has a child (it is followed by a section)
+ // and none of its children have started, then we must wait
+ // until later to start consuming its values.
+ // This catches cases where `GENERATE` is placed between two
+ // `SECTION`s.
+ // **The check for m_children.empty cannot be removed**.
+ // doing so would break `GENERATE` _not_ followed by `SECTION`s.
+ const bool should_wait_for_child = [&]() {
+ // No children -> nobody to wait for
+ if ( m_children.empty() ) {
+ return false;
+ }
+ // If at least one child started executing, don't wait
+ if ( std::find_if(
+ m_children.begin(),
+ m_children.end(),
+ []( TestCaseTracking::ITrackerPtr tracker ) {
+ return tracker->hasStarted();
+ } ) != m_children.end() ) {
+ return false;
+ }
+
+ // No children have started. We need to check if they _can_
+ // start, and thus we should wait for them, or they cannot
+ // start (due to filters), and we shouldn't wait for them
+ auto* parent = m_parent;
+ // This is safe: there is always at least one section
+ // tracker in a test case tracking tree
+ while ( !parent->isSectionTracker() ) {
+ parent = &( parent->parent() );
+ }
+ assert( parent &&
+ "Missing root (test case) level section" );
+
+ auto const& parentSection =
+ static_cast<SectionTracker&>( *parent );
+ auto const& filters = parentSection.getFilters();
+ // No filters -> no restrictions on running sections
+ if ( filters.empty() ) {
+ return true;
+ }
+
+ for ( auto const& child : m_children ) {
+ if ( child->isSectionTracker() &&
+ std::find( filters.begin(),
+ filters.end(),
+ static_cast<SectionTracker&>( *child )
+ .trimmedName() ) !=
+ filters.end() ) {
+ return true;
+ }
+ }
+ return false;
+ }();
+
+ // This check is a bit tricky, because m_generator->next()
+ // has a side-effect, where it consumes generator's current
+ // value, but we do not want to invoke the side-effect if
+ // this generator is still waiting for any child to start.
+ if ( should_wait_for_child ||
+ ( m_runState == CompletedSuccessfully &&
+ m_generator->next() ) ) {
+ m_children.clear();
m_runState = Executing;
+ }
}
// IGeneratorTracker interface
@@ -9725,9 +12710,6 @@ namespace Catch {
void setGenerator( GeneratorBasePtr&& generator ) override {
m_generator = std::move( generator );
}
- auto getIndex() const -> size_t override {
- return m_index;
- }
};
GeneratorTracker::~GeneratorTracker() {}
}
@@ -9825,6 +12807,9 @@ namespace Catch {
// and should be let to clear themselves out.
static_cast<void>(m_reporter->assertionEnded(AssertionStats(result, m_messages, m_totals)));
+ if (result.getResultType() != ResultWas::Warning)
+ m_messageScopes.clear();
+
// Reset working state
resetAssertionInfo();
m_lastResult = result;
@@ -9848,10 +12833,10 @@ namespace Catch {
return true;
}
- auto RunContext::acquireGeneratorTracker( SourceLineInfo const& lineInfo ) -> IGeneratorTracker& {
+ auto RunContext::acquireGeneratorTracker( StringRef generatorName, SourceLineInfo const& lineInfo ) -> IGeneratorTracker& {
using namespace Generators;
- GeneratorTracker& tracker = GeneratorTracker::acquire( m_trackerContext, TestCaseTracking::NameAndLocation( "generator", lineInfo ) );
- assert( tracker.isOpen() );
+ GeneratorTracker& tracker = GeneratorTracker::acquire(m_trackerContext,
+ TestCaseTracking::NameAndLocation( static_cast<std::string>(generatorName), lineInfo ) );
m_lastAssertionInfo.lineInfo = lineInfo;
return tracker;
}
@@ -9879,6 +12864,7 @@ namespace Catch {
m_reporter->sectionEnded(SectionStats(endInfo.sectionInfo, assertions, endInfo.durationInSeconds, missingAssertions));
m_messages.clear();
+ m_messageScopes.clear();
}
void RunContext::sectionEndedEarly(SectionEndInfo const & endInfo) {
@@ -9890,12 +12876,21 @@ namespace Catch {
m_unfinishedSections.push_back(endInfo);
}
+
+#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)
+ void RunContext::benchmarkPreparing(std::string const& name) {
+ m_reporter->benchmarkPreparing(name);
+ }
void RunContext::benchmarkStarting( BenchmarkInfo const& info ) {
m_reporter->benchmarkStarting( info );
}
- void RunContext::benchmarkEnded( BenchmarkStats const& stats ) {
+ void RunContext::benchmarkEnded( BenchmarkStats<> const& stats ) {
m_reporter->benchmarkEnded( stats );
}
+ void RunContext::benchmarkFailed(std::string const & error) {
+ m_reporter->benchmarkFailed(error);
+ }
+#endif // CATCH_CONFIG_ENABLE_BENCHMARKING
void RunContext::pushScopedMessage(MessageInfo const & message) {
m_messages.push_back(message);
@@ -9905,6 +12900,10 @@ namespace Catch {
m_messages.erase(std::remove(m_messages.begin(), m_messages.end(), message), m_messages.end());
}
+ void RunContext::emplaceUnscopedMessage( MessageBuilder const& builder ) {
+ m_messageScopes.emplace_back( builder );
+ }
+
std::string RunContext::getCurrentTestName() const {
return m_activeTestCase
? m_activeTestCase->getTestCaseInfo().name
@@ -9926,7 +12925,7 @@ namespace Catch {
// Don't rebuild the result -- the stringification itself can cause more fatal errors
// Instead, fake a result data.
AssertionResultData tempResult( ResultWas::FatalErrorCondition, { false } );
- tempResult.message = message;
+ tempResult.message = static_cast<std::string>(message);
AssertionResult result(m_lastAssertionInfo, tempResult);
assertionEnded(result);
@@ -9965,6 +12964,7 @@ namespace Catch {
m_lastAssertionPassed = true;
++m_totals.assertions.passed;
resetAssertionInfo();
+ m_messageScopes.clear();
}
bool RunContext::aborting() const {
@@ -9986,13 +12986,10 @@ namespace Catch {
CATCH_TRY {
if (m_reporter->getPreferences().shouldRedirectStdOut) {
#if !defined(CATCH_CONFIG_EXPERIMENTAL_REDIRECT)
- RedirectedStdOut redirectedStdOut;
- RedirectedStdErr redirectedStdErr;
+ RedirectedStreams redirectedStreams(redirectedCout, redirectedCerr);
timer.start();
invokeActiveTestCase();
- redirectedCout += redirectedStdOut.str();
- redirectedCerr += redirectedStdErr.str();
#else
OutputRedirect r(redirectedCout, redirectedCerr);
timer.start();
@@ -10019,15 +13016,15 @@ namespace Catch {
m_testCaseTracker->close();
handleUnfinishedSections();
m_messages.clear();
+ m_messageScopes.clear();
SectionStats testCaseSectionStats(testCaseSection, assertions, duration, missingAssertions);
m_reporter->sectionEnded(testCaseSectionStats);
}
void RunContext::invokeActiveTestCase() {
- FatalConditionHandler fatalConditionHandler; // Handle signals
+ FatalConditionHandlerGuard _(&m_fatalConditionhandler);
m_activeTestCase->invoke();
- fatalConditionHandler.reset();
}
void RunContext::handleUnfinishedSections() {
@@ -10090,7 +13087,7 @@ namespace Catch {
m_lastAssertionInfo = info;
AssertionResultData data( resultType, LazyExpression( false ) );
- data.message = message;
+ data.message = static_cast<std::string>(message);
AssertionResult assertionResult{ m_lastAssertionInfo, data };
assertionEnded( assertionResult );
if( !assertionResult.isOk() )
@@ -10153,6 +13150,18 @@ namespace Catch {
else
CATCH_INTERNAL_ERROR("No result capture instance");
}
+
+ void seedRng(IConfig const& config) {
+ if (config.rngSeed() != 0) {
+ std::srand(config.rngSeed());
+ rng().seed(config.rngSeed());
+ }
+ }
+
+ unsigned int rngSeed() {
+ return getCurrentContext().getConfig()->rngSeed();
+ }
+
}
// end catch_run_context.cpp
// start catch_section.cpp
@@ -10214,7 +13223,7 @@ namespace Catch {
void libIdentify();
int applyCommandLine( int argc, char const * const * argv );
- #if defined(CATCH_CONFIG_WCHAR) && defined(WIN32) && defined(UNICODE)
+ #if defined(CATCH_CONFIG_WCHAR) && defined(_WIN32) && defined(UNICODE)
int applyCommandLine( int argc, wchar_t const * const * argv );
#endif
@@ -10281,6 +13290,8 @@ namespace Catch {
// end catch_version.h
#include <cstdlib>
#include <iomanip>
+#include <set>
+#include <iterator>
namespace Catch {
@@ -10299,52 +13310,76 @@ namespace Catch {
return createReporter(config->getReporterName(), config);
}
- auto multi = std::unique_ptr<ListeningReporter>(new ListeningReporter);
-
+ // On older platforms, returning std::unique_ptr<ListeningReporter>
+ // when the return type is std::unique_ptr<IStreamingReporter>
+ // doesn't compile without a std::move call. However, this causes
+ // a warning on newer platforms. Thus, we have to work around
+ // it a bit and downcast the pointer manually.
+ auto ret = std::unique_ptr<IStreamingReporter>(new ListeningReporter);
+ auto& multi = static_cast<ListeningReporter&>(*ret);
auto const& listeners = Catch::getRegistryHub().getReporterRegistry().getListeners();
for (auto const& listener : listeners) {
- multi->addListener(listener->create(Catch::ReporterConfig(config)));
+ multi.addListener(listener->create(Catch::ReporterConfig(config)));
}
- multi->addReporter(createReporter(config->getReporterName(), config));
- return std::move(multi);
+ multi.addReporter(createReporter(config->getReporterName(), config));
+ return ret;
}
- Catch::Totals runTests(std::shared_ptr<Config> const& config) {
- auto reporter = makeReporter(config);
-
- RunContext context(config, std::move(reporter));
-
- Totals totals;
-
- context.testGroupStarting(config->name(), 1, 1);
-
- TestSpec testSpec = config->testSpec();
-
- auto const& allTestCases = getAllTestCasesSorted(*config);
- for (auto const& testCase : allTestCases) {
- if (!context.aborting() && matchTest(testCase, testSpec, *config))
- totals += context.runTest(testCase);
- else
- context.reporter().skipTest(testCase);
+ class TestGroup {
+ public:
+ explicit TestGroup(std::shared_ptr<Config> const& config)
+ : m_config{config}
+ , m_context{config, makeReporter(config)}
+ {
+ auto const& allTestCases = getAllTestCasesSorted(*m_config);
+ m_matches = m_config->testSpec().matchesByFilter(allTestCases, *m_config);
+ auto const& invalidArgs = m_config->testSpec().getInvalidArgs();
+
+ if (m_matches.empty() && invalidArgs.empty()) {
+ for (auto const& test : allTestCases)
+ if (!test.isHidden())
+ m_tests.emplace(&test);
+ } else {
+ for (auto const& match : m_matches)
+ m_tests.insert(match.tests.begin(), match.tests.end());
+ }
}
- if (config->warnAboutNoTests() && totals.testCases.total() == 0) {
- ReusableStringStream testConfig;
+ Totals execute() {
+ auto const& invalidArgs = m_config->testSpec().getInvalidArgs();
+ Totals totals;
+ m_context.testGroupStarting(m_config->name(), 1, 1);
+ for (auto const& testCase : m_tests) {
+ if (!m_context.aborting())
+ totals += m_context.runTest(*testCase);
+ else
+ m_context.reporter().skipTest(*testCase);
+ }
+
+ for (auto const& match : m_matches) {
+ if (match.tests.empty()) {
+ m_context.reporter().noMatchingTestCases(match.name);
+ totals.error = -1;
+ }
+ }
- bool first = true;
- for (const auto& input : config->getTestsOrTags()) {
- if (!first) { testConfig << ' '; }
- first = false;
- testConfig << input;
+ if (!invalidArgs.empty()) {
+ for (auto const& invalidArg: invalidArgs)
+ m_context.reporter().reportInvalidArguments(invalidArg);
}
- context.reporter().noMatchingTestCases(testConfig.str());
- totals.error = -1;
+ m_context.testGroupEnded(m_config->name(), totals, 1, 1);
+ return totals;
}
- context.testGroupEnded(config->name(), totals, 1, 1);
- return totals;
- }
+ private:
+ using Tests = std::set<TestCase const*>;
+
+ std::shared_ptr<Config> m_config;
+ RunContext m_context;
+ Tests m_tests;
+ TestSpec::Matches m_matches;
+ };
void applyFilenamesAsTags(Catch::IConfig const& config) {
auto& tests = const_cast<std::vector<TestCase>&>(getAllTestCasesSorted(config));
@@ -10381,6 +13416,9 @@ namespace Catch {
#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
const auto& exceptions = getRegistryHub().getStartupExceptionRegistry().getExceptions();
if ( !exceptions.empty() ) {
+ config();
+ getCurrentMutableContext().setConfig(m_config);
+
m_startupExceptions = true;
Colour colourGuard( Colour::Red );
Catch::cerr() << "Errors occurred during startup!" << '\n';
@@ -10410,7 +13448,7 @@ namespace Catch {
}
void Session::libIdentify() {
Catch::cout()
- << std::left << std::setw(16) << "description: " << "A Catch test executable\n"
+ << std::left << std::setw(16) << "description: " << "A Catch2 test executable\n"
<< std::left << std::setw(16) << "category: " << "testframework\n"
<< std::left << std::setw(16) << "framework: " << "Catch Test\n"
<< std::left << std::setw(16) << "version: " << libraryVersion() << std::endl;
@@ -10422,6 +13460,8 @@ namespace Catch {
auto result = m_cli.parse( clara::Args( argc, argv ) );
if( !result ) {
+ config();
+ getCurrentMutableContext().setConfig(m_config);
Catch::cerr()
<< Colour( Colour::Red )
<< "\nError(s) in input:\n"
@@ -10439,17 +13479,17 @@ namespace Catch {
return 0;
}
-#if defined(CATCH_CONFIG_WCHAR) && defined(WIN32) && defined(UNICODE)
+#if defined(CATCH_CONFIG_WCHAR) && defined(_WIN32) && defined(UNICODE)
int Session::applyCommandLine( int argc, wchar_t const * const * argv ) {
char **utf8Argv = new char *[ argc ];
for ( int i = 0; i < argc; ++i ) {
- int bufSize = WideCharToMultiByte( CP_UTF8, 0, argv[i], -1, NULL, 0, NULL, NULL );
+ int bufSize = WideCharToMultiByte( CP_UTF8, 0, argv[i], -1, nullptr, 0, nullptr, nullptr );
utf8Argv[ i ] = new char[ bufSize ];
- WideCharToMultiByte( CP_UTF8, 0, argv[i], -1, utf8Argv[i], bufSize, NULL, NULL );
+ WideCharToMultiByte( CP_UTF8, 0, argv[i], -1, utf8Argv[i], bufSize, nullptr, nullptr );
}
int returnCode = applyCommandLine( argc, utf8Argv );
@@ -10513,10 +13553,15 @@ namespace Catch {
applyFilenamesAsTags( *m_config );
// Handle list request
- if( Option<std::size_t> listed = list( config() ) )
+ if( Option<std::size_t> listed = list( m_config ) )
return static_cast<int>( *listed );
- auto totals = runTests( m_config );
+ TestGroup tests { m_config };
+ auto const totals = tests.execute();
+
+ if( m_config->warnAboutNoTests() && totals.error == -1 )
+ return 2;
+
// Note that on unices only the lower 8 bits are usually used, clamping
// the return value to 255 prevents false negative when some multiple
// of 256 tests has failed
@@ -10564,6 +13609,7 @@ namespace Catch {
// end catch_singletons.cpp
// start catch_startup_exception_registry.cpp
+#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
namespace Catch {
void StartupExceptionRegistry::add( std::exception_ptr const& exception ) noexcept {
CATCH_TRY {
@@ -10579,6 +13625,7 @@ void StartupExceptionRegistry::add( std::exception_ptr const& exception ) noexce
}
} // end namespace Catch
+#endif
// end catch_startup_exception_registry.cpp
// start catch_stream.cpp
@@ -10593,7 +13640,7 @@ namespace Catch {
Catch::IStream::~IStream() = default;
- namespace detail { namespace {
+ namespace Detail { namespace {
template<typename WriterF, std::size_t bufferSize=256>
class StreamBufImpl : public std::streambuf {
char data[bufferSize];
@@ -10692,15 +13739,15 @@ namespace Catch {
auto makeStream( StringRef const &filename ) -> IStream const* {
if( filename.empty() )
- return new detail::CoutStream();
+ return new Detail::CoutStream();
else if( filename[0] == '%' ) {
if( filename == "%debug" )
- return new detail::DebugOutStream();
+ return new Detail::DebugOutStream();
else
CATCH_ERROR( "Unrecognised stream: '" << filename << "'" );
}
else
- return new detail::FileStream( filename );
+ return new Detail::FileStream( filename );
}
// This class encapsulates the idea of a pool of ostringstreams that can be reused.
@@ -10757,12 +13804,13 @@ namespace Catch {
#include <ostream>
#include <cstring>
#include <cctype>
+#include <vector>
namespace Catch {
namespace {
char toLowerCh(char c) {
- return static_cast<char>( std::tolower( c ) );
+ return static_cast<char>( std::tolower( static_cast<unsigned char>(c) ) );
}
}
@@ -10797,6 +13845,18 @@ namespace Catch {
return start != std::string::npos ? str.substr( start, 1+end-start ) : std::string();
}
+ StringRef trim(StringRef ref) {
+ const auto is_ws = [](char c) {
+ return c == ' ' || c == '\t' || c == '\n' || c == '\r';
+ };
+ size_t real_begin = 0;
+ while (real_begin < ref.size() && is_ws(ref[real_begin])) { ++real_begin; }
+ size_t real_end = ref.size();
+ while (real_end > real_begin && is_ws(ref[real_end - 1])) { --real_end; }
+
+ return ref.substr(real_begin, real_end - real_begin);
+ }
+
bool replaceInPlace( std::string& str, std::string const& replaceThis, std::string const& withThis ) {
bool replaced = false;
std::size_t i = str.find( replaceThis );
@@ -10811,6 +13871,21 @@ namespace Catch {
return replaced;
}
+ std::vector<StringRef> splitStringRef( StringRef str, char delimiter ) {
+ std::vector<StringRef> subStrings;
+ std::size_t start = 0;
+ for(std::size_t pos = 0; pos < str.size(); ++pos ) {
+ if( str[pos] == delimiter ) {
+ if( pos - start > 1 )
+ subStrings.push_back( str.substr( start, pos-start ) );
+ start = pos+1;
+ }
+ }
+ if( start < str.size() )
+ subStrings.push_back( str.substr( start, str.size()-start ) );
+ return subStrings;
+ }
+
pluralise::pluralise( std::size_t count, std::string const& label )
: m_count( count ),
m_label( label )
@@ -10827,123 +13902,46 @@ namespace Catch {
// end catch_string_manip.cpp
// start catch_stringref.cpp
-#if defined(__clang__)
-# pragma clang diagnostic push
-# pragma clang diagnostic ignored "-Wexit-time-destructors"
-#endif
-
+#include <algorithm>
#include <ostream>
#include <cstring>
#include <cstdint>
-namespace {
- const uint32_t byte_2_lead = 0xC0;
- const uint32_t byte_3_lead = 0xE0;
- const uint32_t byte_4_lead = 0xF0;
-}
-
namespace Catch {
StringRef::StringRef( char const* rawChars ) noexcept
: StringRef( rawChars, static_cast<StringRef::size_type>(std::strlen(rawChars) ) )
{}
- StringRef::operator std::string() const {
- return std::string( m_start, m_size );
- }
-
- void StringRef::swap( StringRef& other ) noexcept {
- std::swap( m_start, other.m_start );
- std::swap( m_size, other.m_size );
- std::swap( m_data, other.m_data );
- }
-
auto StringRef::c_str() const -> char const* {
- if( isSubstring() )
- const_cast<StringRef*>( this )->takeOwnership();
+ CATCH_ENFORCE(isNullTerminated(), "Called StringRef::c_str() on a non-null-terminated instance");
return m_start;
}
- auto StringRef::currentData() const noexcept -> char const* {
+ auto StringRef::data() const noexcept -> char const* {
return m_start;
}
- auto StringRef::isOwned() const noexcept -> bool {
- return m_data != nullptr;
- }
- auto StringRef::isSubstring() const noexcept -> bool {
- return m_start[m_size] != '\0';
- }
-
- void StringRef::takeOwnership() {
- if( !isOwned() ) {
- m_data = new char[m_size+1];
- memcpy( m_data, m_start, m_size );
- m_data[m_size] = '\0';
- m_start = m_data;
- }
- }
auto StringRef::substr( size_type start, size_type size ) const noexcept -> StringRef {
- if( start < m_size )
- return StringRef( m_start+start, size );
- else
+ if (start < m_size) {
+ return StringRef(m_start + start, (std::min)(m_size - start, size));
+ } else {
return StringRef();
- }
- auto StringRef::operator == ( StringRef const& other ) const noexcept -> bool {
- return
- size() == other.size() &&
- (std::strncmp( m_start, other.m_start, size() ) == 0);
- }
- auto StringRef::operator != ( StringRef const& other ) const noexcept -> bool {
- return !operator==( other );
- }
-
- auto StringRef::operator[](size_type index) const noexcept -> char {
- return m_start[index];
- }
-
- auto StringRef::numberOfCharacters() const noexcept -> size_type {
- size_type noChars = m_size;
- // Make adjustments for uft encodings
- for( size_type i=0; i < m_size; ++i ) {
- char c = m_start[i];
- if( ( c & byte_2_lead ) == byte_2_lead ) {
- noChars--;
- if (( c & byte_3_lead ) == byte_3_lead )
- noChars--;
- if( ( c & byte_4_lead ) == byte_4_lead )
- noChars--;
- }
}
- return noChars;
- }
-
- auto operator + ( StringRef const& lhs, StringRef const& rhs ) -> std::string {
- std::string str;
- str.reserve( lhs.size() + rhs.size() );
- str += lhs;
- str += rhs;
- return str;
}
- auto operator + ( StringRef const& lhs, const char* rhs ) -> std::string {
- return std::string( lhs ) + std::string( rhs );
- }
- auto operator + ( char const* lhs, StringRef const& rhs ) -> std::string {
- return std::string( lhs ) + std::string( rhs );
+ auto StringRef::operator == ( StringRef const& other ) const noexcept -> bool {
+ return m_size == other.m_size
+ && (std::memcmp( m_start, other.m_start, m_size ) == 0);
}
auto operator << ( std::ostream& os, StringRef const& str ) -> std::ostream& {
- return os.write(str.currentData(), str.size());
+ return os.write(str.data(), str.size());
}
auto operator+=( std::string& lhs, StringRef const& rhs ) -> std::string& {
- lhs.append(rhs.currentData(), rhs.size());
+ lhs.append(rhs.data(), rhs.size());
return lhs;
}
} // namespace Catch
-
-#if defined(__clang__)
-# pragma clang diagnostic pop
-#endif
// end catch_stringref.cpp
// start catch_tag_alias.cpp
@@ -11046,7 +14044,7 @@ namespace Catch {
void enforceNotReservedTag( std::string const& tag, SourceLineInfo const& _lineInfo ) {
CATCH_ENFORCE( !isReservedTag(tag),
"Tag name: [" << tag << "] is not allowed.\n"
- << "Tag names starting with non alpha-numeric characters are reserved\n"
+ << "Tag names starting with non alphanumeric characters are reserved\n"
<< _lineInfo );
}
}
@@ -11062,8 +14060,7 @@ namespace Catch {
std::vector<std::string> tags;
std::string desc, tag;
bool inTag = false;
- std::string _descOrTags = nameAndTags.tags;
- for (char c : _descOrTags) {
+ for (char c : nameAndTags.tags) {
if( !inTag ) {
if( c == '[' )
inTag = true;
@@ -11078,6 +14075,12 @@ namespace Catch {
else if( prop == TestCaseInfo::None )
enforceNotReservedTag( tag, _lineInfo );
+ // Merged hide tags like `[.approvals]` should be added as
+ // `[.][approvals]`. The `[.]` is added at later point, so
+ // we only strip the prefix
+ if (startsWith(tag, '.') && tag.size() > 1) {
+ tag.erase(0, 1);
+ }
tags.push_back( tag );
tag.clear();
inTag = false;
@@ -11087,10 +14090,11 @@ namespace Catch {
}
}
if( isHidden ) {
- tags.push_back( "." );
+ // Add all "hidden" tags to make them behave identically
+ tags.insert( tags.end(), { ".", "!hide" } );
}
- TestCaseInfo info( nameAndTags.name, _className, desc, tags, _lineInfo );
+ TestCaseInfo info( static_cast<std::string>(nameAndTags.name), _className, desc, tags, _lineInfo );
return TestCase( _testCase, std::move(info) );
}
@@ -11182,30 +14186,89 @@ namespace Catch {
// end catch_test_case_info.cpp
// start catch_test_case_registry_impl.cpp
+#include <algorithm>
#include <sstream>
namespace Catch {
- std::vector<TestCase> sortTests( IConfig const& config, std::vector<TestCase> const& unsortedTestCases ) {
+ namespace {
+ struct TestHasher {
+ using hash_t = uint64_t;
+
+ explicit TestHasher( hash_t hashSuffix ):
+ m_hashSuffix{ hashSuffix } {}
+
+ uint32_t operator()( TestCase const& t ) const {
+ // FNV-1a hash with multiplication fold.
+ const hash_t prime = 1099511628211u;
+ hash_t hash = 14695981039346656037u;
+ for ( const char c : t.name ) {
+ hash ^= c;
+ hash *= prime;
+ }
+ hash ^= m_hashSuffix;
+ hash *= prime;
+ const uint32_t low{ static_cast<uint32_t>( hash ) };
+ const uint32_t high{ static_cast<uint32_t>( hash >> 32 ) };
+ return low * high;
+ }
- std::vector<TestCase> sorted = unsortedTestCases;
+ private:
+ hash_t m_hashSuffix;
+ };
+ } // end unnamed namespace
+ std::vector<TestCase> sortTests( IConfig const& config, std::vector<TestCase> const& unsortedTestCases ) {
switch( config.runOrder() ) {
- case RunTests::InLexicographicalOrder:
- std::sort( sorted.begin(), sorted.end() );
- break;
- case RunTests::InRandomOrder:
- seedRng( config );
- std::shuffle( sorted.begin(), sorted.end(), rng() );
- break;
case RunTests::InDeclarationOrder:
// already in declaration order
break;
+
+ case RunTests::InLexicographicalOrder: {
+ std::vector<TestCase> sorted = unsortedTestCases;
+ std::sort( sorted.begin(), sorted.end() );
+ return sorted;
+ }
+
+ case RunTests::InRandomOrder: {
+ seedRng( config );
+ TestHasher h{ config.rngSeed() };
+
+ using hashedTest = std::pair<TestHasher::hash_t, TestCase const*>;
+ std::vector<hashedTest> indexed_tests;
+ indexed_tests.reserve( unsortedTestCases.size() );
+
+ for (auto const& testCase : unsortedTestCases) {
+ indexed_tests.emplace_back(h(testCase), &testCase);
+ }
+
+ std::sort(indexed_tests.begin(), indexed_tests.end(),
+ [](hashedTest const& lhs, hashedTest const& rhs) {
+ if (lhs.first == rhs.first) {
+ return lhs.second->name < rhs.second->name;
+ }
+ return lhs.first < rhs.first;
+ });
+
+ std::vector<TestCase> sorted;
+ sorted.reserve( indexed_tests.size() );
+
+ for (auto const& hashed : indexed_tests) {
+ sorted.emplace_back(*hashed.second);
+ }
+
+ return sorted;
+ }
}
- return sorted;
+ return unsortedTestCases;
+ }
+
+ bool isThrowSafe( TestCase const& testCase, IConfig const& config ) {
+ return !testCase.throws() || config.allowThrows();
}
+
bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config ) {
- return testSpec.matches( testCase ) && ( config.allowThrows() || !testCase.throws() );
+ return testSpec.matches( testCase ) && isThrowSafe( testCase, config );
}
void enforceNoDuplicateTestCases( std::vector<TestCase> const& functions ) {
@@ -11222,9 +14285,12 @@ namespace Catch {
std::vector<TestCase> filterTests( std::vector<TestCase> const& testCases, TestSpec const& testSpec, IConfig const& config ) {
std::vector<TestCase> filtered;
filtered.reserve( testCases.size() );
- for( auto const& testCase : testCases )
- if( matchTest( testCase, testSpec, config ) )
- filtered.push_back( testCase );
+ for (auto const& testCase : testCases) {
+ if ((!testSpec.hasFilters() && !testCase.isHidden()) ||
+ (testSpec.hasFilters() && matchTest(testCase, testSpec, config))) {
+ filtered.push_back(testCase);
+ }
+ }
return filtered;
}
std::vector<TestCase> const& getAllTestCasesSorted( IConfig const& config ) {
@@ -11263,7 +14329,7 @@ namespace Catch {
}
std::string extractClassName( StringRef const& classOrQualifiedMethodName ) {
- std::string className = classOrQualifiedMethodName;
+ std::string className(classOrQualifiedMethodName);
if( startsWith( className, '&' ) )
{
std::size_t lastColons = className.rfind( "::" );
@@ -11300,11 +14366,6 @@ namespace TestCaseTracking {
ITracker::~ITracker() = default;
- TrackerContext& TrackerContext::instance() {
- static TrackerContext s_instance;
- return s_instance;
- }
-
ITracker& TrackerContext::startRun() {
m_rootTracker = std::make_shared<SectionTracker>( NameAndLocation( "{root}", CATCH_INTERNAL_LINEINFO ), *this, nullptr );
m_currentTracker = nullptr;
@@ -11336,15 +14397,12 @@ namespace TestCaseTracking {
m_currentTracker = tracker;
}
- TrackerBase::TrackerBase( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent )
- : m_nameAndLocation( nameAndLocation ),
+ TrackerBase::TrackerBase( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent ):
+ ITracker(nameAndLocation),
m_ctx( ctx ),
m_parent( parent )
{}
- NameAndLocation const& TrackerBase::nameAndLocation() const {
- return m_nameAndLocation;
- }
bool TrackerBase::isComplete() const {
return m_runState == CompletedSuccessfully || m_runState == Failed;
}
@@ -11387,7 +14445,7 @@ namespace TestCaseTracking {
}
bool TrackerBase::isSectionTracker() const { return false; }
- bool TrackerBase::isIndexTracker() const { return false; }
+ bool TrackerBase::isGeneratorTracker() const { return false; }
void TrackerBase::open() {
m_runState = Executing;
@@ -11410,7 +14468,7 @@ namespace TestCaseTracking {
m_runState = CompletedSuccessfully;
break;
case ExecutingChildren:
- if( m_children.empty() || m_children.back()->isComplete() )
+ if( std::all_of(m_children.begin(), m_children.end(), [](ITrackerPtr const& t){ return t->isComplete(); }) )
m_runState = CompletedSuccessfully;
break;
@@ -11445,7 +14503,8 @@ namespace TestCaseTracking {
}
SectionTracker::SectionTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent )
- : TrackerBase( nameAndLocation, ctx, parent )
+ : TrackerBase( nameAndLocation, ctx, parent ),
+ m_trimmed_name(trim(nameAndLocation.name))
{
if( parent ) {
while( !parent->isSectionTracker() )
@@ -11456,6 +14515,17 @@ namespace TestCaseTracking {
}
}
+ bool SectionTracker::isComplete() const {
+ bool complete = true;
+
+ if (m_filters.empty()
+ || m_filters[0] == ""
+ || std::find(m_filters.begin(), m_filters.end(), m_trimmed_name) != m_filters.end()) {
+ complete = TrackerBase::isComplete();
+ }
+ return complete;
+ }
+
bool SectionTracker::isSectionTracker() const { return true; }
SectionTracker& SectionTracker::acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation ) {
@@ -11477,63 +14547,29 @@ namespace TestCaseTracking {
}
void SectionTracker::tryOpen() {
- if( !isComplete() && (m_filters.empty() || m_filters[0].empty() || m_filters[0] == m_nameAndLocation.name ) )
+ if( !isComplete() )
open();
}
void SectionTracker::addInitialFilters( std::vector<std::string> const& filters ) {
if( !filters.empty() ) {
- m_filters.push_back(""); // Root - should never be consulted
- m_filters.push_back(""); // Test Case - not a section filter
+ m_filters.reserve( m_filters.size() + filters.size() + 2 );
+ m_filters.emplace_back(""); // Root - should never be consulted
+ m_filters.emplace_back(""); // Test Case - not a section filter
m_filters.insert( m_filters.end(), filters.begin(), filters.end() );
}
}
void SectionTracker::addNextFilters( std::vector<std::string> const& filters ) {
if( filters.size() > 1 )
- m_filters.insert( m_filters.end(), ++filters.begin(), filters.end() );
+ m_filters.insert( m_filters.end(), filters.begin()+1, filters.end() );
}
- IndexTracker::IndexTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent, int size )
- : TrackerBase( nameAndLocation, ctx, parent ),
- m_size( size )
- {}
-
- bool IndexTracker::isIndexTracker() const { return true; }
-
- IndexTracker& IndexTracker::acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation, int size ) {
- std::shared_ptr<IndexTracker> tracker;
-
- ITracker& currentTracker = ctx.currentTracker();
- if( ITrackerPtr childTracker = currentTracker.findChild( nameAndLocation ) ) {
- assert( childTracker );
- assert( childTracker->isIndexTracker() );
- tracker = std::static_pointer_cast<IndexTracker>( childTracker );
- }
- else {
- tracker = std::make_shared<IndexTracker>( nameAndLocation, ctx, &currentTracker, size );
- currentTracker.addChild( tracker );
- }
-
- if( !ctx.completedCycle() && !tracker->isComplete() ) {
- if( tracker->m_runState != ExecutingChildren && tracker->m_runState != NeedsAnotherRun )
- tracker->moveNext();
- tracker->open();
- }
-
- return *tracker;
+ std::vector<std::string> const& SectionTracker::getFilters() const {
+ return m_filters;
}
- int IndexTracker::index() const { return m_index; }
-
- void IndexTracker::moveNext() {
- m_index++;
- m_children.clear();
- }
-
- void IndexTracker::close() {
- TrackerBase::close();
- if( m_runState == CompletedSuccessfully && m_index < m_size-1 )
- m_runState = Executing;
+ std::string const& SectionTracker::trimmedName() const {
+ return m_trimmed_name;
}
} // namespace TestCaseTracking
@@ -11541,7 +14577,6 @@ namespace TestCaseTracking {
using TestCaseTracking::ITracker;
using TestCaseTracking::TrackerContext;
using TestCaseTracking::SectionTracker;
-using TestCaseTracking::IndexTracker;
} // namespace Catch
@@ -11586,47 +14621,81 @@ namespace Catch {
namespace Catch {
+ TestSpec::Pattern::Pattern( std::string const& name )
+ : m_name( name )
+ {}
+
TestSpec::Pattern::~Pattern() = default;
- TestSpec::NamePattern::~NamePattern() = default;
- TestSpec::TagPattern::~TagPattern() = default;
- TestSpec::ExcludedPattern::~ExcludedPattern() = default;
- TestSpec::NamePattern::NamePattern( std::string const& name )
- : m_wildcardPattern( toLower( name ), CaseSensitive::No )
+ std::string const& TestSpec::Pattern::name() const {
+ return m_name;
+ }
+
+ TestSpec::NamePattern::NamePattern( std::string const& name, std::string const& filterString )
+ : Pattern( filterString )
+ , m_wildcardPattern( toLower( name ), CaseSensitive::No )
{}
+
bool TestSpec::NamePattern::matches( TestCaseInfo const& testCase ) const {
- return m_wildcardPattern.matches( toLower( testCase.name ) );
+ return m_wildcardPattern.matches( testCase.name );
}
- TestSpec::TagPattern::TagPattern( std::string const& tag ) : m_tag( toLower( tag ) ) {}
+ TestSpec::TagPattern::TagPattern( std::string const& tag, std::string const& filterString )
+ : Pattern( filterString )
+ , m_tag( toLower( tag ) )
+ {}
+
bool TestSpec::TagPattern::matches( TestCaseInfo const& testCase ) const {
return std::find(begin(testCase.lcaseTags),
end(testCase.lcaseTags),
m_tag) != end(testCase.lcaseTags);
}
- TestSpec::ExcludedPattern::ExcludedPattern( PatternPtr const& underlyingPattern ) : m_underlyingPattern( underlyingPattern ) {}
- bool TestSpec::ExcludedPattern::matches( TestCaseInfo const& testCase ) const { return !m_underlyingPattern->matches( testCase ); }
+ TestSpec::ExcludedPattern::ExcludedPattern( PatternPtr const& underlyingPattern )
+ : Pattern( underlyingPattern->name() )
+ , m_underlyingPattern( underlyingPattern )
+ {}
+
+ bool TestSpec::ExcludedPattern::matches( TestCaseInfo const& testCase ) const {
+ return !m_underlyingPattern->matches( testCase );
+ }
bool TestSpec::Filter::matches( TestCaseInfo const& testCase ) const {
- // All patterns in a filter must match for the filter to be a match
- for( auto const& pattern : m_patterns ) {
- if( !pattern->matches( testCase ) )
- return false;
- }
- return true;
+ return std::all_of( m_patterns.begin(), m_patterns.end(), [&]( PatternPtr const& p ){ return p->matches( testCase ); } );
+ }
+
+ std::string TestSpec::Filter::name() const {
+ std::string name;
+ for( auto const& p : m_patterns )
+ name += p->name();
+ return name;
}
bool TestSpec::hasFilters() const {
return !m_filters.empty();
}
+
bool TestSpec::matches( TestCaseInfo const& testCase ) const {
- // A TestSpec matches if any filter matches
- for( auto const& filter : m_filters )
- if( filter.matches( testCase ) )
- return true;
- return false;
+ return std::any_of( m_filters.begin(), m_filters.end(), [&]( Filter const& f ){ return f.matches( testCase ); } );
}
+
+ TestSpec::Matches TestSpec::matchesByFilter( std::vector<TestCase> const& testCases, IConfig const& config ) const
+ {
+ Matches matches( m_filters.size() );
+ std::transform( m_filters.begin(), m_filters.end(), matches.begin(), [&]( Filter const& filter ){
+ std::vector<TestCase const*> currentMatches;
+ for( auto const& test : testCases )
+ if( isThrowSafe( test, config ) && filter.matches( test ) )
+ currentMatches.emplace_back( &test );
+ return FilterMatch{ filter.name(), currentMatches };
+ } );
+ return matches;
+ }
+
+ const TestSpec::vectorStrings& TestSpec::getInvalidArgs() const{
+ return (m_invalidArgs);
+ }
+
}
// end catch_test_spec.cpp
// start catch_test_spec_parser.cpp
@@ -11638,64 +14707,136 @@ namespace Catch {
TestSpecParser& TestSpecParser::parse( std::string const& arg ) {
m_mode = None;
m_exclusion = false;
- m_start = std::string::npos;
m_arg = m_tagAliases->expandAliases( arg );
m_escapeChars.clear();
+ m_substring.reserve(m_arg.size());
+ m_patternName.reserve(m_arg.size());
+ m_realPatternPos = 0;
+
for( m_pos = 0; m_pos < m_arg.size(); ++m_pos )
- visitChar( m_arg[m_pos] );
- if( m_mode == Name )
- addPattern<TestSpec::NamePattern>();
+ //if visitChar fails
+ if( !visitChar( m_arg[m_pos] ) ){
+ m_testSpec.m_invalidArgs.push_back(arg);
+ break;
+ }
+ endMode();
return *this;
}
TestSpec TestSpecParser::testSpec() {
addFilter();
return m_testSpec;
}
+ bool TestSpecParser::visitChar( char c ) {
+ if( (m_mode != EscapedName) && (c == '\\') ) {
+ escape();
+ addCharToPattern(c);
+ return true;
+ }else if((m_mode != EscapedName) && (c == ',') ) {
+ return separate();
+ }
- void TestSpecParser::visitChar( char c ) {
- if( m_mode == None ) {
- switch( c ) {
- case ' ': return;
- case '~': m_exclusion = true; return;
- case '[': return startNewMode( Tag, ++m_pos );
- case '"': return startNewMode( QuotedName, ++m_pos );
- case '\\': return escape();
- default: startNewMode( Name, m_pos ); break;
- }
+ switch( m_mode ) {
+ case None:
+ if( processNoneChar( c ) )
+ return true;
+ break;
+ case Name:
+ processNameChar( c );
+ break;
+ case EscapedName:
+ endMode();
+ addCharToPattern(c);
+ return true;
+ default:
+ case Tag:
+ case QuotedName:
+ if( processOtherChar( c ) )
+ return true;
+ break;
}
- if( m_mode == Name ) {
- if( c == ',' ) {
- addPattern<TestSpec::NamePattern>();
- addFilter();
- }
- else if( c == '[' ) {
- if( subString() == "exclude:" )
- m_exclusion = true;
- else
- addPattern<TestSpec::NamePattern>();
- startNewMode( Tag, ++m_pos );
- }
- else if( c == '\\' )
- escape();
+
+ m_substring += c;
+ if( !isControlChar( c ) ) {
+ m_patternName += c;
+ m_realPatternPos++;
}
- else if( m_mode == EscapedName )
- m_mode = Name;
- else if( m_mode == QuotedName && c == '"' )
- addPattern<TestSpec::NamePattern>();
- else if( m_mode == Tag && c == ']' )
- addPattern<TestSpec::TagPattern>();
+ return true;
+ }
+ // Two of the processing methods return true to signal the caller to return
+ // without adding the given character to the current pattern strings
+ bool TestSpecParser::processNoneChar( char c ) {
+ switch( c ) {
+ case ' ':
+ return true;
+ case '~':
+ m_exclusion = true;
+ return false;
+ case '[':
+ startNewMode( Tag );
+ return false;
+ case '"':
+ startNewMode( QuotedName );
+ return false;
+ default:
+ startNewMode( Name );
+ return false;
+ }
+ }
+ void TestSpecParser::processNameChar( char c ) {
+ if( c == '[' ) {
+ if( m_substring == "exclude:" )
+ m_exclusion = true;
+ else
+ endMode();
+ startNewMode( Tag );
+ }
+ }
+ bool TestSpecParser::processOtherChar( char c ) {
+ if( !isControlChar( c ) )
+ return false;
+ m_substring += c;
+ endMode();
+ return true;
}
- void TestSpecParser::startNewMode( Mode mode, std::size_t start ) {
+ void TestSpecParser::startNewMode( Mode mode ) {
m_mode = mode;
- m_start = start;
+ }
+ void TestSpecParser::endMode() {
+ switch( m_mode ) {
+ case Name:
+ case QuotedName:
+ return addNamePattern();
+ case Tag:
+ return addTagPattern();
+ case EscapedName:
+ revertBackToLastMode();
+ return;
+ case None:
+ default:
+ return startNewMode( None );
+ }
}
void TestSpecParser::escape() {
- if( m_mode == None )
- m_start = m_pos;
+ saveLastMode();
m_mode = EscapedName;
- m_escapeChars.push_back( m_pos );
+ m_escapeChars.push_back(m_realPatternPos);
+ }
+ bool TestSpecParser::isControlChar( char c ) const {
+ switch( m_mode ) {
+ default:
+ return false;
+ case None:
+ return c == '~';
+ case Name:
+ return c == '[';
+ case EscapedName:
+ return true;
+ case QuotedName:
+ return c == '"';
+ case Tag:
+ return c == '[' || c == ']';
+ }
}
- std::string TestSpecParser::subString() const { return m_arg.substr( m_start, m_pos - m_start ); }
void TestSpecParser::addFilter() {
if( !m_currentFilter.m_patterns.empty() ) {
@@ -11704,6 +14845,86 @@ namespace Catch {
}
}
+ void TestSpecParser::saveLastMode() {
+ lastMode = m_mode;
+ }
+
+ void TestSpecParser::revertBackToLastMode() {
+ m_mode = lastMode;
+ }
+
+ bool TestSpecParser::separate() {
+ if( (m_mode==QuotedName) || (m_mode==Tag) ){
+ //invalid argument, signal failure to previous scope.
+ m_mode = None;
+ m_pos = m_arg.size();
+ m_substring.clear();
+ m_patternName.clear();
+ m_realPatternPos = 0;
+ return false;
+ }
+ endMode();
+ addFilter();
+ return true; //success
+ }
+
+ std::string TestSpecParser::preprocessPattern() {
+ std::string token = m_patternName;
+ for (std::size_t i = 0; i < m_escapeChars.size(); ++i)
+ token = token.substr(0, m_escapeChars[i] - i) + token.substr(m_escapeChars[i] - i + 1);
+ m_escapeChars.clear();
+ if (startsWith(token, "exclude:")) {
+ m_exclusion = true;
+ token = token.substr(8);
+ }
+
+ m_patternName.clear();
+ m_realPatternPos = 0;
+
+ return token;
+ }
+
+ void TestSpecParser::addNamePattern() {
+ auto token = preprocessPattern();
+
+ if (!token.empty()) {
+ TestSpec::PatternPtr pattern = std::make_shared<TestSpec::NamePattern>(token, m_substring);
+ if (m_exclusion)
+ pattern = std::make_shared<TestSpec::ExcludedPattern>(pattern);
+ m_currentFilter.m_patterns.push_back(pattern);
+ }
+ m_substring.clear();
+ m_exclusion = false;
+ m_mode = None;
+ }
+
+ void TestSpecParser::addTagPattern() {
+ auto token = preprocessPattern();
+
+ if (!token.empty()) {
+ // If the tag pattern is the "hide and tag" shorthand (e.g. [.foo])
+ // we have to create a separate hide tag and shorten the real one
+ if (token.size() > 1 && token[0] == '.') {
+ token.erase(token.begin());
+ TestSpec::PatternPtr pattern = std::make_shared<TestSpec::TagPattern>(".", m_substring);
+ if (m_exclusion) {
+ pattern = std::make_shared<TestSpec::ExcludedPattern>(pattern);
+ }
+ m_currentFilter.m_patterns.push_back(pattern);
+ }
+
+ TestSpec::PatternPtr pattern = std::make_shared<TestSpec::TagPattern>(token, m_substring);
+
+ if (m_exclusion) {
+ pattern = std::make_shared<TestSpec::ExcludedPattern>(pattern);
+ }
+ m_currentFilter.m_patterns.push_back(pattern);
+ }
+ m_substring.clear();
+ m_exclusion = false;
+ m_mode = None;
+ }
+
TestSpec parseTestSpec( std::string const& arg ) {
return TestSpecParser( ITagAliasRegistry::get() ).parse( arg ).testSpec();
}
@@ -11744,7 +14965,7 @@ namespace Catch {
// is terrible and we should move on.
// TBD: How to signal that the measured resolution is probably wrong?
if (ticks > startTime + 3 * nanosecondsInSecond) {
- return sum / i;
+ return sum / ( i + 1u );
}
}
@@ -11805,13 +15026,11 @@ namespace Detail {
enum Arch { Big, Little };
static Arch which() {
- union _{
- int asInt;
- char asChar[sizeof (int)];
- } u;
-
- u.asInt = 1;
- return ( u.asChar[sizeof(int)-1] == 1 ) ? Big : Little;
+ int one = 1;
+ // If the lowest byte we read is non-zero, we can assume
+ // that little endian format is used.
+ auto value = *reinterpret_cast<char*>(&one);
+ return value ? Little : Big;
}
};
}
@@ -11935,6 +15154,13 @@ std::string StringMaker<wchar_t *>::convert(wchar_t * str) {
}
#endif
+#if defined(CATCH_CONFIG_CPP17_BYTE)
+#include <cstddef>
+std::string StringMaker<std::byte>::convert(std::byte value) {
+ return ::Catch::Detail::stringify(std::to_integer<unsigned long long>(value));
+}
+#endif // defined(CATCH_CONFIG_CPP17_BYTE)
+
std::string StringMaker<int>::convert(int value) {
return ::Catch::Detail::stringify(static_cast<long long>(value));
}
@@ -11997,11 +15223,16 @@ std::string StringMaker<std::nullptr_t>::convert(std::nullptr_t) {
return "nullptr";
}
+int StringMaker<float>::precision = 5;
+
std::string StringMaker<float>::convert(float value) {
- return fpToString(value, 5) + 'f';
+ return fpToString(value, precision) + 'f';
}
+
+int StringMaker<double>::precision = 10;
+
std::string StringMaker<double>::convert(double value) {
- return fpToString(value, 10);
+ return fpToString(value, precision);
}
std::string ratio_string<std::atto>::symbol() { return "a"; }
@@ -12075,11 +15306,48 @@ namespace Catch {
// end catch_totals.cpp
// start catch_uncaught_exceptions.cpp
+// start catch_config_uncaught_exceptions.hpp
+
+// Copyright Catch2 Authors
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at
+// https://www.boost.org/LICENSE_1_0.txt)
+
+// SPDX-License-Identifier: BSL-1.0
+
+#ifndef CATCH_CONFIG_UNCAUGHT_EXCEPTIONS_HPP
+#define CATCH_CONFIG_UNCAUGHT_EXCEPTIONS_HPP
+
+#if defined(_MSC_VER)
+# if _MSC_VER >= 1900 // Visual Studio 2015 or newer
+# define CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS
+# endif
+#endif
+
+#include <exception>
+
+#if defined(__cpp_lib_uncaught_exceptions) \
+ && !defined(CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS)
+
+# define CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS
+#endif // __cpp_lib_uncaught_exceptions
+
+#if defined(CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS) \
+ && !defined(CATCH_CONFIG_NO_CPP17_UNCAUGHT_EXCEPTIONS) \
+ && !defined(CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS)
+
+# define CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS
+#endif
+
+#endif // CATCH_CONFIG_UNCAUGHT_EXCEPTIONS_HPP
+// end catch_config_uncaught_exceptions.hpp
#include <exception>
namespace Catch {
bool uncaught_exceptions() {
-#if defined(CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS)
+#if defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
+ return false;
+#elif defined(CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS)
return std::uncaught_exceptions() > 0;
#else
return std::uncaught_exception();
@@ -12119,7 +15387,7 @@ namespace Catch {
}
Version const& libraryVersion() {
- static Version version( 2, 5, 0, "", 0 );
+ static Version version( 2, 13, 8, "", 0 );
return version;
}
@@ -12127,14 +15395,12 @@ namespace Catch {
// end catch_version.cpp
// start catch_wildcard_pattern.cpp
-#include <sstream>
-
namespace Catch {
WildcardPattern::WildcardPattern( std::string const& pattern,
CaseSensitive::Choice caseSensitivity )
: m_caseSensitivity( caseSensitivity ),
- m_pattern( adjustCase( pattern ) )
+ m_pattern( normaliseString( pattern ) )
{
if( startsWith( m_pattern, '*' ) ) {
m_pattern = m_pattern.substr( 1 );
@@ -12149,28 +15415,27 @@ namespace Catch {
bool WildcardPattern::matches( std::string const& str ) const {
switch( m_wildcard ) {
case NoWildcard:
- return m_pattern == adjustCase( str );
+ return m_pattern == normaliseString( str );
case WildcardAtStart:
- return endsWith( adjustCase( str ), m_pattern );
+ return endsWith( normaliseString( str ), m_pattern );
case WildcardAtEnd:
- return startsWith( adjustCase( str ), m_pattern );
+ return startsWith( normaliseString( str ), m_pattern );
case WildcardAtBothEnds:
- return contains( adjustCase( str ), m_pattern );
+ return contains( normaliseString( str ), m_pattern );
default:
CATCH_INTERNAL_ERROR( "Unknown enum" );
}
}
- std::string WildcardPattern::adjustCase( std::string const& str ) const {
- return m_caseSensitivity == CaseSensitive::No ? toLower( str ) : str;
+ std::string WildcardPattern::normaliseString( std::string const& str ) const {
+ return trim( m_caseSensitivity == CaseSensitive::No ? toLower( str ) : str );
}
}
// end catch_wildcard_pattern.cpp
// start catch_xmlwriter.cpp
#include <iomanip>
-
-using uchar = unsigned char;
+#include <type_traits>
namespace Catch {
@@ -12203,13 +15468,37 @@ namespace {
}
void hexEscapeChar(std::ostream& os, unsigned char c) {
+ std::ios_base::fmtflags f(os.flags());
os << "\\x"
<< std::uppercase << std::hex << std::setfill('0') << std::setw(2)
<< static_cast<int>(c);
+ os.flags(f);
+ }
+
+ bool shouldNewline(XmlFormatting fmt) {
+ return !!(static_cast<std::underlying_type<XmlFormatting>::type>(fmt & XmlFormatting::Newline));
+ }
+
+ bool shouldIndent(XmlFormatting fmt) {
+ return !!(static_cast<std::underlying_type<XmlFormatting>::type>(fmt & XmlFormatting::Indent));
}
} // anonymous namespace
+ XmlFormatting operator | (XmlFormatting lhs, XmlFormatting rhs) {
+ return static_cast<XmlFormatting>(
+ static_cast<std::underlying_type<XmlFormatting>::type>(lhs) |
+ static_cast<std::underlying_type<XmlFormatting>::type>(rhs)
+ );
+ }
+
+ XmlFormatting operator & (XmlFormatting lhs, XmlFormatting rhs) {
+ return static_cast<XmlFormatting>(
+ static_cast<std::underlying_type<XmlFormatting>::type>(lhs) &
+ static_cast<std::underlying_type<XmlFormatting>::type>(rhs)
+ );
+ }
+
XmlEncode::XmlEncode( std::string const& str, ForWhat forWhat )
: m_str( str ),
m_forWhat( forWhat )
@@ -12220,7 +15509,7 @@ namespace {
// (see: http://www.w3.org/TR/xml/#syntax)
for( std::size_t idx = 0; idx < m_str.size(); ++ idx ) {
- uchar c = m_str[idx];
+ unsigned char c = m_str[idx];
switch (c) {
case '<': os << "&lt;"; break;
case '&': os << "&amp;"; break;
@@ -12280,7 +15569,7 @@ namespace {
bool valid = true;
uint32_t value = headerValue(c);
for (std::size_t n = 1; n < encBytes; ++n) {
- uchar nc = m_str[idx + n];
+ unsigned char nc = m_str[idx + n];
valid &= ((nc & 0xC0) == 0x80);
value = (value << 6) | (nc & 0x3F);
}
@@ -12314,13 +15603,17 @@ namespace {
return os;
}
- XmlWriter::ScopedElement::ScopedElement( XmlWriter* writer )
- : m_writer( writer )
+ XmlWriter::ScopedElement::ScopedElement( XmlWriter* writer, XmlFormatting fmt )
+ : m_writer( writer ),
+ m_fmt(fmt)
{}
XmlWriter::ScopedElement::ScopedElement( ScopedElement&& other ) noexcept
- : m_writer( other.m_writer ){
+ : m_writer( other.m_writer ),
+ m_fmt(other.m_fmt)
+ {
other.m_writer = nullptr;
+ other.m_fmt = XmlFormatting::None;
}
XmlWriter::ScopedElement& XmlWriter::ScopedElement::operator=( ScopedElement&& other ) noexcept {
if ( m_writer ) {
@@ -12328,16 +15621,19 @@ namespace {
}
m_writer = other.m_writer;
other.m_writer = nullptr;
+ m_fmt = other.m_fmt;
+ other.m_fmt = XmlFormatting::None;
return *this;
}
XmlWriter::ScopedElement::~ScopedElement() {
- if( m_writer )
- m_writer->endElement();
+ if (m_writer) {
+ m_writer->endElement(m_fmt);
+ }
}
- XmlWriter::ScopedElement& XmlWriter::ScopedElement::writeText( std::string const& text, bool indent ) {
- m_writer->writeText( text, indent );
+ XmlWriter::ScopedElement& XmlWriter::ScopedElement::writeText( std::string const& text, XmlFormatting fmt ) {
+ m_writer->writeText( text, fmt );
return *this;
}
@@ -12347,37 +15643,47 @@ namespace {
}
XmlWriter::~XmlWriter() {
- while( !m_tags.empty() )
+ while (!m_tags.empty()) {
endElement();
+ }
+ newlineIfNecessary();
}
- XmlWriter& XmlWriter::startElement( std::string const& name ) {
+ XmlWriter& XmlWriter::startElement( std::string const& name, XmlFormatting fmt ) {
ensureTagClosed();
newlineIfNecessary();
- m_os << m_indent << '<' << name;
+ if (shouldIndent(fmt)) {
+ m_os << m_indent;
+ m_indent += " ";
+ }
+ m_os << '<' << name;
m_tags.push_back( name );
- m_indent += " ";
m_tagIsOpen = true;
+ applyFormatting(fmt);
return *this;
}
- XmlWriter::ScopedElement XmlWriter::scopedElement( std::string const& name ) {
- ScopedElement scoped( this );
- startElement( name );
+ XmlWriter::ScopedElement XmlWriter::scopedElement( std::string const& name, XmlFormatting fmt ) {
+ ScopedElement scoped( this, fmt );
+ startElement( name, fmt );
return scoped;
}
- XmlWriter& XmlWriter::endElement() {
- newlineIfNecessary();
- m_indent = m_indent.substr( 0, m_indent.size()-2 );
+ XmlWriter& XmlWriter::endElement(XmlFormatting fmt) {
+ m_indent = m_indent.substr(0, m_indent.size() - 2);
+
if( m_tagIsOpen ) {
m_os << "/>";
m_tagIsOpen = false;
+ } else {
+ newlineIfNecessary();
+ if (shouldIndent(fmt)) {
+ m_os << m_indent;
+ }
+ m_os << "</" << m_tags.back() << ">";
}
- else {
- m_os << m_indent << "</" << m_tags.back() << ">";
- }
- m_os << std::endl;
+ m_os << std::flush;
+ applyFormatting(fmt);
m_tags.pop_back();
return *this;
}
@@ -12393,22 +15699,26 @@ namespace {
return *this;
}
- XmlWriter& XmlWriter::writeText( std::string const& text, bool indent ) {
+ XmlWriter& XmlWriter::writeText( std::string const& text, XmlFormatting fmt) {
if( !text.empty() ){
bool tagWasOpen = m_tagIsOpen;
ensureTagClosed();
- if( tagWasOpen && indent )
+ if (tagWasOpen && shouldIndent(fmt)) {
m_os << m_indent;
+ }
m_os << XmlEncode( text );
- m_needsNewline = true;
+ applyFormatting(fmt);
}
return *this;
}
- XmlWriter& XmlWriter::writeComment( std::string const& text ) {
+ XmlWriter& XmlWriter::writeComment( std::string const& text, XmlFormatting fmt) {
ensureTagClosed();
- m_os << m_indent << "<!--" << text << "-->";
- m_needsNewline = true;
+ if (shouldIndent(fmt)) {
+ m_os << m_indent;
+ }
+ m_os << "<!--" << text << "-->";
+ applyFormatting(fmt);
return *this;
}
@@ -12424,11 +15734,16 @@ namespace {
void XmlWriter::ensureTagClosed() {
if( m_tagIsOpen ) {
- m_os << ">" << std::endl;
+ m_os << '>' << std::flush;
+ newlineIfNecessary();
m_tagIsOpen = false;
}
}
+ void XmlWriter::applyFormatting(XmlFormatting fmt) {
+ m_needsNewline = shouldNewline(fmt);
+ }
+
void XmlWriter::writeDeclaration() {
m_os << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
}
@@ -12469,11 +15784,37 @@ namespace Catch {
#ifdef _MSC_VER
sprintf_s(buffer, "%.3f", duration);
#else
- sprintf(buffer, "%.3f", duration);
+ std::sprintf(buffer, "%.3f", duration);
#endif
return std::string(buffer);
}
+ bool shouldShowDuration( IConfig const& config, double duration ) {
+ if ( config.showDurations() == ShowDurations::Always ) {
+ return true;
+ }
+ if ( config.showDurations() == ShowDurations::Never ) {
+ return false;
+ }
+ const double min = config.minDuration();
+ return min >= 0 && duration >= min;
+ }
+
+ std::string serializeFilters( std::vector<std::string> const& container ) {
+ ReusableStringStream oss;
+ bool first = true;
+ for (auto&& filter : container)
+ {
+ if (!first)
+ oss << ' ';
+ else
+ first = false;
+
+ oss << filter;
+ }
+ return oss.str();
+ }
+
TestEventListenerBase::TestEventListenerBase(ReporterConfig const & _config)
:StreamingReporterBase(_config) {}
@@ -12689,24 +16030,25 @@ private:
if (itMessage == messages.end())
return;
- // using messages.end() directly yields (or auto) compilation error:
- std::vector<MessageInfo>::const_iterator itEnd = messages.end();
- const std::size_t N = static_cast<std::size_t>(std::distance(itMessage, itEnd));
+ const auto itEnd = messages.cend();
+ const auto N = static_cast<std::size_t>(std::distance(itMessage, itEnd));
{
Colour colourGuard(colour);
stream << " with " << pluralise(N, "message") << ':';
}
- for (; itMessage != itEnd; ) {
+ while (itMessage != itEnd) {
// If this assertion is a warning ignore any INFO messages
if (printInfoMessages || itMessage->type != ResultWas::Info) {
- stream << " '" << itMessage->message << '\'';
- if (++itMessage != itEnd) {
+ printMessage();
+ if (itMessage != itEnd) {
Colour colourGuard(dimColour());
stream << " and";
}
+ continue;
}
+ ++itMessage;
}
}
@@ -12724,10 +16066,6 @@ private:
return "Reports test results on a single line, suitable for IDEs";
}
- ReporterPreferences CompactReporter::getPreferences() const {
- return m_reporterPrefs;
- }
-
void CompactReporter::noMatchingTestCases( std::string const& spec ) {
stream << "No test cases matched '" << spec << '\'' << std::endl;
}
@@ -12754,8 +16092,9 @@ private:
}
void CompactReporter::sectionEnded(SectionStats const& _sectionStats) {
- if (m_config->showDurations() == ShowDurations::Always) {
- stream << getFormattedDuration(_sectionStats.durationInSeconds) << " s: " << _sectionStats.sectionInfo.name << std::endl;
+ double dur = _sectionStats.durationInSeconds;
+ if ( shouldShowDuration( *m_config, dur ) ) {
+ stream << getFormattedDuration( dur ) << " s: " << _sectionStats.sectionInfo.name << std::endl;
}
}
@@ -12779,8 +16118,13 @@ private:
#if defined(_MSC_VER)
#pragma warning(push)
#pragma warning(disable:4061) // Not all labels are EXPLICITLY handled in switch
- // Note that 4062 (not all labels are handled
- // and default is missing) is enabled
+ // Note that 4062 (not all labels are handled and default is missing) is enabled
+#endif
+
+#if defined(__clang__)
+# pragma clang diagnostic push
+// For simplicity, benchmarking-only helpers are always enabled
+# pragma clang diagnostic ignored "-Wunused-function"
#endif
namespace Catch {
@@ -12962,11 +16306,11 @@ class Duration {
static const uint64_t s_nanosecondsInASecond = 1000 * s_nanosecondsInAMillisecond;
static const uint64_t s_nanosecondsInAMinute = 60 * s_nanosecondsInASecond;
- uint64_t m_inNanoseconds;
+ double m_inNanoseconds;
Unit m_units;
public:
- explicit Duration(uint64_t inNanoseconds, Unit units = Unit::Auto)
+ explicit Duration(double inNanoseconds, Unit units = Unit::Auto)
: m_inNanoseconds(inNanoseconds),
m_units(units) {
if (m_units == Unit::Auto) {
@@ -12995,7 +16339,7 @@ public:
case Unit::Minutes:
return m_inNanoseconds / static_cast<double>(s_nanosecondsInAMinute);
default:
- return static_cast<double>(m_inNanoseconds);
+ return m_inNanoseconds;
}
}
auto unitsAsString() const -> std::string {
@@ -13003,7 +16347,7 @@ public:
case Unit::Nanoseconds:
return "ns";
case Unit::Microseconds:
- return "µs";
+ return "us";
case Unit::Milliseconds:
return "ms";
case Unit::Seconds:
@@ -13016,7 +16360,7 @@ public:
}
friend auto operator << (std::ostream& os, Duration const& duration) -> std::ostream& {
- return os << duration.value() << " " << duration.unitsAsString();
+ return os << duration.value() << ' ' << duration.unitsAsString();
}
};
} // end anon namespace
@@ -13041,10 +16385,16 @@ public:
if (!m_isOpen) {
m_isOpen = true;
*this << RowBreak();
- for (auto const& info : m_columnInfos)
- *this << info.name << ColumnBreak();
- *this << RowBreak();
- m_os << Catch::getLineOfChars<'-'>() << "\n";
+
+ Columns headerCols;
+ Spacer spacer(2);
+ for (auto const& info : m_columnInfos) {
+ headerCols += Column(info.name).width(static_cast<std::size_t>(info.width - 2));
+ headerCols += spacer;
+ }
+ m_os << headerCols << '\n';
+
+ m_os << Catch::getLineOfChars<'-'>() << '\n';
}
}
void close() {
@@ -13063,30 +16413,29 @@ public:
friend TablePrinter& operator << (TablePrinter& tp, ColumnBreak) {
auto colStr = tp.m_oss.str();
- // This takes account of utf8 encodings
- auto strSize = Catch::StringRef(colStr).numberOfCharacters();
+ const auto strSize = colStr.size();
tp.m_oss.str("");
tp.open();
if (tp.m_currentColumn == static_cast<int>(tp.m_columnInfos.size() - 1)) {
tp.m_currentColumn = -1;
- tp.m_os << "\n";
+ tp.m_os << '\n';
}
tp.m_currentColumn++;
auto colInfo = tp.m_columnInfos[tp.m_currentColumn];
- auto padding = (strSize + 2 < static_cast<std::size_t>(colInfo.width))
- ? std::string(colInfo.width - (strSize + 2), ' ')
+ auto padding = (strSize + 1 < static_cast<std::size_t>(colInfo.width))
+ ? std::string(colInfo.width - (strSize + 1), ' ')
: std::string();
if (colInfo.justification == ColumnInfo::Left)
- tp.m_os << colStr << padding << " ";
+ tp.m_os << colStr << padding << ' ';
else
- tp.m_os << padding << colStr << " ";
+ tp.m_os << padding << colStr << ' ';
return tp;
}
friend TablePrinter& operator << (TablePrinter& tp, RowBreak) {
if (tp.m_currentColumn > 0) {
- tp.m_os << "\n";
+ tp.m_os << '\n';
tp.m_currentColumn = -1;
}
return tp;
@@ -13096,12 +16445,26 @@ public:
ConsoleReporter::ConsoleReporter(ReporterConfig const& config)
: StreamingReporterBase(config),
m_tablePrinter(new TablePrinter(config.stream(),
- {
- { "benchmark name", CATCH_CONFIG_CONSOLE_WIDTH - 32, ColumnInfo::Left },
- { "iters", 8, ColumnInfo::Right },
- { "elapsed ns", 14, ColumnInfo::Right },
- { "average", 14, ColumnInfo::Right }
- })) {}
+ [&config]() -> std::vector<ColumnInfo> {
+ if (config.fullConfig()->benchmarkNoAnalysis())
+ {
+ return{
+ { "benchmark name", CATCH_CONFIG_CONSOLE_WIDTH - 43, ColumnInfo::Left },
+ { " samples", 14, ColumnInfo::Right },
+ { " iterations", 14, ColumnInfo::Right },
+ { " mean", 14, ColumnInfo::Right }
+ };
+ }
+ else
+ {
+ return{
+ { "benchmark name", CATCH_CONFIG_CONSOLE_WIDTH - 43, ColumnInfo::Left },
+ { "samples mean std dev", 14, ColumnInfo::Right },
+ { "iterations low mean low std dev", 14, ColumnInfo::Right },
+ { "estimated high mean high std dev", 14, ColumnInfo::Right }
+ };
+ }
+ }())) {}
ConsoleReporter::~ConsoleReporter() = default;
std::string ConsoleReporter::getDescription() {
@@ -13112,6 +16475,10 @@ void ConsoleReporter::noMatchingTestCases(std::string const& spec) {
stream << "No test cases matched '" << spec << '\'' << std::endl;
}
+void ConsoleReporter::reportInvalidArguments(std::string const&arg){
+ stream << "Invalid Filter: " << arg << std::endl;
+}
+
void ConsoleReporter::assertionStarting(AssertionInfo const&) {}
bool ConsoleReporter::assertionEnded(AssertionStats const& _assertionStats) {
@@ -13132,6 +16499,7 @@ bool ConsoleReporter::assertionEnded(AssertionStats const& _assertionStats) {
}
void ConsoleReporter::sectionStarting(SectionInfo const& _sectionInfo) {
+ m_tablePrinter->close();
m_headerPrinted = false;
StreamingReporterBase::sectionStarting(_sectionInfo);
}
@@ -13146,8 +16514,9 @@ void ConsoleReporter::sectionEnded(SectionStats const& _sectionStats) {
stream << "\nNo assertions in test case";
stream << " '" << _sectionStats.sectionInfo.name << "'\n" << std::endl;
}
- if (m_config->showDurations() == ShowDurations::Always) {
- stream << getFormattedDuration(_sectionStats.durationInSeconds) << " s: " << _sectionStats.sectionInfo.name << std::endl;
+ double dur = _sectionStats.durationInSeconds;
+ if (shouldShowDuration(*m_config, dur)) {
+ stream << getFormattedDuration(dur) << " s: " << _sectionStats.sectionInfo.name << std::endl;
}
if (m_headerPrinted) {
m_headerPrinted = false;
@@ -13155,28 +16524,53 @@ void ConsoleReporter::sectionEnded(SectionStats const& _sectionStats) {
StreamingReporterBase::sectionEnded(_sectionStats);
}
-void ConsoleReporter::benchmarkStarting(BenchmarkInfo const& info) {
- lazyPrintWithoutClosingBenchmarkTable();
+#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)
+void ConsoleReporter::benchmarkPreparing(std::string const& name) {
+ lazyPrintWithoutClosingBenchmarkTable();
- auto nameCol = Column( info.name ).width( static_cast<std::size_t>( m_tablePrinter->columnInfos()[0].width - 2 ) );
+ auto nameCol = Column(name).width(static_cast<std::size_t>(m_tablePrinter->columnInfos()[0].width - 2));
- bool firstLine = true;
- for (auto line : nameCol) {
- if (!firstLine)
- (*m_tablePrinter) << ColumnBreak() << ColumnBreak() << ColumnBreak();
- else
- firstLine = false;
+ bool firstLine = true;
+ for (auto line : nameCol) {
+ if (!firstLine)
+ (*m_tablePrinter) << ColumnBreak() << ColumnBreak() << ColumnBreak();
+ else
+ firstLine = false;
+
+ (*m_tablePrinter) << line << ColumnBreak();
+ }
+}
- (*m_tablePrinter) << line << ColumnBreak();
+void ConsoleReporter::benchmarkStarting(BenchmarkInfo const& info) {
+ (*m_tablePrinter) << info.samples << ColumnBreak()
+ << info.iterations << ColumnBreak();
+ if (!m_config->benchmarkNoAnalysis())
+ (*m_tablePrinter) << Duration(info.estimatedDuration) << ColumnBreak();
+}
+void ConsoleReporter::benchmarkEnded(BenchmarkStats<> const& stats) {
+ if (m_config->benchmarkNoAnalysis())
+ {
+ (*m_tablePrinter) << Duration(stats.mean.point.count()) << ColumnBreak();
+ }
+ else
+ {
+ (*m_tablePrinter) << ColumnBreak()
+ << Duration(stats.mean.point.count()) << ColumnBreak()
+ << Duration(stats.mean.lower_bound.count()) << ColumnBreak()
+ << Duration(stats.mean.upper_bound.count()) << ColumnBreak() << ColumnBreak()
+ << Duration(stats.standardDeviation.point.count()) << ColumnBreak()
+ << Duration(stats.standardDeviation.lower_bound.count()) << ColumnBreak()
+ << Duration(stats.standardDeviation.upper_bound.count()) << ColumnBreak() << ColumnBreak() << ColumnBreak() << ColumnBreak() << ColumnBreak();
}
}
-void ConsoleReporter::benchmarkEnded(BenchmarkStats const& stats) {
- Duration average(stats.elapsedTimeInNanoseconds / stats.iterations);
+
+void ConsoleReporter::benchmarkFailed(std::string const& error) {
+ Colour colour(Colour::Red);
(*m_tablePrinter)
- << stats.iterations << ColumnBreak()
- << stats.elapsedTimeInNanoseconds << ColumnBreak()
- << average << ColumnBreak();
+ << "Benchmark failed (" << error << ')'
+ << ColumnBreak() << RowBreak();
}
+#endif // CATCH_CONFIG_ENABLE_BENCHMARKING
void ConsoleReporter::testCaseEnded(TestCaseStats const& _testCaseStats) {
m_tablePrinter->close();
@@ -13198,6 +16592,10 @@ void ConsoleReporter::testRunEnded(TestRunStats const& _testRunStats) {
stream << std::endl;
StreamingReporterBase::testRunEnded(_testRunStats);
}
+void ConsoleReporter::testRunStarting(TestRunInfo const& _testInfo) {
+ StreamingReporterBase::testRunStarting(_testInfo);
+ printTestFilters();
+}
void ConsoleReporter::lazyPrint() {
@@ -13251,11 +16649,9 @@ void ConsoleReporter::printTestCaseAndSectionHeader() {
SourceLineInfo lineInfo = m_sectionStack.back().lineInfo;
- if (!lineInfo.empty()) {
- stream << getLineOfChars<'-'>() << '\n';
- Colour colourGuard(Colour::FileName);
- stream << lineInfo << '\n';
- }
+ stream << getLineOfChars<'-'>() << '\n';
+ Colour colourGuard(Colour::FileName);
+ stream << lineInfo << '\n';
stream << getLineOfChars<'.'>() << '\n' << std::endl;
}
@@ -13379,6 +16775,13 @@ void ConsoleReporter::printSummaryDivider() {
stream << getLineOfChars<'-'>() << '\n';
}
+void ConsoleReporter::printTestFilters() {
+ if (m_config->testSpec().hasFilters()) {
+ Colour guard(Colour::BrightYellow);
+ stream << "Filters: " << serializeFilters(m_config->getTestsOrTags()) << '\n';
+ }
+}
+
CATCH_REGISTER_REPORTER("console", ConsoleReporter)
} // end namespace Catch
@@ -13386,6 +16789,10 @@ CATCH_REGISTER_REPORTER("console", ConsoleReporter)
#if defined(_MSC_VER)
#pragma warning(pop)
#endif
+
+#if defined(__clang__)
+# pragma clang diagnostic pop
+#endif
// end catch_reporter_console.cpp
// start catch_reporter_junit.cpp
@@ -13393,6 +16800,7 @@ CATCH_REGISTER_REPORTER("console", ConsoleReporter)
#include <sstream>
#include <ctime>
#include <algorithm>
+#include <iomanip>
namespace Catch {
@@ -13420,7 +16828,7 @@ namespace Catch {
#else
std::strftime(timeStamp, timeStampSize, fmt, timeInfo);
#endif
- return std::string(timeStamp);
+ return std::string(timeStamp, timeStampSize-1);
}
std::string fileNameTag(const std::vector<std::string> &tags) {
@@ -13431,6 +16839,17 @@ namespace Catch {
return it->substr(1);
return std::string();
}
+
+ // Formats the duration in seconds to 3 decimal places.
+ // This is done because some genius defined Maven Surefire schema
+ // in a way that only accepts 3 decimal places, and tools like
+ // Jenkins use that schema for validation JUnit reporter output.
+ std::string formatDuration( double seconds ) {
+ ReusableStringStream rss;
+ rss << std::fixed << std::setprecision( 3 ) << seconds;
+ return rss.str();
+ }
+
} // anonymous namespace
JunitReporter::JunitReporter( ReporterConfig const& _config )
@@ -13490,6 +16909,7 @@ namespace Catch {
void JunitReporter::writeGroup( TestGroupNode const& groupNode, double suiteTime ) {
XmlWriter::ScopedElement e = xml.scopedElement( "testsuite" );
+
TestGroupStats const& stats = groupNode.value;
xml.writeAttribute( "name", stats.groupInfo.name );
xml.writeAttribute( "errors", unexpectedExceptions );
@@ -13499,15 +16919,30 @@ namespace Catch {
if( m_config->showDurations() == ShowDurations::Never )
xml.writeAttribute( "time", "" );
else
- xml.writeAttribute( "time", suiteTime );
+ xml.writeAttribute( "time", formatDuration( suiteTime ) );
xml.writeAttribute( "timestamp", getCurrentTimestamp() );
+ // Write properties if there are any
+ if (m_config->hasTestFilters() || m_config->rngSeed() != 0) {
+ auto properties = xml.scopedElement("properties");
+ if (m_config->hasTestFilters()) {
+ xml.scopedElement("property")
+ .writeAttribute("name", "filters")
+ .writeAttribute("value", serializeFilters(m_config->getTestsOrTags()));
+ }
+ if (m_config->rngSeed() != 0) {
+ xml.scopedElement("property")
+ .writeAttribute("name", "random-seed")
+ .writeAttribute("value", m_config->rngSeed());
+ }
+ }
+
// Write test cases
for( auto const& child : groupNode.children )
writeTestCase( *child );
- xml.scopedElement( "system-out" ).writeText( trim( stdOutForSuite ), false );
- xml.scopedElement( "system-err" ).writeText( trim( stdErrForSuite ), false );
+ xml.scopedElement( "system-out" ).writeText( trim( stdOutForSuite ), XmlFormatting::Newline );
+ xml.scopedElement( "system-err" ).writeText( trim( stdErrForSuite ), XmlFormatting::Newline );
}
void JunitReporter::writeTestCase( TestCaseNode const& testCaseNode ) {
@@ -13529,12 +16964,13 @@ namespace Catch {
if ( !m_config->name().empty() )
className = m_config->name() + "." + className;
- writeSection( className, "", rootSection );
+ writeSection( className, "", rootSection, stats.testInfo.okToFail() );
}
- void JunitReporter::writeSection( std::string const& className,
- std::string const& rootName,
- SectionNode const& sectionNode ) {
+ void JunitReporter::writeSection( std::string const& className,
+ std::string const& rootName,
+ SectionNode const& sectionNode,
+ bool testOkToFail) {
std::string name = trim( sectionNode.stats.sectionInfo.name );
if( !rootName.empty() )
name = rootName + '/' + name;
@@ -13551,20 +16987,30 @@ namespace Catch {
xml.writeAttribute( "classname", className );
xml.writeAttribute( "name", name );
}
- xml.writeAttribute( "time", ::Catch::Detail::stringify( sectionNode.stats.durationInSeconds ) );
+ xml.writeAttribute( "time", formatDuration( sectionNode.stats.durationInSeconds ) );
+ // This is not ideal, but it should be enough to mimic gtest's
+ // junit output.
+ // Ideally the JUnit reporter would also handle `skipTest`
+ // events and write those out appropriately.
+ xml.writeAttribute( "status", "run" );
+
+ if (sectionNode.stats.assertions.failedButOk) {
+ xml.scopedElement("skipped")
+ .writeAttribute("message", "TEST_CASE tagged with !mayfail");
+ }
writeAssertions( sectionNode );
if( !sectionNode.stdOut.empty() )
- xml.scopedElement( "system-out" ).writeText( trim( sectionNode.stdOut ), false );
+ xml.scopedElement( "system-out" ).writeText( trim( sectionNode.stdOut ), XmlFormatting::Newline );
if( !sectionNode.stdErr.empty() )
- xml.scopedElement( "system-err" ).writeText( trim( sectionNode.stdErr ), false );
+ xml.scopedElement( "system-err" ).writeText( trim( sectionNode.stdErr ), XmlFormatting::Newline );
}
for( auto const& childNode : sectionNode.childSections )
if( className.empty() )
- writeSection( name, "", *childNode );
+ writeSection( name, "", *childNode, testOkToFail );
else
- writeSection( className, name, *childNode );
+ writeSection( className, name, *childNode, testOkToFail );
}
void JunitReporter::writeAssertions( SectionNode const& sectionNode ) {
@@ -13582,11 +17028,7 @@ namespace Catch {
elementName = "error";
break;
case ResultWas::ExplicitFailure:
- elementName = "failure";
- break;
case ResultWas::ExpressionFailed:
- elementName = "failure";
- break;
case ResultWas::DidntThrowException:
elementName = "failure";
break;
@@ -13604,10 +17046,25 @@ namespace Catch {
XmlWriter::ScopedElement e = xml.scopedElement( elementName );
- xml.writeAttribute( "message", result.getExpandedExpression() );
+ xml.writeAttribute( "message", result.getExpression() );
xml.writeAttribute( "type", result.getTestMacroName() );
ReusableStringStream rss;
+ if (stats.totals.assertions.total() > 0) {
+ rss << "FAILED" << ":\n";
+ if (result.hasExpression()) {
+ rss << " ";
+ rss << result.getExpressionInMacro();
+ rss << '\n';
+ }
+ if (result.hasExpandedExpression()) {
+ rss << "with expansion:\n";
+ rss << Column(result.getExpandedExpression()).indent(2) << '\n';
+ }
+ } else {
+ rss << '\n';
+ }
+
if( !result.getMessage().empty() )
rss << result.getMessage() << '\n';
for( auto const& msg : stats.infoMessages )
@@ -13615,7 +17072,7 @@ namespace Catch {
rss << msg.message << '\n';
rss << "at " << result.getSourceInfo();
- xml.writeText( rss.str(), false );
+ xml.writeText( rss.str(), XmlFormatting::Newline );
}
}
@@ -13659,19 +17116,41 @@ namespace Catch {
m_reporter->noMatchingTestCases( spec );
}
+ void ListeningReporter::reportInvalidArguments(std::string const&arg){
+ for ( auto const& listener : m_listeners ) {
+ listener->reportInvalidArguments( arg );
+ }
+ m_reporter->reportInvalidArguments( arg );
+ }
+
+#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)
+ void ListeningReporter::benchmarkPreparing( std::string const& name ) {
+ for (auto const& listener : m_listeners) {
+ listener->benchmarkPreparing(name);
+ }
+ m_reporter->benchmarkPreparing(name);
+ }
void ListeningReporter::benchmarkStarting( BenchmarkInfo const& benchmarkInfo ) {
for ( auto const& listener : m_listeners ) {
listener->benchmarkStarting( benchmarkInfo );
}
m_reporter->benchmarkStarting( benchmarkInfo );
}
- void ListeningReporter::benchmarkEnded( BenchmarkStats const& benchmarkStats ) {
+ void ListeningReporter::benchmarkEnded( BenchmarkStats<> const& benchmarkStats ) {
for ( auto const& listener : m_listeners ) {
listener->benchmarkEnded( benchmarkStats );
}
m_reporter->benchmarkEnded( benchmarkStats );
}
+ void ListeningReporter::benchmarkFailed( std::string const& error ) {
+ for (auto const& listener : m_listeners) {
+ listener->benchmarkFailed(error);
+ }
+ m_reporter->benchmarkFailed(error);
+ }
+#endif // CATCH_CONFIG_ENABLE_BENCHMARKING
+
void ListeningReporter::testRunStarting( TestRunInfo const& testRunInfo ) {
for ( auto const& listener : m_listeners ) {
listener->testRunStarting( testRunInfo );
@@ -13802,6 +17281,8 @@ namespace Catch {
m_xml.startElement( "Catch" );
if( !m_config->name().empty() )
m_xml.writeAttribute( "name", m_config->name() );
+ if (m_config->testSpec().hasFilters())
+ m_xml.writeAttribute( "filters", serializeFilters( m_config->getTestsOrTags() ) );
if( m_config->rngSeed() != 0 )
m_xml.scopedElement( "Randomness" )
.writeAttribute( "seed", m_config->rngSeed() );
@@ -13937,9 +17418,9 @@ namespace Catch {
e.writeAttribute( "durationInSeconds", m_testCaseTimer.getElapsedSeconds() );
if( !testCaseStats.stdOut.empty() )
- m_xml.scopedElement( "StdOut" ).writeText( trim( testCaseStats.stdOut ), false );
+ m_xml.scopedElement( "StdOut" ).writeText( trim( testCaseStats.stdOut ), XmlFormatting::Newline );
if( !testCaseStats.stdErr.empty() )
- m_xml.scopedElement( "StdErr" ).writeText( trim( testCaseStats.stdErr ), false );
+ m_xml.scopedElement( "StdErr" ).writeText( trim( testCaseStats.stdErr ), XmlFormatting::Newline );
m_xml.endElement();
}
@@ -13951,6 +17432,10 @@ namespace Catch {
.writeAttribute( "successes", testGroupStats.totals.assertions.passed )
.writeAttribute( "failures", testGroupStats.totals.assertions.failed )
.writeAttribute( "expectedFailures", testGroupStats.totals.assertions.failedButOk );
+ m_xml.scopedElement( "OverallResultsCases")
+ .writeAttribute( "successes", testGroupStats.totals.testCases.passed )
+ .writeAttribute( "failures", testGroupStats.totals.testCases.failed )
+ .writeAttribute( "expectedFailures", testGroupStats.totals.testCases.failedButOk );
m_xml.endElement();
}
@@ -13960,9 +17445,58 @@ namespace Catch {
.writeAttribute( "successes", testRunStats.totals.assertions.passed )
.writeAttribute( "failures", testRunStats.totals.assertions.failed )
.writeAttribute( "expectedFailures", testRunStats.totals.assertions.failedButOk );
+ m_xml.scopedElement( "OverallResultsCases")
+ .writeAttribute( "successes", testRunStats.totals.testCases.passed )
+ .writeAttribute( "failures", testRunStats.totals.testCases.failed )
+ .writeAttribute( "expectedFailures", testRunStats.totals.testCases.failedButOk );
+ m_xml.endElement();
+ }
+
+#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)
+ void XmlReporter::benchmarkPreparing(std::string const& name) {
+ m_xml.startElement("BenchmarkResults")
+ .writeAttribute("name", name);
+ }
+
+ void XmlReporter::benchmarkStarting(BenchmarkInfo const &info) {
+ m_xml.writeAttribute("samples", info.samples)
+ .writeAttribute("resamples", info.resamples)
+ .writeAttribute("iterations", info.iterations)
+ .writeAttribute("clockResolution", info.clockResolution)
+ .writeAttribute("estimatedDuration", info.estimatedDuration)
+ .writeComment("All values in nano seconds");
+ }
+
+ void XmlReporter::benchmarkEnded(BenchmarkStats<> const& benchmarkStats) {
+ m_xml.startElement("mean")
+ .writeAttribute("value", benchmarkStats.mean.point.count())
+ .writeAttribute("lowerBound", benchmarkStats.mean.lower_bound.count())
+ .writeAttribute("upperBound", benchmarkStats.mean.upper_bound.count())
+ .writeAttribute("ci", benchmarkStats.mean.confidence_interval);
+ m_xml.endElement();
+ m_xml.startElement("standardDeviation")
+ .writeAttribute("value", benchmarkStats.standardDeviation.point.count())
+ .writeAttribute("lowerBound", benchmarkStats.standardDeviation.lower_bound.count())
+ .writeAttribute("upperBound", benchmarkStats.standardDeviation.upper_bound.count())
+ .writeAttribute("ci", benchmarkStats.standardDeviation.confidence_interval);
+ m_xml.endElement();
+ m_xml.startElement("outliers")
+ .writeAttribute("variance", benchmarkStats.outlierVariance)
+ .writeAttribute("lowMild", benchmarkStats.outliers.low_mild)
+ .writeAttribute("lowSevere", benchmarkStats.outliers.low_severe)
+ .writeAttribute("highMild", benchmarkStats.outliers.high_mild)
+ .writeAttribute("highSevere", benchmarkStats.outliers.high_severe);
+ m_xml.endElement();
m_xml.endElement();
}
+ void XmlReporter::benchmarkFailed(std::string const &error) {
+ m_xml.scopedElement("failed").
+ writeAttribute("message", error);
+ m_xml.endElement();
+ }
+#endif // CATCH_CONFIG_ENABLE_BENCHMARKING
+
CATCH_REGISTER_REPORTER( "xml", XmlReporter )
} // end namespace Catch
@@ -13988,7 +17522,7 @@ namespace Catch {
#ifndef __OBJC__
-#if defined(CATCH_CONFIG_WCHAR) && defined(WIN32) && defined(_UNICODE) && !defined(DO_NOT_USE_WMAIN)
+#if defined(CATCH_CONFIG_WCHAR) && defined(CATCH_PLATFORM_WINDOWS) && defined(_UNICODE) && !defined(DO_NOT_USE_WMAIN)
// Standard C/C++ Win32 Unicode wmain entry point
extern "C" int wmain (int argc, wchar_t * argv[], wchar_t * []) {
#else
@@ -14036,7 +17570,7 @@ int main (int argc, char * const argv[]) {
#define CATCH_REQUIRE( ... ) INTERNAL_CATCH_TEST( "CATCH_REQUIRE", Catch::ResultDisposition::Normal, __VA_ARGS__ )
#define CATCH_REQUIRE_FALSE( ... ) INTERNAL_CATCH_TEST( "CATCH_REQUIRE_FALSE", Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, __VA_ARGS__ )
-#define CATCH_REQUIRE_THROWS( ... ) INTERNAL_CATCH_THROWS( "CATCH_REQUIRE_THROWS", Catch::ResultDisposition::Normal, "", __VA_ARGS__ )
+#define CATCH_REQUIRE_THROWS( ... ) INTERNAL_CATCH_THROWS( "CATCH_REQUIRE_THROWS", Catch::ResultDisposition::Normal, __VA_ARGS__ )
#define CATCH_REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "CATCH_REQUIRE_THROWS_AS", exceptionType, Catch::ResultDisposition::Normal, expr )
#define CATCH_REQUIRE_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS_STR_MATCHES( "CATCH_REQUIRE_THROWS_WITH", Catch::ResultDisposition::Normal, matcher, expr )
#if !defined(CATCH_CONFIG_DISABLE_MATCHERS)
@@ -14050,7 +17584,7 @@ int main (int argc, char * const argv[]) {
#define CATCH_CHECKED_ELSE( ... ) INTERNAL_CATCH_ELSE( "CATCH_CHECKED_ELSE", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
#define CATCH_CHECK_NOFAIL( ... ) INTERNAL_CATCH_TEST( "CATCH_CHECK_NOFAIL", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, __VA_ARGS__ )
-#define CATCH_CHECK_THROWS( ... ) INTERNAL_CATCH_THROWS( "CATCH_CHECK_THROWS", Catch::ResultDisposition::ContinueOnFailure, "", __VA_ARGS__ )
+#define CATCH_CHECK_THROWS( ... ) INTERNAL_CATCH_THROWS( "CATCH_CHECK_THROWS", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
#define CATCH_CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "CATCH_CHECK_THROWS_AS", exceptionType, Catch::ResultDisposition::ContinueOnFailure, expr )
#define CATCH_CHECK_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS_STR_MATCHES( "CATCH_CHECK_THROWS_WITH", Catch::ResultDisposition::ContinueOnFailure, matcher, expr )
#if !defined(CATCH_CONFIG_DISABLE_MATCHERS)
@@ -14065,6 +17599,7 @@ int main (int argc, char * const argv[]) {
#endif // CATCH_CONFIG_DISABLE_MATCHERS
#define CATCH_INFO( msg ) INTERNAL_CATCH_INFO( "CATCH_INFO", msg )
+#define CATCH_UNSCOPED_INFO( msg ) INTERNAL_CATCH_UNSCOPED_INFO( "CATCH_UNSCOPED_INFO", msg )
#define CATCH_WARN( msg ) INTERNAL_CATCH_MSG( "CATCH_WARN", Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, msg )
#define CATCH_CAPTURE( ... ) INTERNAL_CATCH_CAPTURE( INTERNAL_CATCH_UNIQUE_NAME(capturer), "CATCH_CAPTURE",__VA_ARGS__ )
@@ -14082,10 +17617,22 @@ int main (int argc, char * const argv[]) {
#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
#define CATCH_TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ )
+#define CATCH_TEMPLATE_TEST_CASE_SIG( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG( __VA_ARGS__ )
#define CATCH_TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )
+#define CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( className, __VA_ARGS__ )
+#define CATCH_TEMPLATE_PRODUCT_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE( __VA_ARGS__ )
+#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG( ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG( __VA_ARGS__ )
+#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, __VA_ARGS__ )
+#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, __VA_ARGS__ )
#else
#define CATCH_TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ ) )
+#define CATCH_TEMPLATE_TEST_CASE_SIG( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG( __VA_ARGS__ ) )
#define CATCH_TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ ) )
+#define CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( className, __VA_ARGS__ ) )
+#define CATCH_TEMPLATE_PRODUCT_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE( __VA_ARGS__ ) )
+#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG( __VA_ARGS__ ) )
+#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, __VA_ARGS__ ) )
+#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, __VA_ARGS__ ) )
#endif
#if !defined(CATCH_CONFIG_RUNTIME_STATIC_REQUIRE)
@@ -14106,6 +17653,13 @@ int main (int argc, char * const argv[]) {
#define CATCH_THEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " Then: " << desc )
#define CATCH_AND_THEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " And: " << desc )
+#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)
+#define CATCH_BENCHMARK(...) \
+ INTERNAL_CATCH_BENCHMARK(INTERNAL_CATCH_UNIQUE_NAME(C_A_T_C_H_B_E_N_C_H_), INTERNAL_CATCH_GET_1_ARG(__VA_ARGS__,,), INTERNAL_CATCH_GET_2_ARG(__VA_ARGS__,,))
+#define CATCH_BENCHMARK_ADVANCED(name) \
+ INTERNAL_CATCH_BENCHMARK_ADVANCED(INTERNAL_CATCH_UNIQUE_NAME(C_A_T_C_H_B_E_N_C_H_), name)
+#endif // CATCH_CONFIG_ENABLE_BENCHMARKING
+
// If CATCH_CONFIG_PREFIX_ALL is not defined then the CATCH_ prefix is not required
#else
@@ -14141,6 +17695,7 @@ int main (int argc, char * const argv[]) {
#endif // CATCH_CONFIG_DISABLE_MATCHERS
#define INFO( msg ) INTERNAL_CATCH_INFO( "INFO", msg )
+#define UNSCOPED_INFO( msg ) INTERNAL_CATCH_UNSCOPED_INFO( "UNSCOPED_INFO", msg )
#define WARN( msg ) INTERNAL_CATCH_MSG( "WARN", Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, msg )
#define CAPTURE( ... ) INTERNAL_CATCH_CAPTURE( INTERNAL_CATCH_UNIQUE_NAME(capturer), "CAPTURE",__VA_ARGS__ )
@@ -14157,10 +17712,26 @@ int main (int argc, char * const argv[]) {
#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
#define TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ )
+#define TEMPLATE_TEST_CASE_SIG( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG( __VA_ARGS__ )
#define TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )
+#define TEMPLATE_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( className, __VA_ARGS__ )
+#define TEMPLATE_PRODUCT_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE( __VA_ARGS__ )
+#define TEMPLATE_PRODUCT_TEST_CASE_SIG( ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG( __VA_ARGS__ )
+#define TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, __VA_ARGS__ )
+#define TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, __VA_ARGS__ )
+#define TEMPLATE_LIST_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE(__VA_ARGS__)
+#define TEMPLATE_LIST_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_METHOD( className, __VA_ARGS__ )
#else
#define TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ ) )
+#define TEMPLATE_TEST_CASE_SIG( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG( __VA_ARGS__ ) )
#define TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ ) )
+#define TEMPLATE_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( className, __VA_ARGS__ ) )
+#define TEMPLATE_PRODUCT_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE( __VA_ARGS__ ) )
+#define TEMPLATE_PRODUCT_TEST_CASE_SIG( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG( __VA_ARGS__ ) )
+#define TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, __VA_ARGS__ ) )
+#define TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, __VA_ARGS__ ) )
+#define TEMPLATE_LIST_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE( __VA_ARGS__ ) )
+#define TEMPLATE_LIST_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_METHOD( className, __VA_ARGS__ ) )
#endif
#if !defined(CATCH_CONFIG_RUNTIME_STATIC_REQUIRE)
@@ -14186,6 +17757,13 @@ int main (int argc, char * const argv[]) {
#define THEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " Then: " << desc )
#define AND_THEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " And: " << desc )
+#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)
+#define BENCHMARK(...) \
+ INTERNAL_CATCH_BENCHMARK(INTERNAL_CATCH_UNIQUE_NAME(C_A_T_C_H_B_E_N_C_H_), INTERNAL_CATCH_GET_1_ARG(__VA_ARGS__,,), INTERNAL_CATCH_GET_2_ARG(__VA_ARGS__,,))
+#define BENCHMARK_ADVANCED(name) \
+ INTERNAL_CATCH_BENCHMARK_ADVANCED(INTERNAL_CATCH_UNIQUE_NAME(C_A_T_C_H_B_E_N_C_H_), name)
+#endif // CATCH_CONFIG_ENABLE_BENCHMARKING
+
using Catch::Detail::Approx;
#else // CATCH_CONFIG_DISABLE
@@ -14225,12 +17803,13 @@ using Catch::Detail::Approx;
#define CATCH_REQUIRE_THAT( arg, matcher ) (void)(0)
#endif // CATCH_CONFIG_DISABLE_MATCHERS
-#define CATCH_INFO( msg ) (void)(0)
-#define CATCH_WARN( msg ) (void)(0)
-#define CATCH_CAPTURE( msg ) (void)(0)
+#define CATCH_INFO( msg ) (void)(0)
+#define CATCH_UNSCOPED_INFO( msg ) (void)(0)
+#define CATCH_WARN( msg ) (void)(0)
+#define CATCH_CAPTURE( msg ) (void)(0)
-#define CATCH_TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ))
-#define CATCH_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ))
+#define CATCH_TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_S_T_ ))
+#define CATCH_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_S_T_ ))
#define CATCH_METHOD_AS_TEST_CASE( method, ... )
#define CATCH_REGISTER_TEST_CASE( Function, ... ) (void)(0)
#define CATCH_SECTION( ... )
@@ -14239,19 +17818,31 @@ using Catch::Detail::Approx;
#define CATCH_FAIL_CHECK( ... ) (void)(0)
#define CATCH_SUCCEED( ... ) (void)(0)
-#define CATCH_ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ))
+#define CATCH_ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_S_T_ ))
#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
-#define CATCH_TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ) )
-#define CATCH_TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), className )
+#define CATCH_TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(__VA_ARGS__)
+#define CATCH_TEMPLATE_TEST_CASE_SIG( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG_NO_REGISTRATION(__VA_ARGS__)
+#define CATCH_TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION(className, __VA_ARGS__)
+#define CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG_NO_REGISTRATION(className, __VA_ARGS__ )
+#define CATCH_TEMPLATE_PRODUCT_TEST_CASE( ... ) CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ )
+#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG( ... ) CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ )
+#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )
+#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, ... ) CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )
#else
-#define CATCH_TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ) ) )
-#define CATCH_TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), className ) )
+#define CATCH_TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(__VA_ARGS__) )
+#define CATCH_TEMPLATE_TEST_CASE_SIG( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG_NO_REGISTRATION(__VA_ARGS__) )
+#define CATCH_TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION(className, __VA_ARGS__ ) )
+#define CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG_NO_REGISTRATION(className, __VA_ARGS__ ) )
+#define CATCH_TEMPLATE_PRODUCT_TEST_CASE( ... ) CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ )
+#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG( ... ) CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ )
+#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )
+#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, ... ) CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )
#endif
// "BDD-style" convenience wrappers
-#define CATCH_SCENARIO( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ))
-#define CATCH_SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_METHOD_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), className )
+#define CATCH_SCENARIO( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_S_T_ ))
+#define CATCH_SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_METHOD_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_S_T_ ), className )
#define CATCH_GIVEN( desc )
#define CATCH_AND_GIVEN( desc )
#define CATCH_WHEN( desc )
@@ -14297,11 +17888,12 @@ using Catch::Detail::Approx;
#endif // CATCH_CONFIG_DISABLE_MATCHERS
#define INFO( msg ) (void)(0)
+#define UNSCOPED_INFO( msg ) (void)(0)
#define WARN( msg ) (void)(0)
#define CAPTURE( msg ) (void)(0)
-#define TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ))
-#define TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ))
+#define TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_S_T_ ))
+#define TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_S_T_ ))
#define METHOD_AS_TEST_CASE( method, ... )
#define REGISTER_TEST_CASE( Function, ... ) (void)(0)
#define SECTION( ... )
@@ -14309,14 +17901,26 @@ using Catch::Detail::Approx;
#define FAIL( ... ) (void)(0)
#define FAIL_CHECK( ... ) (void)(0)
#define SUCCEED( ... ) (void)(0)
-#define ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ))
+#define ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_S_T_ ))
#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
-#define TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ) )
-#define TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), className )
+#define TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(__VA_ARGS__)
+#define TEMPLATE_TEST_CASE_SIG( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG_NO_REGISTRATION(__VA_ARGS__)
+#define TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION(className, __VA_ARGS__)
+#define TEMPLATE_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG_NO_REGISTRATION(className, __VA_ARGS__ )
+#define TEMPLATE_PRODUCT_TEST_CASE( ... ) TEMPLATE_TEST_CASE( __VA_ARGS__ )
+#define TEMPLATE_PRODUCT_TEST_CASE_SIG( ... ) TEMPLATE_TEST_CASE( __VA_ARGS__ )
+#define TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )
+#define TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, ... ) TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )
#else
-#define TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ) ) )
-#define TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), className ) )
+#define TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(__VA_ARGS__) )
+#define TEMPLATE_TEST_CASE_SIG( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG_NO_REGISTRATION(__VA_ARGS__) )
+#define TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION(className, __VA_ARGS__ ) )
+#define TEMPLATE_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG_NO_REGISTRATION(className, __VA_ARGS__ ) )
+#define TEMPLATE_PRODUCT_TEST_CASE( ... ) TEMPLATE_TEST_CASE( __VA_ARGS__ )
+#define TEMPLATE_PRODUCT_TEST_CASE_SIG( ... ) TEMPLATE_TEST_CASE( __VA_ARGS__ )
+#define TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )
+#define TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, ... ) TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )
#endif
#define STATIC_REQUIRE( ... ) (void)(0)
@@ -14327,8 +17931,8 @@ using Catch::Detail::Approx;
#define CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION_NO_REG( INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator ), signature )
// "BDD-style" convenience wrappers
-#define SCENARIO( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ) )
-#define SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_METHOD_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), className )
+#define SCENARIO( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_S_T_ ) )
+#define SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_METHOD_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_S_T_ ), className )
#define GIVEN( desc )
#define AND_GIVEN( desc )
diff --git a/third_party/gsl-disable-gsl-suppress.patch b/third_party/gsl-disable-gsl-suppress.patch
new file mode 100644
index 0000000..fb1a126
--- /dev/null
+++ b/third_party/gsl-disable-gsl-suppress.patch
@@ -0,0 +1,11 @@
+--- a/include/gsl/gsl-lite.hpp
++++ b/include/gsl/gsl-lite.hpp
+@@ -1081,7 +1081,7 @@ namespace __cxxabiv1 { struct __cxa_eh_globals; extern "C" __cxa_eh_globals * __
+ // MSVC warning suppression macros:
+
+ #if gsl_COMPILER_MSVC_VERSION >= 140 && ! gsl_COMPILER_NVCC_VERSION
+-# define gsl_SUPPRESS_MSGSL_WARNING(expr) [[gsl::suppress(expr)]]
++# define gsl_SUPPRESS_MSGSL_WARNING(expr) /* Pimm: note disabled for intel [[gsl::suppress(expr)]]*/
+ # define gsl_SUPPRESS_MSVC_WARNING(code, descr) __pragma(warning(suppress: code) )
+ # define gsl_DISABLE_MSVC_WARNINGS(codes) __pragma(warning(push)) __pragma(warning(disable: codes))
+ # define gsl_RESTORE_MSVC_WARNINGS() __pragma(warning(pop ))
diff --git a/third_party/gsl.h b/third_party/gsl.h
index 0d79484..1bfa97f 100755..100644
--- a/third_party/gsl.h
+++ b/third_party/gsl.h
@@ -1,6 +1,6 @@
//
-// gsl-lite is based on GSL: Guideline Support Library.
-// For more information see https://github.com/martinmoene/gsl-lite
+// gsl-lite is based on GSL: Guidelines Support Library.
+// For more information see https://github.com/gsl-lite/gsl-lite
//
// Copyright (c) 2015 Martin Moene
// Copyright (c) 2015 Microsoft Corporation. All rights reserved.
@@ -17,11 +17,11 @@
// mimic MS include hierarchy
-#pragma once
-
#ifndef GSL_GSL_H_INCLUDED
#define GSL_GSL_H_INCLUDED
-#include "gsl/gsl-lite.h"
+#pragma message ("gsl.h is deprecated since version 0.27.0, use gsl/gsl-lite.hpp instead.")
+
+#include "gsl/gsl-lite.hpp"
#endif // GSL_GSL_H_INCLUDED
diff --git a/third_party/gsl/gsl b/third_party/gsl/gsl
index 339bd31..7ef52ac 100755..100644
--- a/third_party/gsl/gsl
+++ b/third_party/gsl/gsl
@@ -1,5 +1,5 @@
//
-// gsl-lite is based on GSL: Guideline Support Library.
+// gsl-lite is based on GSL: Guidelines Support Library.
// For more information see https://github.com/martinmoene/gsl-lite
//
// Copyright (c) 2015 Martin Moene
@@ -22,6 +22,8 @@
#ifndef GSL_GSL_H_INCLUDED
#define GSL_GSL_H_INCLUDED
-#include "gsl-lite.h"
+#pragma message ("gsl/gsl is deprecated since version 0.38.1, use gsl/gsl-lite.hpp instead.")
+
+#include "gsl-lite.hpp"
#endif // GSL_GSL_H_INCLUDED
diff --git a/third_party/gsl/gsl-lite-vc6.h b/third_party/gsl/gsl-lite-vc6.hpp
index 96b1904..3579336 100755..100644
--- a/third_party/gsl/gsl-lite-vc6.h
+++ b/third_party/gsl/gsl-lite-vc6.hpp
@@ -1,6 +1,6 @@
//
-// gsl-lite-vc6 is based on GSL: Guideline Support Library,
-// For more information see https://github.com/martinmoene/gsl-lite
+// gsl-lite-vc6 is based on GSL: Guidelines Support Library,
+// For more information see https://github.com/gsl-lite/gsl-lite
//
// Copyright (c) 2015 Martin Moene
// Copyright (c) 2015 Microsoft Corporation. All rights reserved.
@@ -33,20 +33,20 @@
// Configuration:
-#ifndef gsl_FEATURE_HAVE_IMPLICIT_MACRO
-# define gsl_FEATURE_HAVE_IMPLICIT_MACRO 1
+#ifndef gsl_FEATURE_IMPLICIT_MACRO
+# define gsl_FEATURE_IMPLICIT_MACRO 1
#endif
-#ifndef gsl_FEATURE_HAVE_OWNER_MACRO
-# define gsl_FEATURE_HAVE_OWNER_MACRO 1
+#ifndef gsl_FEATURE_OWNER_MACRO
+# define gsl_FEATURE_OWNER_MACRO 1
#endif
-#ifndef gsl_FEATURE_HAVE_SHARED_PTR
-# define gsl_FEATURE_HAVE_SHARED_PTR 0
+#ifndef gsl_FEATURE_SHARED_PTR
+# define gsl_FEATURE_SHARED_PTR 0
#endif
-#ifndef gsl_FEATURE_HAVE_UNIQUE_PTR
-# define gsl_FEATURE_HAVE_UNIQUE_PTR 0
+#ifndef gsl_FEATURE_UNIQUE_PTR
+# define gsl_FEATURE_UNIQUE_PTR 0
#endif
#ifndef gsl_CONFIG_THROWS_FOR_TESTING
@@ -75,35 +75,37 @@
// Compiler detection:
-#if defined(_MSC_VER)
-# define gsl_COMPILER_MSVC_VERSION (_MSC_VER / 100 - 5 - (_MSC_VER < 1900))
+#if defined(_MSC_VER ) && !defined(__clang__)
+# define gsl_COMPILER_MSVC_VER (_MSC_VER )
+# define gsl_COMPILER_MSVC_VERSION (_MSC_VER / 10 - 10 * ( 5 + (_MSC_VER < 1900 ) ) )
#else
+# define gsl_COMPILER_MSVC_VER 0
# define gsl_COMPILER_MSVC_VERSION 0
# define gsl_COMPILER_NON_MSVC 1
#endif
-#if gsl_COMPILER_MSVC_VERSION != 6
+#if gsl_COMPILER_MSVC_VERSION != 60
# error GSL Lite: this header is for Visual C++ 6
#endif
// half-open range [lo..hi):
-#define gsl_BETWEEN( v, lo, hi ) ( lo <= v && v < hi )
+#define gsl_BETWEEN( v, lo, hi ) ( (lo) <= (v) && (v) < (hi) )
// Presence of C++ language features:
// C++ feature usage:
-#if gsl_FEATURE_HAVE_IMPLICIT_MACRO
+#if gsl_FEATURE_IMPLICIT_MACRO
# define implicit
#endif
#define gsl_DIMENSION_OF( a ) ( sizeof(a) / sizeof(0[a]) )
-#if gsl_FEATURE_HAVE_SHARED_PTR
+#if gsl_FEATURE_SHARED_PTR
# include gsl_CONFIG_SHARED_PTR_INCLUDE
#endif
-#if gsl_FEATURE_HAVE_UNIQUE_PTR
+#if gsl_FEATURE_UNIQUE_PTR
# include gsl_CONFIG_UNIQUE_PTR_INCLUDE
#endif
@@ -113,10 +115,10 @@ namespace gsl {
// GSL.owner: ownership pointers
//
// ToDo:
-#if gsl_FEATURE_HAVE_SHARED_PTR
+#if gsl_FEATURE_SHARED_PTR
using gsl_CONFIG_SHARED_PTR_DECL;
#endif
-#if gsl_FEATURE_HAVE_UNIQUE_PTR
+#if gsl_FEATURE_UNIQUE_PTR
using gsl_CONFIG_UNIQUE_PTR_DECL;
#endif
@@ -124,7 +126,7 @@ template< class T > struct owner { typedef T type; };
#define gsl_HAVE_OWNER_TEMPLATE 0
-#if gsl_FEATURE_HAVE_OWNER_MACRO
+#if gsl_FEATURE_OWNER_MACRO
# define Owner(t) ::gsl::owner<t>::type
#endif
@@ -177,15 +179,15 @@ inline void fail_fast_assert( bool cond, char const * const )
// GSL.util: utilities
//
-class final_act
+class final_action
{
public:
typedef void (*Action)();
- final_act( Action action )
+ final_action( Action action )
: action_( action ) {}
- ~final_act()
+ ~final_action()
{
action_();
}
@@ -195,9 +197,9 @@ private:
};
template< class Fn >
-final_act finally( Fn const & f )
+final_action finally( Fn const & f )
{
- return final_act(( f ));
+ return final_action(( f ));
}
template< class T, class U >
@@ -655,7 +657,7 @@ namespace detail {
template<class T, class SizeType, const T Sentinel>
struct ensure
{
- static span<T> sentinel( T * seq, SizeType max = std::numeric_limits<SizeType>::max() )
+ static span<T> sentinel( T * seq, SizeType max = (std::numeric_limits<SizeType>::max)() )
{
typedef T * pointer;
typedef typename std::iterator_traits<pointer>::difference_type difference_type;
@@ -679,7 +681,7 @@ struct ensure
//
template< typename T >
-span<T> ensure_z( T * sz, size_t max = std::numeric_limits<size_t>::max() )
+span<T> ensure_z( T * sz, size_t max = (std::numeric_limits<size_t>::max)() )
{
return detail::ensure<T, size_t, 0>::sentinel( sz, max );
}
diff --git a/third_party/gsl/gsl-lite.h b/third_party/gsl/gsl-lite.h
index aae4b3e..a738253 100755..100644
--- a/third_party/gsl/gsl-lite.h
+++ b/third_party/gsl/gsl-lite.h
@@ -1,2251 +1,27 @@
//
-// gsl-lite is based on GSL: Guideline Support Library.
-// For more information see https://github.com/martinmoene/gsl-lite
+// gsl-lite is based on GSL: Guidelines Support Library.
+// For more information see https://github.com/gsl-lite/gsl-lite
//
// Copyright (c) 2015 Martin Moene
-// Copyright (c) 2015 Microsoft Corporation. All rights reserved.
-//
-// This code is licensed under the MIT License (MIT).
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-#pragma once
+// Copyright (c) 2015 Microsoft Corporation. All rights reserved.
+//
+// This code is licensed under the MIT License (MIT).
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+// mimic MS include hierarchy
#ifndef GSL_GSL_LITE_H_INCLUDED
#define GSL_GSL_LITE_H_INCLUDED
-#include <exception>
-#include <iterator>
-#include <limits>
-#include <memory>
-#include <ostream>
-#include <stdexcept>
-#include <string>
-#include <utility>
-#include <vector>
-
-#define gsl_lite_VERSION "0.22.0"
-
-// gsl-lite backward compatibility:
-
-#ifdef gsl_CONFIG_ALLOWS_SPAN_CONTAINER_CTOR
-# define gsl_CONFIG_ALLOWS_UNCONSTRAINED_SPAN_CONTAINER_CTOR gsl_CONFIG_ALLOWS_SPAN_CONTAINER_CTOR
-# pragma message ("gsl_CONFIG_ALLOWS_SPAN_CONTAINER_CTOR is deprecated since gsl-lite 0.7.0; replace with gsl_CONFIG_ALLOWS_UNCONSTRAINED_SPAN_CONTAINER_CTOR, or consider span(with_container, cont).")
-#endif
-
-// M-GSL compatibility:
-
-#if defined( GSL_THROW_ON_CONTRACT_VIOLATION )
-# define gsl_CONFIG_CONTRACT_VIOLATION_THROWS 1
-#endif
-
-#if defined( GSL_TERMINATE_ON_CONTRACT_VIOLATION )
-# define gsl_CONFIG_CONTRACT_VIOLATION_THROWS 0
-#endif
-
-#if defined( GSL_UNENFORCED_ON_CONTRACT_VIOLATION )
-# define gsl_CONFIG_CONTRACT_LEVEL_OFF 1
-#endif
-
-// Configuration:
-
-#ifndef gsl_FEATURE_HAVE_IMPLICIT_MACRO
-# define gsl_FEATURE_HAVE_IMPLICIT_MACRO 1
-#endif
-
-#ifndef gsl_FEATURE_HAVE_OWNER_MACRO
-# define gsl_FEATURE_HAVE_OWNER_MACRO 1
-#endif
-
-#ifndef gsl_FEATURE_EXPERIMENTAL_RETURN_GUARD
-# define gsl_FEATURE_EXPERIMENTAL_RETURN_GUARD 0
-#endif
-
-#ifndef gsl_CONFIG_SPAN_INDEX_TYPE
-# define gsl_CONFIG_SPAN_INDEX_TYPE size_t
-#endif
-
-#ifndef gsl_CONFIG_CONFIRMS_COMPILATION_ERRORS
-# define gsl_CONFIG_CONFIRMS_COMPILATION_ERRORS 0
-#endif
-
-#ifndef gsl_CONFIG_ALLOWS_NONSTRICT_SPAN_COMPARISON
-# define gsl_CONFIG_ALLOWS_NONSTRICT_SPAN_COMPARISON 1
-#endif
-
-#ifndef gsl_CONFIG_ALLOWS_UNCONSTRAINED_SPAN_CONTAINER_CTOR
-# define gsl_CONFIG_ALLOWS_UNCONSTRAINED_SPAN_CONTAINER_CTOR 0
-#endif
-
-#if defined( gsl_CONFIG_CONTRACT_LEVEL_ON )
-# define gsl_CONFIG_CONTRACT_LEVEL_MASK 0x11
-#elif defined( gsl_CONFIG_CONTRACT_LEVEL_OFF )
-# define gsl_CONFIG_CONTRACT_LEVEL_MASK 0x00
-#elif defined( gsl_CONFIG_CONTRACT_LEVEL_EXPECTS_ONLY )
-# define gsl_CONFIG_CONTRACT_LEVEL_MASK 0x01
-#elif defined( gsl_CONFIG_CONTRACT_LEVEL_ENSURES_ONLY )
-# define gsl_CONFIG_CONTRACT_LEVEL_MASK 0x10
-#else
-# define gsl_CONFIG_CONTRACT_LEVEL_MASK 0x11
-#endif
-
-#if !defined( gsl_CONFIG_CONTRACT_VIOLATION_THROWS ) && \
- !defined( gsl_CONFIG_CONTRACT_VIOLATION_TERMINATES )
-# define gsl_CONFIG_CONTRACT_VIOLATION_THROWS_V 0
-#elif defined( gsl_CONFIG_CONTRACT_VIOLATION_THROWS ) && \
- !defined( gsl_CONFIG_CONTRACT_VIOLATION_TERMINATES )
-# define gsl_CONFIG_CONTRACT_VIOLATION_THROWS_V 1
-#elif !defined( gsl_CONFIG_CONTRACT_VIOLATION_THROWS ) && \
- defined( gsl_CONFIG_CONTRACT_VIOLATION_TERMINATES )
-# define gsl_CONFIG_CONTRACT_VIOLATION_THROWS_V 0
-#else
-# error only one of gsl_CONFIG_CONTRACT_VIOLATION_THROWS and gsl_CONFIG_CONTRACT_VIOLATION_TERMINATES may be defined.
-#endif
-
-// Compiler detection (C++17 is speculative):
-
-#define gsl_CPP11_OR_GREATER ( __cplusplus >= 201103L )
-#define gsl_CPP14_OR_GREATER ( __cplusplus >= 201402L )
-#define gsl_CPP17_OR_GREATER ( __cplusplus >= 201700L )
-
-// half-open range [lo..hi):
-#define gsl_BETWEEN( v, lo, hi ) ( lo <= v && v < hi )
-
-#if defined(_MSC_VER) && !defined(__clang__)
-# define gsl_COMPILER_MSVC_VERSION (_MSC_VER / 100 - 5 - (_MSC_VER < 1900))
-#else
-# define gsl_COMPILER_MSVC_VERSION 0
-# define gsl_COMPILER_NON_MSVC 1
-#endif
-
-// Note: simplistic version computation; works for GCC versions on http://godbolt.org/
-#if defined(__GNUC__) && !defined(__clang__)
-# define gsl_COMPILER_GCC_VERSION ( 10 * (10 *__GNUC__ + __GNUC_MINOR__) + __GNUC_PATCHLEVEL__)
-#else
-# define gsl_COMPILER_GCC_VERSION 0
-#endif
-
-// Presence of C++11 language features:
-
-#if gsl_CPP11_OR_GREATER || gsl_COMPILER_MSVC_VERSION >= 10
-# define gsl_HAVE_AUTO 1
-# define gsl_HAVE_NULLPTR 1
-#endif
-
-#if gsl_CPP11_OR_GREATER || gsl_COMPILER_MSVC_VERSION >= 12
-# define gsl_HAVE_DEFAULT_FUNCTION_TEMPLATE_ARG 1
-#endif
-
-#if gsl_CPP11_OR_GREATER || gsl_COMPILER_MSVC_VERSION >= 14
-# define gsl_HAVE_ALIAS_TEMPLATE 1
-# define gsl_HAVE_CONSTEXPR_11 1
-# define gsl_HAVE_ENUM_CLASS 1
-# define gsl_HAVE_EXPLICIT_CONVERSION 1
-# define gsl_HAVE_INITIALIZER_LIST 1
-# define gsl_HAVE_IS_DEFAULT 1
-# define gsl_HAVE_IS_DELETE 1
-# define gsl_HAVE_NOEXCEPT 1
-#endif
-
-#if gsl_CPP11_OR_GREATER
-// see above
-#endif
-
-// Presence of C++14 language features:
-
-#if gsl_CPP14_OR_GREATER
-# define gsl_HAVE_CONSTEXPR_14 1
-#endif
-
-// Presence of C++17 language features:
-
-#if gsl_CPP17_OR_GREATER
-# define gsl_HAVE_ENUM_CLASS_CONSTRUCTION_FROM_UNDERLYING_TYPE 1
-#endif
-
-// Presence of C++ library features:
-
-#if gsl_COMPILER_GCC_VERSION
-# define gsl_HAVE_TR1_TYPE_TRAITS 1
-#endif
-
-#if gsl_CPP11_OR_GREATER || gsl_COMPILER_MSVC_VERSION >= 11
-# define gsl_HAVE_ARRAY 1
-# define gsl_HAVE_TR1_TYPE_TRAITS 1
-#endif
-
-#if gsl_CPP11_OR_GREATER || gsl_COMPILER_MSVC_VERSION >= 14 || (gsl_COMPILER_MSVC_VERSION >= 9 && _HAS_CPP0X)
-# define gsl_HAVE_CONTAINER_DATA_METHOD 1
-#endif
-
-#if gsl_CPP11_OR_GREATER || gsl_COMPILER_MSVC_VERSION >= 14
-# define gsl_HAVE_SIZED_TYPES 1
-#endif
-
-#if gsl_CPP11_OR_GREATER || gsl_COMPILER_MSVC_VERSION >= 14 || (gsl_COMPILER_MSVC_VERSION >= 10 && _HAS_CPP0X)
-# define gsl_HAVE_SHARED_PTR 1
-# define gsl_HAVE_UNIQUE_PTR 1
-#endif
-
-#if gsl_CPP14_OR_GREATER || gsl_COMPILER_MSVC_VERSION >= 12
-# define gsl_HAVE_MAKE_UNIQUE 1
-#endif
-
-#if gsl_CPP11_OR_GREATER || gsl_COMPILER_MSVC_VERSION >= 11
-# define gsl_HAVE_TYPE_TRAITS 1
-#endif
-
-#if gsl_HAVE_TYPE_TRAITS
-# define gsl_HAVE_ADD_CONST 1
-# define gsl_HAVE_INTEGRAL_CONSTANT 1
-# define gsl_HAVE_REMOVE_REFERENCE 1
-#elif gsl_HAVE_TR1_TYPE_TRAITS
-# define gsl_HAVE_TR1_ADD_CONST 1
-# define gsl_HAVE_TR1_INTEGRAL_CONSTANT 1
-# define gsl_HAVE_TR1_REMOVE_REFERENCE 1
-#endif
-
-// For the rest, consider VC12, VC14 as C++11 for GSL Lite:
-
-#if gsl_COMPILER_MSVC_VERSION >= 12
-# undef gsl_CPP11_OR_GREATER
-# define gsl_CPP11_OR_GREATER 1
-#endif
-
-// C++ feature usage:
-
-#if gsl_HAVE_CONSTEXPR_11
-# define gsl_constexpr constexpr
-#else
-# define gsl_constexpr /*constexpr*/
-#endif
-
-#if gsl_HAVE_CONSTEXPR_14
-# define gsl_constexpr14 constexpr
-#else
-# define gsl_constexpr14 /*constexpr*/
-#endif
-
-#if gsl_HAVE_EXPLICIT_CONVERSION
-# define gsl_explicit explicit
-#else
-# define gsl_explicit /*explicit*/
-#endif
-
-#if gsl_FEATURE_HAVE_IMPLICIT_MACRO
-# define implicit /*implicit*/
-#endif
-
-#if !gsl_HAVE_NOEXCEPT || gsl_CONFIG_CONTRACT_VIOLATION_THROWS_V
-# define gsl_noexcept /*noexcept*/
-#else
-# define gsl_noexcept noexcept
-#endif
-
-#if gsl_HAVE_NULLPTR
-# define gsl_nullptr nullptr
-#else
-# define gsl_nullptr NULL
-#endif
-
-#define gsl_DIMENSION_OF( a ) ( sizeof(a) / sizeof(0[a]) )
-
-// Other features:
-
-#if gsl_HAVE_DEFAULT_FUNCTION_TEMPLATE_ARG && gsl_HAVE_CONTAINER_DATA_METHOD
-# define gsl_HAVE_CONSTRAINED_SPAN_CONTAINER_CTOR 1
-#endif
-
-// Note: !defined(__NVCC__) doesn't work with nvcc here:
-#define gsl_HAVE_UNCONSTRAINED_SPAN_CONTAINER_CTOR \
- ( gsl_CONFIG_ALLOWS_UNCONSTRAINED_SPAN_CONTAINER_CTOR && (__NVCC__== 0) )
-
-// GSL API (e.g. for CUDA platform):
-
-#ifndef gsl_api
-# ifdef __CUDACC__
-# define gsl_api __host__ __device__
-# else
-# define gsl_api /*gsl_api*/
-# endif
-#endif
-
-// additional includes:
-
-#if gsl_HAVE_ARRAY
-# include <array>
-#endif
-
-#if gsl_HAVE_TYPE_TRAITS
-# include <type_traits>
-#elif gsl_HAVE_TR1_TYPE_TRAITS
-# include <tr1/type_traits>
-#endif
-
-#if gsl_HAVE_SIZED_TYPES
-# include <cstdint>
-#endif
-
-namespace gsl {
-
-namespace detail {
-
-// C++11 emulation:
-
-#if gsl_HAVE_ADD_CONST
-
-using std::add_const;
-
-#elif gsl_HAVE_TR1_ADD_CONST
-
-using std::tr1::add_const;
-
-#else
-
-template< class T > struct add_const { typedef const T type; };
-
-#endif // gsl_HAVE_ADD_CONST
-
-#if gsl_HAVE_REMOVE_CONST
-
-using std::remove_cv;
-using std::remove_const;
-using std::remove_volatile;
-
-#elif gsl_HAVE_TR1_REMOVE_CONST
-
-using std::tr1::remove_cv;
-using std::tr1::remove_const;
-using std::tr1::remove_volatile;
-
-#else
-
-template< class T > struct remove_const { typedef T type; };
-template< class T > struct remove_const<T const> { typedef T type; };
-
-template< class T > struct remove_volatile { typedef T type; };
-template< class T > struct remove_volatile<T volatile> { typedef T type; };
-
-template< class T >
-struct remove_cv
-{
- typedef typename detail::remove_volatile<typename detail::remove_const<T>::type>::type type;
-};
-
-#endif // gsl_HAVE_REMOVE_CONST
-
-#if gsl_HAVE_INTEGRAL_CONSTANT
-
-using std::integral_constant;
-using std::true_type;
-using std::false_type;
-
-#elif gsl_HAVE_TR1_INTEGRAL_CONSTANT
-
-using std::tr1::integral_constant;
-using std::tr1::true_type;
-using std::tr1::false_type;
-
-#else
-
-template< int v > struct integral_constant { enum { value = v }; };
-typedef integral_constant< true > true_type;
-typedef integral_constant< false > false_type;
-
-#endif
-
-#if gsl_HAVE_ARRAY
-
-template< class T >
-struct is_std_array_oracle : false_type {};
-
-template< class T, std::size_t N >
-struct is_std_array_oracle< std::array<T, N> > : true_type {};
-
-template< class T >
-struct is_std_array : is_std_array_oracle< typename remove_cv<T>::type > {};
-
-#endif
-
-} // namespace detail
-
-//
-// GSL.owner: ownership pointers
-//
-#if gsl_HAVE_SHARED_PTR
- using std::unique_ptr;
- using std::shared_ptr;
- using std::make_shared;
-# if gsl_HAVE_MAKE_UNIQUE
- using std::make_unique;
-# endif
-#endif
-
-#if gsl_HAVE_ALIAS_TEMPLATE
- template< class T > using owner = T;
-#else
- template< class T > struct owner { typedef T type; };
-#endif
-
-#define gsl_HAVE_OWNER_TEMPLATE gsl_HAVE_ALIAS_TEMPLATE
-
-#if gsl_FEATURE_HAVE_OWNER_MACRO
-# if gsl_HAVE_OWNER_TEMPLATE
-# define Owner(t) ::gsl::owner<t>
-# else
-# define Owner(t) ::gsl::owner<t>::type
-# endif
-#endif
-
-//
-// GSL.assert: assertions
-//
-
-#define gsl_ELIDE_CONTRACT_EXPECTS ( 0 == ( gsl_CONFIG_CONTRACT_LEVEL_MASK & 0x01 ) )
-#define gsl_ELIDE_CONTRACT_ENSURES ( 0 == ( gsl_CONFIG_CONTRACT_LEVEL_MASK & 0x10 ) )
-
-#if gsl_ELIDE_CONTRACT_EXPECTS
-# define Expects( x ) /* Expects elided */
-#elif gsl_CONFIG_CONTRACT_VIOLATION_THROWS_V
-# define Expects( x ) ::gsl::fail_fast_assert( (x), "GSL: Precondition failure at " __FILE__ ": " gsl_STRINGIFY(__LINE__) );
-#else
-# define Expects( x ) ::gsl::fail_fast_assert( (x) )
-#endif
-
-#if gsl_ELIDE_CONTRACT_ENSURES
-# define Ensures( x ) /* Ensures elided */
-#elif gsl_CONFIG_CONTRACT_VIOLATION_THROWS_V
-# define Ensures( x ) ::gsl::fail_fast_assert( (x), "GSL: Postcondition failure at " __FILE__ ": " gsl_STRINGIFY(__LINE__) );
-#else
-# define Ensures( x ) ::gsl::fail_fast_assert( (x) )
-#endif
-
-#define gsl_STRINGIFY( x ) gsl_STRINGIFY_( x )
-#define gsl_STRINGIFY_( x ) #x
-
-struct fail_fast : public std::logic_error
-{
- gsl_api explicit fail_fast( char const * const message )
- : std::logic_error( message ) {}
-};
-
-// workaround for gcc 5 throw/terminate constexpr bug:
-
-#if gsl_BETWEEN( gsl_COMPILER_GCC_VERSION, 430, 600 ) && gsl_HAVE_CONSTEXPR_14
-
-# if gsl_CONFIG_CONTRACT_VIOLATION_THROWS_V
-
-gsl_api inline gsl_constexpr14 auto fail_fast_assert( bool cond, char const * const message ) -> void
-{
- !cond ? throw fail_fast( message ) : 0;
-}
-
-# else
-
-gsl_api inline gsl_constexpr14 auto fail_fast_assert( bool cond ) -> void
-{
- struct F { static gsl_constexpr14 void f(){}; };
-
- !cond ? std::terminate() : F::f();
-}
-
-# endif
-
-#else // workaround
-
-# if gsl_CONFIG_CONTRACT_VIOLATION_THROWS_V
-
-gsl_api inline gsl_constexpr14 void fail_fast_assert( bool cond, char const * const message )
-{
- if ( !cond )
- throw fail_fast( message );
-}
-
-# else
-
-gsl_api inline gsl_constexpr14 void fail_fast_assert( bool cond )
-{
- if ( !cond )
- std::terminate();
-}
-
-# endif
-#endif // workaround
-
-//
-// GSL.util: utilities
-//
-
-#if gsl_CPP11_OR_GREATER || gsl_COMPILER_MSVC_VERSION == 11
-
-template< class F >
-class final_act
-{
-public:
- gsl_api explicit final_act( F action ) gsl_noexcept
- : action_( std::move( action ) )
- , invoke_( true )
- {}
-
- gsl_api final_act( final_act && other ) gsl_noexcept
- : action_( std::move( other.action_ ) )
- , invoke_( other.invoke_ )
- {
- other.invoke_ = false;
- }
-
-#if gsl_HAVE_IS_DELETE
- gsl_api final_act( final_act const & ) = delete;
- gsl_api final_act & operator=( final_act const & ) = delete;
-#else
-private:
- gsl_api final_act( final_act const & );
- gsl_api final_act & operator=( final_act const & );
-public:
-#endif
-
- gsl_api virtual ~final_act() gsl_noexcept
- {
- if ( invoke_ )
- action_();
- }
-
-protected:
- gsl_api void dismiss() gsl_noexcept
- {
- invoke_ = false;
- }
-
-#if gsl_CPP17_OR_GREATER
- gsl_api int uncaught_exceptions() gsl_noexcept
- {
- return std::uncaught_exceptions();
- }
-#else
- gsl_api int uncaught_exceptions()
- {
- return std::uncaught_exception() ? 1 : 0;
- }
-#endif
-
-private:
- F action_;
- bool invoke_;
-};
-
-template< class F >
-gsl_api inline final_act<F> finally( F const & action ) gsl_noexcept
-{
- return final_act<F>( action );
-}
-
-template< class F >
-gsl_api inline final_act<F> finally( F && action ) gsl_noexcept
-{
- return final_act<F>( std::forward<F>( action ) );
-}
-
-#if gsl_FEATURE_EXPERIMENTAL_RETURN_GUARD
-
-template< class F >
-class final_act_return : public final_act<F>
-{
-public:
- gsl_api explicit final_act_return( F && action ) gsl_noexcept
- : final_act<F>( std::move( action ) )
- {}
-
- gsl_api final_act_return( final_act_return && other ) gsl_noexcept
- : final_act<F>( std::move( other ) )
- {}
-
-#if gsl_HAVE_IS_DELETE
- gsl_api final_act_return( final_act_return const & ) = delete;
- gsl_api final_act_return & operator=( final_act_return const & ) = delete;
-#else
-private:
- gsl_api final_act_return( final_act_return const & );
- gsl_api final_act_return & operator=( final_act_return const & );
-public:
-#endif
-
- gsl_api ~final_act_return() override
- {
- if ( this->uncaught_exceptions() )
- this->dismiss();
- }
-};
-
-template< class F >
-gsl_api inline final_act_return<F> on_return( F const & action ) gsl_noexcept
-{
- return final_act_return<F>( action );
-}
-
-template< class F >
-gsl_api inline final_act_return<F> on_return( F && action ) gsl_noexcept
-{
- return final_act_return<F>( std::forward<F>( action ) );
-}
-
-template< class F >
-class final_act_error : public final_act<F>
-{
-public:
- gsl_api explicit final_act_error( F && action ) gsl_noexcept
- : final_act<F>( std::move( action ) )
- {}
-
- gsl_api final_act_error( final_act_error && other ) gsl_noexcept
- : final_act<F>( std::move( other ) )
- {}
-
-#if gsl_HAVE_IS_DELETE
- gsl_api final_act_error( final_act_error const & ) = delete;
- gsl_api final_act_error & operator=( final_act_error const & ) = delete;
-#else
-private:
- gsl_api final_act_error( final_act_error const & );
- gsl_api final_act_error & operator=( final_act_error const & );
-public:
-#endif
-
- gsl_api ~final_act_error() override
- {
- if ( ! this->uncaught_exceptions() )
- this->dismiss();
- }
-};
-
-template< class F >
-gsl_api inline final_act_error<F> on_error( F const & action ) gsl_noexcept
-{
- return final_act_error<F>( action );
-}
-
-template< class F >
-gsl_api inline final_act_error<F> on_error( F && action ) gsl_noexcept
-{
- return final_act_error<F>( std::forward<F>( action ) );
-}
-
-#endif // gsl_FEATURE_EXPERIMENTAL_RETURN_GUARD
-
-#else // gsl_CPP11_OR_GREATER || gsl_COMPILER_MSVC_VERSION == 11
-
-class final_act
-{
-public:
- typedef void (*Action)();
-
- gsl_api final_act( Action action )
- : action_( action )
- , invoke_( true )
- {}
-
- gsl_api final_act( final_act const & other )
- : action_( other.action_ )
- , invoke_( other.invoke_ )
- {
- other.invoke_ = false;
- }
-
- gsl_api virtual ~final_act()
- {
- if ( invoke_ )
- action_();
- }
-
-protected:
- gsl_api void dismiss()
- {
- invoke_ = false;
- }
-
- gsl_api int uncaught_exceptions()
- {
- return std::uncaught_exception() ? 1 : 0;
- }
-
-private:
- gsl_api final_act & operator=( final_act const & );
-
-private:
- Action action_;
- mutable bool invoke_;
-};
-
-template< class F >
-gsl_api inline final_act finally( F const & f )
-{
- return final_act(( f ));
-}
-
-#if gsl_FEATURE_EXPERIMENTAL_RETURN_GUARD
-
-class final_act_return : public final_act
-{
-public:
- gsl_api explicit final_act_return( Action action )
- : final_act( action )
- {}
-
- gsl_api ~final_act_return()
- {
- if ( this->uncaught_exceptions() )
- this->dismiss();
- }
-
-private:
- gsl_api final_act_return & operator=( final_act_return const & );
-};
-
-template< class F >
-gsl_api inline final_act_return on_return( F const & action )
-{
- return final_act_return( action );
-}
-
-class final_act_error : public final_act
-{
-public:
- gsl_api explicit final_act_error( Action action )
- : final_act( action )
- {}
-
- gsl_api ~final_act_error()
- {
- if ( ! this->uncaught_exceptions() )
- this->dismiss();
- }
-
-private:
- gsl_api final_act_error & operator=( final_act_error const & );
-};
-
-template< class F >
-gsl_api inline final_act_error on_error( F const & action )
-{
- return final_act_error( action );
-}
-
-#endif // gsl_FEATURE_EXPERIMENTAL_RETURN_GUARD
-
-#endif // gsl_CPP11_OR_GREATER || gsl_COMPILER_MSVC_VERSION == 11
-
-#if gsl_CPP11_OR_GREATER
-
-template< class T, class U >
-gsl_api inline gsl_constexpr T narrow_cast( U && u ) gsl_noexcept
-{
- return static_cast<T>( std::forward<U>( u ) );
-}
-
-#else
-
-template< class T, class U >
-gsl_api inline T narrow_cast( U u ) gsl_noexcept
-{
- return static_cast<T>( u );
-}
-
-#endif // gsl_CPP11_OR_GREATER
-
-struct narrowing_error : public std::exception {};
-
-#if gsl_HAVE_TYPE_TRAITS
-
-namespace details
-{
- template< class T, class U >
- struct is_same_signedness : public std::integral_constant<bool, std::is_signed<T>::value == std::is_signed<U>::value>
- {};
-}
-#endif
-
-template< class T, class U >
-gsl_api inline T narrow( U u )
-{
- T t = narrow_cast<T>( u );
-
- if ( static_cast<U>( t ) != u )
- {
-#if gsl_CONFIG_CONTRACT_VIOLATION_THROWS_V
- throw narrowing_error();
-#else
- std::terminate();
-#endif
- }
-
-#if gsl_HAVE_TYPE_TRAITS
- if ( ! details::is_same_signedness<T, U>::value && ( ( t < T() ) != ( u < U() ) ) )
-#else
- // Don't assume T() works:
- if ( ( t < 0 ) != ( u < 0 ) )
-#endif
- {
-#if gsl_CONFIG_CONTRACT_VIOLATION_THROWS_V
- throw narrowing_error();
-#else
- std::terminate();
-#endif
- }
- return t;
-}
-
-//
-// at() - Bounds-checked way of accessing static arrays, std::array, std::vector.
-//
-
-template< class T, size_t N >
-gsl_api inline gsl_constexpr14 T & at( T(&arr)[N], size_t index )
-{
- Expects( index < N );
- return arr[index];
-}
-
-#if gsl_HAVE_ARRAY
-
-template< class T, size_t N >
-gsl_api inline gsl_constexpr14 T & at( std::array<T, N> & arr, size_t index )
-{
- Expects( index < N );
- return arr[index];
-}
-#endif
-
-template< class Cont >
-gsl_api inline gsl_constexpr14 typename Cont::value_type & at( Cont & cont, size_t index )
-{
- Expects( index < cont.size() );
- return cont[index];
-}
-
-#if gsl_HAVE_INITIALIZER_LIST
-
-template< class T >
-gsl_api inline const gsl_constexpr14 T & at( std::initializer_list<T> cont, size_t index )
-{
- Expects( index < cont.size() );
- return *( cont.begin() + index );
-}
-#endif
-
-template< class T >
-class span;
-
-template< class T >
-gsl_api inline gsl_constexpr14 T & at( span<T> s, size_t index )
-{
- return s.at( index );
-}
-
-//
-// GSL.views: views
-//
-
-//
-// not_null<> - Wrap any indirection and enforce non-null.
-//
-template< class T >
-class not_null
-{
-public:
- gsl_api not_null( T t ) : ptr_ ( t ){ Expects( ptr_ != gsl_nullptr ); }
- gsl_api not_null & operator=( T const & t ) { ptr_ = t ; Expects( ptr_ != gsl_nullptr ); return *this; }
-
- gsl_api not_null( not_null const & other ) : ptr_ ( other.ptr_ ) {}
- gsl_api not_null & operator=( not_null const & other ) { ptr_ = other.ptr_; return *this; }
-
-#if gsl_HAVE_DEFAULT_FUNCTION_TEMPLATE_ARG
-
- template< class U, class Dummy =
- typename std::enable_if<std::is_convertible<U, T>::value, void>::type >
- gsl_api not_null( not_null<U> const & other ) : ptr_( other.get() ) {}
-
- template< class U, class Dummy =
- typename std::enable_if<std::is_convertible<U, T>::value, void>::type >
- gsl_api not_null & operator=( not_null<U> const & other )
- {
- ptr_ = other.get();
- return *this;
- }
-
-#else
-
- template< class U >
- gsl_api not_null( not_null<U> const & other ) : ptr_( other.get() ) {}
-
- template< class U >
- gsl_api not_null & operator=( not_null<U> const & other )
- {
- ptr_ = other.get();
- return *this;
- }
-#endif
-
-private:
- // Prevent compilation when initialized with a nullptr or literal 0:
-#if gsl_HAVE_NULLPTR
- gsl_api not_null( std::nullptr_t );
- gsl_api not_null & operator=( std::nullptr_t );
-#endif
- gsl_api not_null( int );
- gsl_api not_null & operator=( int );
-
-public:
- gsl_api T get() const
- {
-#if gsl_HAVE_NULLPTR && gsl_COMPILER_MSVC_VERSION > 0
- // The assume() should help the optimizer:
- __assume( ptr_ != nullptr );
-#endif
- return ptr_;
- }
-
- gsl_api operator T() const { return get(); }
- gsl_api T operator->() const { return get(); }
-
- gsl_api bool operator==(T const & rhs) const { return ptr_ == rhs; }
- gsl_api bool operator!=(T const & rhs) const { return !(*this == rhs); }
-
-private:
- T ptr_;
-
- gsl_api not_null & operator++();
- gsl_api not_null & operator--();
- gsl_api not_null operator++( int );
- gsl_api not_null operator--( int );
- gsl_api not_null & operator+ ( size_t );
- gsl_api not_null & operator+=( size_t );
- gsl_api not_null & operator- ( size_t );
- gsl_api not_null & operator-=( size_t );
-};
-
-//
-// Byte-specific type.
-//
-#if gsl_HAVE_ENUM_CLASS_CONSTRUCTION_FROM_UNDERLYING_TYPE
- enum class byte : unsigned char {};
-#else
- struct byte { typedef unsigned char type; type v; };
-#endif
-
-#if gsl_HAVE_DEFAULT_FUNCTION_TEMPLATE_ARG
-# define gsl_ENABLE_IF_INTEGRAL_T(T) \
- , class = typename std::enable_if<std::is_integral<T>::value>::type
-#else
-# define gsl_ENABLE_IF_INTEGRAL_T(T)
-#endif
-
-template< class T >
-gsl_api inline gsl_constexpr byte to_byte( T v ) gsl_noexcept
-{
-#if gsl_HAVE_ENUM_CLASS_CONSTRUCTION_FROM_UNDERLYING_TYPE
- static_assert( false, "Implement to_byte() using conversion from underlying type." );
-#elif gsl_HAVE_CONSTEXPR_11
- return { static_cast<typename byte::type>( v ) };
-#else
- byte b = { static_cast<typename byte::type>( v ) }; return b;
-#endif
-}
-
-template< class IntegerType gsl_ENABLE_IF_INTEGRAL_T( IntegerType ) >
-gsl_api inline gsl_constexpr IntegerType to_integer( byte b ) gsl_noexcept
-{
-#if gsl_HAVE_ENUM_CLASS_CONSTRUCTION_FROM_UNDERLYING_TYPE
- static_assert( false, "Implement to_integer() using conversion from underlying type." );
-#else
- return b.v;
-#endif
-}
-
-gsl_api inline gsl_constexpr unsigned char to_uchar( byte b ) gsl_noexcept
-{
- return to_integer<unsigned char>( b );
-}
-
-gsl_api inline gsl_constexpr unsigned char to_uchar( int i ) gsl_noexcept
-{
- return static_cast<unsigned char>( i );
-}
-
-#if ! gsl_HAVE_ENUM_CLASS_CONSTRUCTION_FROM_UNDERLYING_TYPE
-
-gsl_api inline gsl_constexpr bool operator==( byte l, byte r ) gsl_noexcept
-{
- return l.v == r.v;
-}
-
-gsl_api inline gsl_constexpr bool operator!=( byte l, byte r ) gsl_noexcept
-{
- return !( l == r );
-}
-
-gsl_api inline gsl_constexpr bool operator< ( byte l, byte r ) gsl_noexcept
-{
- return l.v < r.v;
-}
-
-gsl_api inline gsl_constexpr bool operator<=( byte l, byte r ) gsl_noexcept
-{
- return !( r < l );
-}
-
-gsl_api inline gsl_constexpr bool operator> ( byte l, byte r ) gsl_noexcept
-{
- return ( r < l );
-}
-
-gsl_api inline gsl_constexpr bool operator>=( byte l, byte r ) gsl_noexcept
-{
- return !( l < r );
-}
-#endif
-
-template< class IntegerType gsl_ENABLE_IF_INTEGRAL_T( IntegerType ) >
-gsl_api inline gsl_constexpr14 byte & operator<<=( byte & b, IntegerType shift ) gsl_noexcept
-{
-#if gsl_HAVE_ENUM_CLASS_CONSTRUCTION_FROM_UNDERLYING_TYPE
- return b = to_byte( to_uchar( b ) << shift );
-#else
- b.v = to_uchar( b.v << shift ); return b;
-#endif
-}
-
-template< class IntegerType gsl_ENABLE_IF_INTEGRAL_T( IntegerType ) >
-gsl_api inline gsl_constexpr byte operator<<( byte b, IntegerType shift ) gsl_noexcept
-{
- return to_byte( to_uchar( b ) << shift );
-}
-
-template< class IntegerType gsl_ENABLE_IF_INTEGRAL_T( IntegerType ) >
-gsl_api inline gsl_constexpr14 byte & operator>>=( byte & b, IntegerType shift ) gsl_noexcept
-{
-#if gsl_HAVE_ENUM_CLASS_CONSTRUCTION_FROM_UNDERLYING_TYPE
- return b = to_byte( to_uchar( b ) >> shift );
-#else
- b.v = to_uchar( b.v >> shift ); return b;
-#endif
-}
-
-template< class IntegerType gsl_ENABLE_IF_INTEGRAL_T( IntegerType ) >
-gsl_api inline gsl_constexpr byte operator>>( byte b, IntegerType shift ) gsl_noexcept
-{
- return to_byte( to_uchar( b ) >> shift );
-}
-
-gsl_api inline gsl_constexpr14 byte & operator|=( byte & l, byte r ) gsl_noexcept
-{
-#if gsl_HAVE_ENUM_CLASS_CONSTRUCTION_FROM_UNDERLYING_TYPE
- return l = to_byte( to_uchar( l ) | to_uchar( r ) );
-#else
- l.v = to_uchar( l ) | to_uchar( r ); return l;
-#endif
-}
-
-gsl_api inline gsl_constexpr byte operator|( byte l, byte r ) gsl_noexcept
-{
- return to_byte( to_uchar( l ) | to_uchar( r ) );
-}
-
-gsl_api inline gsl_constexpr14 byte & operator&=( byte & l, byte r ) gsl_noexcept
-{
-#if gsl_HAVE_ENUM_CLASS_CONSTRUCTION_FROM_UNDERLYING_TYPE
- return l = to_byte( to_uchar( l ) & to_uchar( r ) );
-#else
- l.v = to_uchar( l ) & to_uchar( r ); return l;
-#endif
-}
-
-gsl_api inline gsl_constexpr byte operator&( byte l, byte r ) gsl_noexcept
-{
- return to_byte( to_uchar( l ) & to_uchar( r ) );
-}
-
-gsl_api inline gsl_constexpr14 byte & operator^=( byte & l, byte r ) gsl_noexcept
-{
-#if gsl_HAVE_ENUM_CLASS_CONSTRUCTION_FROM_UNDERLYING_TYPE
- return l = to_byte( to_uchar( l ) ^ to_uchar (r ) );
-#else
- l.v = to_uchar( l ) ^ to_uchar (r ); return l;
-#endif
-}
-
-gsl_api inline gsl_constexpr byte operator^( byte l, byte r ) gsl_noexcept
-{
- return to_byte( to_uchar( l ) ^ to_uchar( r ) );
-}
-
-gsl_api inline gsl_constexpr byte operator~( byte b ) gsl_noexcept
-{
- return to_byte( ~to_uchar( b ) );
-}
-
-// tag to select span constructor taking a container
-struct with_container_t{ gsl_constexpr14 with_container_t(){} };
-const with_container_t with_container;
-
-//
-// span<> - A 1D view of contiguous T's, replace (*,len).
-//
-template< class T >
-class span
-{
- template< class U > friend class span;
-
-public:
- typedef gsl_CONFIG_SPAN_INDEX_TYPE index_type; // p0122r3 uses std::ptrdiff_t
-
- typedef T element_type;
- typedef T & reference;
- typedef T * pointer;
- typedef T const * const_pointer;
- typedef T const & const_reference;
-
- typedef pointer iterator;
- typedef const_pointer const_iterator;
+#pragma message ("gsl/gsl-lite.h is deprecated since version 0.27.0, use gsl/gsl-lite.hpp instead.")
- typedef std::reverse_iterator< iterator > reverse_iterator;
- typedef std::reverse_iterator< const_iterator > const_reverse_iterator;
-
- typedef typename std::iterator_traits< iterator >::difference_type difference_type;
-
- gsl_api gsl_constexpr14 span() gsl_noexcept
- : first_( gsl_nullptr )
- , last_ ( gsl_nullptr )
- {
- Expects( size() == 0 );
- }
-
-#if gsl_HAVE_NULLPTR
- gsl_api gsl_constexpr14 span( std::nullptr_t, index_type size_in )
- : first_( nullptr )
- , last_ ( nullptr )
- {
- Expects( size_in == 0 );
- }
-#endif
-
-#if gsl_HAVE_IS_DELETE
- gsl_api gsl_constexpr14 span( reference data_in )
- : span( &data_in, 1 )
- {}
-
- gsl_api gsl_constexpr14 span( element_type && ) = delete;
-#endif
-
- gsl_api gsl_constexpr14 span( pointer first_in, pointer last_in )
- : first_( first_in )
- , last_ ( last_in )
- {
- Expects( first_in <= last_in );
- }
-
- gsl_api gsl_constexpr14 span( pointer data_in, index_type size_in )
- : first_( data_in )
- , last_ ( data_in + size_in )
- {
- Expects( size_in == 0 || ( size_in > 0 && data_in != gsl_nullptr ) );
- }
-
- template< class U >
- gsl_api gsl_constexpr14 span( U * & data_in, index_type size_in )
- : first_( data_in )
- , last_ ( data_in + size_in )
- {
- Expects( size_in == 0 || ( size_in > 0 && data_in != gsl_nullptr ) );
- }
-
- template< class U >
- gsl_api gsl_constexpr14 span( U * const & data_in, index_type size_in )
- : first_( data_in )
- , last_ ( data_in + size_in )
- {
- Expects( size_in == 0 || ( size_in > 0 && data_in != gsl_nullptr ) );
- }
-
- template< class U, size_t N >
- gsl_api gsl_constexpr14 span( U (&arr)[N] )
- : first_( &arr[0] )
- , last_ ( &arr[0] + N )
- {}
-
-#if gsl_HAVE_ARRAY
- template< class U, size_t N >
- gsl_api gsl_constexpr14 span( std::array< U, N > & arr )
- : first_( arr.data() )
- , last_ ( arr.data() + N )
- {}
-
- template< class U, size_t N >
- gsl_api gsl_constexpr14 span( std::array< U, N > const & arr )
- : first_( arr.data() )
- , last_ ( arr.data() + N )
- {}
-#endif
-
-#if gsl_HAVE_CONSTRAINED_SPAN_CONTAINER_CTOR
- // SFINAE enable only if Cont has a data() member function
- template< class Cont, class = decltype(std::declval<Cont>().data()) >
- gsl_api gsl_constexpr14 span( Cont & cont )
- : first_( cont.data() )
- , last_ ( cont.data() + cont.size() )
- {}
-#elif gsl_HAVE_UNCONSTRAINED_SPAN_CONTAINER_CTOR
- template< class Cont >
- gsl_api gsl_constexpr14 span( Cont & cont )
- : first_( cont.size() == 0 ? gsl_nullptr : &cont[0] )
- , last_ ( cont.size() == 0 ? gsl_nullptr : &cont[0] + cont.size() )
- {}
-#endif
-
- template< class Cont >
- gsl_api gsl_constexpr14 span( with_container_t, Cont & cont )
- : first_( cont.size() == 0 ? gsl_nullptr : &cont[0] )
- , last_ ( cont.size() == 0 ? gsl_nullptr : &cont[0] + cont.size() )
- {}
-
-#if gsl_HAVE_SHARED_PTR
- gsl_api gsl_constexpr14 span( shared_ptr<element_type> const & ptr )
- : first_( ptr.get() )
- , last_ ( ptr.get() ? ptr.get() + 1 : 0 )
- {}
-#endif
-
-#if gsl_HAVE_UNIQUE_PTR
-# if gsl_HAVE_DEFAULT_FUNCTION_TEMPLATE_ARG
- template< class ArrayElementType = typename std::add_pointer<element_type>::type >
-# else
- template< class ArrayElementType >
-# endif
- gsl_api gsl_constexpr14 span( unique_ptr<ArrayElementType> const & ptr, index_type count )
- : first_( ptr.get() )
- , last_ ( ptr.get() + count )
- {}
-
- gsl_api gsl_constexpr14 span( unique_ptr<element_type> const & ptr )
- : first_( ptr.get() )
- , last_ ( ptr.get() ? ptr.get() + 1 : 0 )
- {}
-#endif
-
-#if gsl_HAVE_IS_DEFAULT && ! gsl_BETWEEN( gsl_COMPILER_GCC_VERSION, 430, 600)
- gsl_api gsl_constexpr14 span( span && ) = default;
- gsl_api gsl_constexpr14 span( span const & ) = default;
-#else
- gsl_api gsl_constexpr14 span( span const & other )
- : first_( other.begin() )
- , last_ ( other.end() )
- {}
-#endif
-
- template< class U >
- gsl_api gsl_constexpr14 span( span<U> const & other )
- : first_( other.begin() )
- , last_ ( other.end() )
- {}
-
-#if gsl_HAVE_IS_DEFAULT
- gsl_api span & operator=( span && ) = default;
- gsl_api span & operator=( span const & ) = default;
-#else
- gsl_api span & operator=( span other )
- {
- other.swap( *this );
- return *this;
- }
-#endif
-
-#if 0
- // Converting from other span ?
- template< class U > operator=();
-#endif
-
- gsl_api gsl_constexpr14 span first( index_type count ) const gsl_noexcept
- {
- Expects( count <= this->size() );
- return span( this->data(), count );
- }
-
- gsl_api gsl_constexpr14 span last( index_type count ) const gsl_noexcept
- {
- Expects( count <= this->size() );
- return span( this->data() + this->size() - count, count );
- }
-
- gsl_api gsl_constexpr14 span subspan( index_type offset ) const gsl_noexcept
- {
- Expects( offset <= this->size() );
- return span( this->data() + offset, this->length() - offset );
- }
-
- gsl_api gsl_constexpr14 span subspan( index_type offset, index_type count ) const gsl_noexcept
- {
- Expects( offset <= this->size() && count <= this->size() - offset );
- return span( this->data() + offset, count );
- }
-
- gsl_api gsl_constexpr14 iterator begin() const gsl_noexcept
- {
- return iterator( first_ );
- }
-
- gsl_api gsl_constexpr14 iterator end() const gsl_noexcept
- {
- return iterator( last_ );
- }
-
- gsl_api gsl_constexpr14 const_iterator cbegin() const gsl_noexcept
- {
- return const_iterator( begin() );
- }
-
- gsl_api gsl_constexpr14 const_iterator cend() const gsl_noexcept
- {
- return const_iterator( end() );
- }
-
- gsl_api gsl_constexpr14 reverse_iterator rbegin() const gsl_noexcept
- {
- return reverse_iterator( end() );
- }
-
- gsl_api gsl_constexpr14 reverse_iterator rend() const gsl_noexcept
- {
- return reverse_iterator( begin() );
- }
-
- gsl_api gsl_constexpr14 const_reverse_iterator crbegin() const gsl_noexcept
- {
- return const_reverse_iterator( cend() );
- }
-
- gsl_api gsl_constexpr14 const_reverse_iterator crend() const gsl_noexcept
- {
- return const_reverse_iterator( cbegin() );
- }
-
- gsl_api gsl_constexpr14 reference operator[]( index_type index ) const
- {
- return at( index );
- }
-
- gsl_api gsl_constexpr14 reference operator()( index_type index ) const
- {
- return at( index );
- }
-
- gsl_api gsl_constexpr14 reference at( index_type index ) const
- {
- Expects( index < size() );
- return first_[ index ];
- }
-
- gsl_api gsl_constexpr14 pointer data() const gsl_noexcept
- {
- return first_;
- }
-
- gsl_api gsl_constexpr14 bool empty() const gsl_noexcept
- {
- return size() == 0;
- }
-
- gsl_api gsl_constexpr14 index_type size() const gsl_noexcept
- {
- return narrow_cast<index_type>( last_ - first_ );
- }
-
- gsl_api gsl_constexpr14 index_type length() const gsl_noexcept
- {
- return size();
- }
-
- gsl_api gsl_constexpr14 index_type size_bytes() const gsl_noexcept
- {
- return size() * narrow_cast<index_type>( sizeof( element_type ) );
- }
-
- gsl_api gsl_constexpr14 index_type length_bytes() const gsl_noexcept
- {
- return size_bytes();
- }
-
- gsl_api void swap( span & other ) gsl_noexcept
- {
- using std::swap;
- swap( first_, other.first_ );
- swap( last_ , other.last_ );
- }
-
- // member as_bytes(), as_writeable_bytes deprecated since 0.17.0
-
- gsl_api span< const byte > as_bytes() const gsl_noexcept
- {
- return span< const byte >( reinterpret_cast<const byte *>( data() ), size_bytes() );
- }
-
- gsl_api span< byte > as_writeable_bytes() const gsl_noexcept
- {
- return span< byte >( reinterpret_cast<byte *>( data() ), size_bytes() );
- }
-
- template< class U >
- gsl_api span< U > as_span() const gsl_noexcept
- {
- Expects( ( this->size_bytes() % sizeof(U) ) == 0 );
- return span< U >( reinterpret_cast<U *>( this->data() ), this->size_bytes() / sizeof( U ) );
- }
-
-private:
- pointer first_;
- pointer last_;
-};
-
-// span comparison functions
-
-#if gsl_CONFIG_ALLOWS_NONSTRICT_SPAN_COMPARISON
-
-template< class T, class U >
-gsl_api inline gsl_constexpr14 bool operator==( span<T> const & l, span<U> const & r )
-{
- return l.size() == r.size()
- && (l.begin() == r.begin() || std::equal( l.begin(), l.end(), r.begin() ) );
-}
-
-template< class T, class U >
-gsl_api inline gsl_constexpr14 bool operator< ( span<T> const & l, span<U> const & r )
-{
- return std::lexicographical_compare( l.begin(), l.end(), r.begin(), r.end() );
-}
-
-#else
-
-template< class T >
-gsl_api inline gsl_constexpr14 bool operator==( span<T> const & l, span<T> const & r )
-{
- return l.size() == r.size()
- && (l.begin() == r.begin() || std::equal( l.begin(), l.end(), r.begin() ) );
-}
-
-template< class T >
-gsl_api inline gsl_constexpr14 bool operator< ( span<T> const & l, span<T> const & r )
-{
- return std::lexicographical_compare( l.begin(), l.end(), r.begin(), r.end() );
-}
-#endif
-
-template< class T, class U >
-gsl_api inline gsl_constexpr14 bool operator!=( span<T> const & l, span<U> const & r )
-{
- return !( l == r );
-}
-
-template< class T, class U >
-gsl_api inline gsl_constexpr14 bool operator<=( span<T> const & l, span<U> const & r )
-{
- return !( r < l );
-}
-
-template< class T, class U >
-gsl_api inline gsl_constexpr14 bool operator> ( span<T> const & l, span<U> const & r )
-{
- return ( r < l );
-}
-
-template< class T, class U >
-gsl_api inline gsl_constexpr14 bool operator>=( span<T> const & l, span<U> const & r )
-{
- return !( l < r );
-}
-
-// span algorithms
-
-namespace detail {
-
-template< class II, class N, class OI >
-gsl_api inline OI copy_n( II first, N count, OI result )
-{
- if ( count > 0 )
- {
- *result++ = *first;
- for ( N i = 1; i < count; ++i )
- {
- *result++ = *++first;
- }
- }
- return result;
-}
-}
-
-template< class T, class U >
-gsl_api inline void copy( span<T> src, span<U> dest )
-{
-#if gsl_CPP14_OR_GREATER // gsl_HAVE_TYPE_TRAITS (circumvent Travis clang 3.4)
- static_assert( std::is_assignable<U &, T const &>::value, "Cannot assign elements of source span to elements of destination span" );
-#endif
- Expects( dest.size() >= src.size() );
- detail::copy_n( src.data(), src.size(), dest.data() );
-}
-
-// span creator functions (see ctors)
-
-template< class T >
-gsl_api inline span< const byte > as_bytes( span<T> spn ) gsl_noexcept
-{
- return span< const byte >( reinterpret_cast<const byte *>( spn.data() ), spn.size_bytes() );
-}
-
-template< class T>
-gsl_api inline span< byte > as_writeable_bytes( span<T> spn ) gsl_noexcept
-{
- return span< byte >( reinterpret_cast<byte *>( spn.data() ), spn.size_bytes() );
-}
-
-template< class T >
-gsl_api inline gsl_constexpr14 span<T> make_span( T * first, T * last )
-{
- return span<T>( first, last );
-}
-
-template< class T >
-gsl_api inline gsl_constexpr14 span<T> make_span( T * ptr, typename span<T>::index_type count )
-{
- return span<T>( ptr, count );
-}
-
-template< class T, size_t N >
-gsl_api inline gsl_constexpr14 span<T> make_span( T (&arr)[N] )
-{
- return span<T>( &arr[0], N );
-}
-
-#if gsl_HAVE_ARRAY
-
-template< class T, size_t N >
-gsl_api inline gsl_constexpr14 span<T> make_span( std::array<T,N> & arr )
-{
- return span<T>( arr );
-}
-
-template< class T, size_t N >
-gsl_api inline gsl_constexpr14 span<const T> make_span( std::array<T,N> const & arr )
-{
- return span<const T>( arr );
-}
-#endif
-
-#if gsl_HAVE_CONSTRAINED_SPAN_CONTAINER_CTOR && gsl_HAVE_AUTO
-
-template< class Cont >
-gsl_api inline gsl_constexpr14 auto make_span( Cont & cont ) -> span< typename Cont::value_type >
-{
- return span< typename Cont::value_type >( cont );
-}
-
-template< class Cont >
-gsl_api inline gsl_constexpr14 auto make_span( Cont const & cont ) -> span< const typename Cont::value_type >
-{
- return span< const typename Cont::value_type >( cont );
-}
-
-#else
-
-template< class T >
-gsl_api inline span<T> make_span( std::vector<T> & cont )
-{
- return span<T>( with_container, cont );
-}
-
-template< class T >
-gsl_api inline span<const T> make_span( std::vector<T> const & cont )
-{
- return span<const T>( with_container, cont );
-}
-#endif
-
-template< class Ptr >
-gsl_api inline span<typename Ptr::element_type> make_span( Ptr & ptr )
-{
- return span<typename Ptr::element_type>( ptr );
-}
-
-template< class Ptr >
-span<typename Ptr::element_type> make_span( Ptr & ptr, typename span<typename Ptr::element_type>::index_type count )
-{
- return span<typename Ptr::element_type>( ptr, count);
-}
-
-//
-// basic_string_span:
-//
-
-template< class T >
-class basic_string_span;
-
-namespace detail {
-
-template< class T >
-struct is_basic_string_span_oracle : false_type {};
-
-template< class T >
-struct is_basic_string_span_oracle< basic_string_span<T> > : true_type {};
-
-template< class T >
-struct is_basic_string_span : is_basic_string_span_oracle< typename remove_cv<T>::type > {};
-
-template< class T >
-gsl_api inline gsl_constexpr14 std::size_t string_length( T * ptr, std::size_t max )
-{
- if ( ptr == gsl_nullptr || max <= 0 )
- return 0;
-
- std::size_t len = 0;
- while ( len < max && ptr[len] )
- ++len;
-
- return len;
-}
-
-} // namespace detail
-
-//
-// basic_string_span<> - A view of contiguous characters, replace (*,len).
-//
-template< class T >
-class basic_string_span
-{
-public:
- typedef T element_type;
- typedef span<T> span_type;
-
- typedef typename span_type::index_type index_type;
- typedef typename span_type::difference_type difference_type;
-
- typedef typename span_type::pointer pointer ;
- typedef typename span_type::reference reference ;
-
- typedef typename span_type::iterator iterator ;
- typedef typename span_type::const_iterator const_iterator ;
- typedef typename span_type::reverse_iterator reverse_iterator;
- typedef typename span_type::const_reverse_iterator const_reverse_iterator;
-
- // construction:
-
-#if gsl_HAVE_IS_DEFAULT
- gsl_api gsl_constexpr basic_string_span() gsl_noexcept = default;
-#else
- gsl_api gsl_constexpr basic_string_span() gsl_noexcept {}
-#endif
-
-#if gsl_HAVE_NULLPTR
- gsl_api gsl_constexpr basic_string_span( std::nullptr_t ptr ) gsl_noexcept
- : span_( ptr, 0 )
- {}
-#endif
-
- gsl_api gsl_constexpr basic_string_span( pointer ptr )
- : span_( remove_z( ptr, std::numeric_limits<index_type>::max() ) )
- {}
-
- gsl_api gsl_constexpr basic_string_span( pointer ptr, index_type count )
- : span_( ptr, count )
- {}
-
- gsl_api gsl_constexpr basic_string_span( pointer first, pointer last )
- : span_( first, last )
- {}
-
- template< std::size_t N >
- gsl_api gsl_constexpr basic_string_span( element_type (&arr)[N] )
- : span_( remove_z( &arr[0], N ) )
- {}
-
-#if gsl_HAVE_ARRAY
-
- template< std::size_t N >
- gsl_api gsl_constexpr basic_string_span( std::array< typename detail::remove_const<element_type>::type, N> & arr )
- : span_( remove_z( arr ) )
- {}
-
- template< std::size_t N >
- gsl_api gsl_constexpr basic_string_span( std::array< typename detail::remove_const<element_type>::type, N> const & arr )
- : span_( remove_z( arr ) )
- {}
-
-#endif
-
-#if gsl_HAVE_CONSTRAINED_SPAN_CONTAINER_CTOR
-
- // Exclude: array, [basic_string,] basic_string_span
-
- template<
- class Cont,
- class = typename std::enable_if<
- ! detail::is_std_array< Cont >::value
- && ! detail::is_basic_string_span< Cont >::value
- && std::is_convertible< typename Cont::pointer, pointer >::value
- && std::is_convertible< typename Cont::pointer, decltype(std::declval<Cont>().data()) >::value
- >::type
- >
- gsl_api gsl_constexpr basic_string_span( Cont & cont )
- : span_( ( cont ) )
- {}
-
- // Exclude: array, [basic_string,] basic_string_span
-
- template<
- class Cont,
- class = typename std::enable_if<
- ! detail::is_std_array< Cont >::value
- && ! detail::is_basic_string_span< Cont >::value
- && std::is_convertible< typename Cont::pointer, pointer >::value
- && std::is_convertible< typename Cont::pointer, decltype(std::declval<Cont>().data()) >::value
- >::type
- >
- gsl_api gsl_constexpr basic_string_span( Cont const & cont )
- : span_( ( cont ) )
- {}
-
-#elif gsl_HAVE_UNCONSTRAINED_SPAN_CONTAINER_CTOR
-
- template< class Cont >
- gsl_api gsl_constexpr basic_string_span( Cont & cont )
- : span_( cont )
- {}
-
- template< class Cont >
- gsl_api gsl_constexpr basic_string_span( Cont const & cont )
- : span_( cont )
- {}
-
-#else
-
- template< class U >
- gsl_api gsl_constexpr basic_string_span( span<U> const & rhs )
- : span_( rhs )
- {}
-
-#endif
-
- template< class Cont >
- gsl_api gsl_constexpr14 basic_string_span( with_container_t, Cont & cont )
- : span_( with_container, cont )
- {}
-
-#if gsl_HAVE_IS_DEFAULT
-# if gsl_BETWEEN( gsl_COMPILER_GCC_VERSION, 440, 600 )
- gsl_api gsl_constexpr basic_string_span( basic_string_span const & rhs ) = default;
-
- gsl_api gsl_constexpr basic_string_span( basic_string_span && rhs ) = default;
-# else
- gsl_api gsl_constexpr basic_string_span( basic_string_span const & rhs ) gsl_noexcept = default;
-
- gsl_api gsl_constexpr basic_string_span( basic_string_span && rhs ) gsl_noexcept = default;
-# endif
-#endif
-
- template< class U
-#if gsl_HAVE_DEFAULT_FUNCTION_TEMPLATE_ARG
- , class = typename std::enable_if< std::is_convertible<typename basic_string_span<U>::pointer, pointer>::value >::type
-#endif
- >
- gsl_api gsl_constexpr basic_string_span( basic_string_span<U> const & rhs )
- : span_( reinterpret_cast<pointer>( rhs.data() ), rhs.length() )
- {}
-
-#if gsl_CPP11_OR_GREATER
- template< class U
- , class = typename std::enable_if< std::is_convertible<typename basic_string_span<U>::pointer, pointer>::value >::type
- >
- gsl_api gsl_constexpr basic_string_span( basic_string_span<U> && rhs )
- : span_( reinterpret_cast<pointer>( rhs.data() ), rhs.length() )
- {}
-#endif
-
- template< class CharTraits, class Allocator >
- gsl_api gsl_constexpr basic_string_span(
- std::basic_string< typename detail::remove_const<element_type>::type, CharTraits, Allocator > & str )
- : span_( &str[0], str.length() )
- {}
-
- template< class CharTraits, class Allocator >
- gsl_api gsl_constexpr basic_string_span(
- std::basic_string< typename detail::remove_const<element_type>::type, CharTraits, Allocator > const & str )
- : span_( &str[0], str.length() )
- {}
-
- // destruction, assignment:
-
-#if gsl_HAVE_IS_DEFAULT
- gsl_api ~basic_string_span() gsl_noexcept = default;
-
- gsl_api basic_string_span & operator=( basic_string_span const & rhs ) gsl_noexcept = default;
-
- gsl_api basic_string_span & operator=( basic_string_span && rhs ) gsl_noexcept = default;
-#endif
-
- // sub span:
-
- gsl_api gsl_constexpr basic_string_span first( index_type count ) const
- {
- return span_.first( count );
- }
-
- gsl_api gsl_constexpr basic_string_span last( index_type count ) const
- {
- return span_.last( count );
- }
-
- gsl_api gsl_constexpr basic_string_span subspan( index_type offset ) const
- {
- return span_.subspan( offset );
- }
-
- gsl_api gsl_constexpr basic_string_span subspan( index_type offset, index_type count ) const
- {
- return span_.subspan( offset, count );
- }
-
- // observers:
-
- gsl_api gsl_constexpr index_type length() const gsl_noexcept
- {
- return span_.size();
- }
-
- gsl_api gsl_constexpr index_type size() const gsl_noexcept
- {
- return span_.size();
- }
-
- gsl_api gsl_constexpr index_type length_bytes() const gsl_noexcept
- {
- return span_.size_bytes();
- }
-
- gsl_api gsl_constexpr index_type size_bytes() const gsl_noexcept
- {
- return span_.size_bytes();
- }
-
- gsl_api gsl_constexpr bool empty() const gsl_noexcept
- {
- return size() == 0;
- }
-
- gsl_api gsl_constexpr reference operator[]( index_type idx ) const
- {
- return span_[idx];
- }
-
- gsl_api gsl_constexpr reference operator()( index_type idx ) const
- {
- return span_[idx];
- }
-
- gsl_api gsl_constexpr pointer data() const gsl_noexcept
- {
- return span_.data();
- }
-
- gsl_api iterator begin() const gsl_noexcept
- {
- return span_.begin();
- }
-
- gsl_api iterator end() const gsl_noexcept
- {
- return span_.end();
- }
-
- gsl_api reverse_iterator rbegin() const gsl_noexcept
- {
- return span_.rbegin();
- }
-
- gsl_api reverse_iterator rend() const gsl_noexcept
- {
- return span_.rend();
- }
-
- // const version not in p0123r2:
-
- gsl_api const_iterator cbegin() const gsl_noexcept
- {
- return span_.cbegin();
- }
-
- gsl_api const_iterator cend() const gsl_noexcept
- {
- return span_.cend();
- }
-
- gsl_api const_reverse_iterator crbegin() const gsl_noexcept
- {
- return span_.crbegin();
- }
-
- gsl_api const_reverse_iterator crend() const gsl_noexcept
- {
- return span_.crend();
- }
-
-private:
- gsl_api static gsl_constexpr14 span_type remove_z( pointer const & sz, std::size_t max )
- {
- return span_type( sz, detail::string_length( sz, max ) );
- }
-
-#if gsl_HAVE_ARRAY
- template< size_t N >
- gsl_api static gsl_constexpr14 span_type remove_z( std::array<typename detail::remove_const<element_type>::type, N> & arr )
- {
- return remove_z( &arr[0], narrow_cast< std::size_t >( N ) );
- }
-
- template< size_t N >
- gsl_api static gsl_constexpr14 span_type remove_z( std::array<typename detail::remove_const<element_type>::type, N> const & arr )
- {
- return remove_z( &arr[0], narrow_cast< std::size_t >( N ) );
- }
-#endif
-
-private:
- span_type span_;
-};
-
-// basic_string_span comparison functions:
-
-#if gsl_CONFIG_ALLOWS_NONSTRICT_SPAN_COMPARISON
-
-template< class T, class U >
-gsl_api inline gsl_constexpr14 bool operator==( basic_string_span<T> const & l, U const & u ) gsl_noexcept
-{
- basic_string_span< typename detail::add_const<T>::type > r( u );
-
- return l.size() == r.size()
- && std::equal( l.begin(), l.end(), r.begin() );
-}
-
-template< class T, class U >
-gsl_api inline gsl_constexpr14 bool operator<( basic_string_span<T> const & l, U const & u ) gsl_noexcept
-{
- basic_string_span< typename detail::add_const<T>::type > r( u );
-
- return std::lexicographical_compare( l.begin(), l.end(), r.begin(), r.end() );
-}
-
-#if gsl_HAVE_DEFAULT_FUNCTION_TEMPLATE_ARG
-
-template< class T, class U,
- class = typename std::enable_if<!detail::is_basic_string_span<U>::value >::type >
-gsl_api inline gsl_constexpr14 bool operator==( U const & u, basic_string_span<T> const & r ) gsl_noexcept
-{
- basic_string_span< typename detail::add_const<T>::type > l( u );
-
- return l.size() == r.size()
- && std::equal( l.begin(), l.end(), r.begin() );
-}
-
-template< class T, class U,
- class = typename std::enable_if<!detail::is_basic_string_span<U>::value >::type >
-gsl_api inline gsl_constexpr14 bool operator<( U const & u, basic_string_span<T> const & r ) gsl_noexcept
-{
- basic_string_span< typename detail::add_const<T>::type > l( u );
-
- return std::lexicographical_compare( l.begin(), l.end(), r.begin(), r.end() );
-}
-#endif
-
-#else //gsl_CONFIG_ALLOWS_NONSTRICT_SPAN_COMPARISON
-
-template< class T >
-gsl_api inline gsl_constexpr14 bool operator==( basic_string_span<T> const & l, basic_string_span<T> const & r ) gsl_noexcept
-{
- return l.size() == r.size()
- && std::equal( l.begin(), l.end(), r.begin() );
-}
-
-template< class T >
-gsl_api inline gsl_constexpr14 bool operator<( basic_string_span<T> const & l, basic_string_span<T> const & r ) gsl_noexcept
-{
- return std::lexicographical_compare( l.begin(), l.end(), r.begin(), r.end() );
-}
-
-#endif // gsl_CONFIG_ALLOWS_NONSTRICT_SPAN_COMPARISON
-
-template< class T, class U >
-gsl_api inline gsl_constexpr14 bool operator!=( basic_string_span<T> const & l, U const & r ) gsl_noexcept
-{
- return !( l == r );
-}
-
-template< class T, class U >
-gsl_api inline gsl_constexpr14 bool operator<=( basic_string_span<T> const & l, U const & r ) gsl_noexcept
-{
-#if gsl_HAVE_DEFAULT_FUNCTION_TEMPLATE_ARG || ! gsl_CONFIG_ALLOWS_NONSTRICT_SPAN_COMPARISON
- return !( r < l );
-#else
- basic_string_span< typename detail::add_const<T>::type > rr( r );
- return !( rr < l );
-#endif
-}
-
-template< class T, class U >
-gsl_api inline gsl_constexpr14 bool operator>( basic_string_span<T> const & l, U const & r ) gsl_noexcept
-{
-#if gsl_HAVE_DEFAULT_FUNCTION_TEMPLATE_ARG || ! gsl_CONFIG_ALLOWS_NONSTRICT_SPAN_COMPARISON
- return ( r < l );
-#else
- basic_string_span< typename detail::add_const<T>::type > rr( r );
- return ( rr < l );
-#endif
-}
-
-template< class T, class U >
-gsl_api inline gsl_constexpr14 bool operator>=( basic_string_span<T> const & l, U const & r ) gsl_noexcept
-{
- return !( l < r );
-}
-
-#if gsl_HAVE_DEFAULT_FUNCTION_TEMPLATE_ARG
-
-template< class T, class U,
- class = typename std::enable_if<!detail::is_basic_string_span<U>::value >::type >
-gsl_api inline gsl_constexpr14 bool operator!=( U const & l, basic_string_span<T> const & r ) gsl_noexcept
-{
- return !( l == r );
-}
-
-template< class T, class U,
- class = typename std::enable_if<!detail::is_basic_string_span<U>::value >::type >
-gsl_api inline gsl_constexpr14 bool operator<=( U const & l, basic_string_span<T> const & r ) gsl_noexcept
-{
- return !( r < l );
-}
-
-template< class T, class U,
- class = typename std::enable_if<!detail::is_basic_string_span<U>::value >::type >
-gsl_api inline gsl_constexpr14 bool operator>( U const & l, basic_string_span<T> const & r ) gsl_noexcept
-{
- return ( r < l );
-}
-
-template< class T, class U,
- class = typename std::enable_if<!detail::is_basic_string_span<U>::value >::type >
-gsl_api inline gsl_constexpr14 bool operator>=( U const & l, basic_string_span<T> const & r ) gsl_noexcept
-{
- return !( l < r );
-}
-
-#endif // gsl_HAVE_DEFAULT_FUNCTION_TEMPLATE_ARG
-
-// convert basic_string_span to byte span:
-
-template< class T >
-gsl_api inline span< const byte > as_bytes( basic_string_span<T> spn ) gsl_noexcept
-{
- return span< const byte >( reinterpret_cast<const byte *>( spn.data() ), spn.size_bytes() );
-}
-
-//
-// String types:
-//
-
-typedef char * zstring;
-typedef wchar_t * zwstring;
-typedef const char * czstring;
-typedef const wchar_t * cwzstring;
-
-typedef basic_string_span< char > string_span;
-typedef basic_string_span< wchar_t > wstring_span;
-typedef basic_string_span< char const > cstring_span;
-typedef basic_string_span< wchar_t const > cwstring_span;
-
-// to_string() allow (explicit) conversions from string_span to string
-
-#if 0
-
-template< class T >
-gsl_api inline std::basic_string< typename std::remove_const<T>::type > to_string( basic_string_span<T> spn )
-{
- std::string( spn.data(), spn.length() );
-}
-
-#else
-
-gsl_api inline std::string to_string( string_span const & spn )
-{
- return std::string( spn.data(), spn.length() );
-}
-
-gsl_api inline std::string to_string( cstring_span const & spn )
-{
- return std::string( spn.data(), spn.length() );
-}
-
-gsl_api inline std::wstring to_string( wstring_span const & spn )
-{
- return std::wstring( spn.data(), spn.length() );
-}
-
-gsl_api inline std::wstring to_string( cwstring_span const & spn )
-{
- return std::wstring( spn.data(), spn.length() );
-}
-
-#endif // to_string()
-
-//
-// Stream output for string_span types
-//
-
-namespace detail {
-
-template< class Stream >
-gsl_api void write_padding( Stream & os, std::streamsize n )
-{
- for ( std::streamsize i = 0; i < n; ++i )
- os.rdbuf()->sputc( os.fill() );
-}
-
-template< class Stream, class Span >
-gsl_api Stream & write_to_stream( Stream & os, Span const & spn )
-{
- typename Stream::sentry sentry( os );
-
- if ( !os )
- return os;
-
- std::streamsize length = narrow<std::streamsize>( spn.length() );
-
- // Whether, and how, to pad
- bool pad = ( length < os.width() );
- bool left_pad = pad && ( os.flags() & std::ios_base::adjustfield ) == std::ios_base::left;
-
- if ( left_pad )
- write_padding( os, os.width() - length );
-
- // Write span characters
- os.rdbuf()->sputn( spn.begin(), length );
-
- if ( pad && !left_pad )
- write_padding( os, os.width() - length );
-
- // Reset output stream width
- os.width(0);
-
- return os;
-}
-
-} // namespace detail
-
-template< typename Traits >
-gsl_api std::basic_ostream< char, Traits > & operator<<( std::basic_ostream< char, Traits > & os, string_span const & spn )
-{
- return detail::write_to_stream( os, spn );
-}
-
-template< typename Traits >
-gsl_api std::basic_ostream< char, Traits > & operator<<( std::basic_ostream< char, Traits > & os, cstring_span const & spn )
-{
- return detail::write_to_stream( os, spn );
-}
-
-template< typename Traits >
-gsl_api std::basic_ostream< wchar_t, Traits > & operator<<( std::basic_ostream< wchar_t, Traits > & os, wstring_span const & spn )
-{
- return detail::write_to_stream( os, spn );
-}
-
-template< typename Traits >
-gsl_api std::basic_ostream< wchar_t, Traits > & operator<<( std::basic_ostream< wchar_t, Traits > & os, cwstring_span const & spn )
-{
- return detail::write_to_stream( os, spn );
-}
-
-//
-// ensure_sentinel()
-//
-// Provides a way to obtain a span from a contiguous sequence
-// that ends with a (non-inclusive) sentinel value.
-//
-// Will fail-fast if sentinel cannot be found before max elements are examined.
-//
-namespace detail {
-
-template< class T, class SizeType, const T Sentinel >
-gsl_api static span<T> ensure_sentinel( T * seq, SizeType max = std::numeric_limits<SizeType>::max() )
-{
- typedef T * pointer;
-
- pointer cur = seq;
-
- while ( static_cast<SizeType>( cur - seq ) < max && *cur != Sentinel )
- ++cur;
-
- Expects( *cur == Sentinel );
-
- return span<T>( seq, narrow_cast< typename span<T>::index_type >( cur - seq ) );
-}
-} // namespace detail
-
-//
-// ensure_z - creates a string_span for a czstring or cwzstring.
-// Will fail fast if a null-terminator cannot be found before
-// the limit of size_type.
-//
-
-template< class T >
-gsl_api inline span<T> ensure_z( T * const & sz, size_t max = std::numeric_limits<size_t>::max() )
-{
- return detail::ensure_sentinel<T, size_t, 0>( sz, max );
-}
-
-template< class T, size_t N >
-gsl_api inline span<T> ensure_z( T (&sz)[N] )
-{
- return ensure_z( &sz[0], N );
-}
-
-# if gsl_HAVE_TYPE_TRAITS
-
-template< class Cont >
-gsl_api inline span< typename std::remove_pointer<typename Cont::pointer>::type >
-ensure_z( Cont & cont )
-{
- return ensure_z( cont.data(), cont.length() );
-}
-# endif
-
-} // namespace gsl
-
-#if gsl_CPP11_OR_GREATER
-
-namespace std {
-
-template<>
-struct hash< gsl::byte >
-{
-public:
- std::size_t operator()( gsl::byte v ) const gsl_noexcept
- {
- return gsl::to_integer<std::size_t>( v );
- }
-};
-
-} // namespace std
-
-#endif
+#include "gsl-lite.hpp"
#endif // GSL_GSL_LITE_H_INCLUDED
-
-// end of file
diff --git a/third_party/gsl/gsl-lite.hpp b/third_party/gsl/gsl-lite.hpp
new file mode 100644
index 0000000..21c114c
--- /dev/null
+++ b/third_party/gsl/gsl-lite.hpp
@@ -0,0 +1,5197 @@
+//
+// gsl-lite is based on GSL: Guidelines Support Library.
+// For more information see https://github.com/gsl-lite/gsl-lite
+//
+// Copyright (c) 2015-2019 Martin Moene
+// Copyright (c) 2019-2021 Moritz Beutel
+// Copyright (c) 2015-2018 Microsoft Corporation. All rights reserved.
+//
+// This code is licensed under the MIT License (MIT).
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#ifndef GSL_GSL_LITE_HPP_INCLUDED
+#define GSL_GSL_LITE_HPP_INCLUDED
+
+#include <exception> // for exception, terminate(), uncaught_exceptions()
+#include <limits>
+#include <memory> // for addressof(), unique_ptr<>, shared_ptr<>
+#include <iosfwd> // for basic_ostream<>
+#include <ios> // for ios_base, streamsize
+#include <stdexcept> // for logic_error
+#include <string>
+#include <utility> // for move(), forward<>(), swap()
+#include <cstddef> // for size_t, ptrdiff_t, nullptr_t
+
+#define gsl_lite_MAJOR 0
+#define gsl_lite_MINOR 38
+#define gsl_lite_PATCH 1
+
+#define gsl_lite_VERSION gsl_STRINGIFY(gsl_lite_MAJOR) "." gsl_STRINGIFY(gsl_lite_MINOR) "." gsl_STRINGIFY(gsl_lite_PATCH)
+
+#define gsl_STRINGIFY( x ) gsl_STRINGIFY_( x )
+#define gsl_STRINGIFY_( x ) #x
+#define gsl_CONCAT_( a, b ) gsl_CONCAT2_( a, b )
+#define gsl_CONCAT2_( a, b ) a##b
+#define gsl_EVALF_( f ) f()
+
+// configuration argument checking:
+
+#define gsl_DETAIL_CFG_TOGGLE_VALUE_1 1
+#define gsl_DETAIL_CFG_TOGGLE_VALUE_0 1
+#define gsl_DETAIL_CFG_DEFAULTS_VERSION_VALUE_1 1
+#define gsl_DETAIL_CFG_DEFAULTS_VERSION_VALUE_0 1
+#define gsl_DETAIL_CFG_STD_VALUE_98 1
+#define gsl_DETAIL_CFG_STD_VALUE_3 1
+#define gsl_DETAIL_CFG_STD_VALUE_03 1
+#define gsl_DETAIL_CFG_STD_VALUE_11 1
+#define gsl_DETAIL_CFG_STD_VALUE_14 1
+#define gsl_DETAIL_CFG_STD_VALUE_17 1
+#define gsl_DETAIL_CFG_STD_VALUE_20 1
+#define gsl_DETAIL_CFG_NO_VALUE_ 1
+#define gsl_DETAIL_CFG_NO_VALUE_1 1 // many compilers treat the command-line parameter "-Dfoo" as equivalent to "-Dfoo=1", so we tolerate that
+#define gsl_CHECK_CFG_TOGGLE_VALUE_( x ) gsl_CONCAT_( gsl_DETAIL_CFG_TOGGLE_VALUE_, x )
+#define gsl_CHECK_CFG_DEFAULTS_VERSION_VALUE_( x ) gsl_CONCAT_( gsl_DETAIL_CFG_DEFAULTS_VERSION_VALUE_, x )
+#define gsl_CHECK_CFG_STD_VALUE_( x ) gsl_CONCAT_( gsl_DETAIL_CFG_STD_VALUE_, x )
+#define gsl_CHECK_CFG_NO_VALUE_( x ) gsl_CONCAT_( gsl_DETAIL_CFG_NO_VALUE, gsl_CONCAT_( _, x ) )
+
+// gsl-lite backward compatibility:
+
+#if defined( gsl_CONFIG_DEFAULTS_VERSION )
+# if ! gsl_CHECK_CFG_DEFAULTS_VERSION_VALUE_( gsl_CONFIG_DEFAULTS_VERSION )
+# pragma message ("invalid configuration value gsl_CONFIG_DEFAULTS_VERSION=" gsl_STRINGIFY(gsl_CONFIG_DEFAULTS_VERSION) ", must be 0 or 1")
+# endif
+#else
+# define gsl_CONFIG_DEFAULTS_VERSION gsl_lite_MAJOR // default
+#endif
+# define gsl_CONFIG_DEFAULTS_VERSION_() gsl_CONFIG_DEFAULTS_VERSION
+
+#if defined( gsl_CONFIG_ALLOWS_SPAN_CONTAINER_CTOR )
+# if ! gsl_CHECK_CFG_TOGGLE_VALUE_( gsl_CONFIG_ALLOWS_SPAN_CONTAINER_CTOR )
+# pragma message ("invalid configuration value gsl_CONFIG_ALLOWS_SPAN_CONTAINER_CTOR=" gsl_STRINGIFY(gsl_CONFIG_ALLOWS_SPAN_CONTAINER_CTOR) ", must be 0 or 1")
+# endif
+# define gsl_CONFIG_ALLOWS_UNCONSTRAINED_SPAN_CONTAINER_CTOR gsl_CONFIG_ALLOWS_SPAN_CONTAINER_CTOR
+# pragma message ("gsl_CONFIG_ALLOWS_SPAN_CONTAINER_CTOR is deprecated since gsl-lite 0.7; replace with gsl_CONFIG_ALLOWS_UNCONSTRAINED_SPAN_CONTAINER_CTOR, or consider span(with_container, cont).")
+#endif
+
+#if defined( gsl_CONFIG_CONTRACT_LEVEL_ON )
+# if ! gsl_CHECK_CFG_NO_VALUE_( gsl_CONFIG_CONTRACT_LEVEL_ON )
+# pragma message ("invalid configuration value gsl_CONFIG_CONTRACT_LEVEL_ON=" gsl_STRINGIFY(gsl_CONFIG_CONTRACT_LEVEL_ON) "; macro must be defined without value")
+# endif
+# pragma message ("gsl_CONFIG_CONTRACT_LEVEL_ON is deprecated since gsl-lite 0.36; replace with gsl_CONFIG_CONTRACT_CHECKING_ON.")
+# define gsl_CONFIG_CONTRACT_CHECKING_ON
+#endif
+#if defined( gsl_CONFIG_CONTRACT_LEVEL_OFF )
+# if ! gsl_CHECK_CFG_NO_VALUE_( gsl_CONFIG_CONTRACT_LEVEL_OFF )
+# pragma message ("invalid configuration value gsl_CONFIG_CONTRACT_LEVEL_OFF=" gsl_STRINGIFY(gsl_CONFIG_CONTRACT_LEVEL_OFF) "; macro must be defined without value")
+# endif
+# pragma message ("gsl_CONFIG_CONTRACT_LEVEL_OFF is deprecated since gsl-lite 0.36; replace with gsl_CONFIG_CONTRACT_CHECKING_OFF.")
+# define gsl_CONFIG_CONTRACT_CHECKING_OFF
+#endif
+#if defined( gsl_CONFIG_CONTRACT_LEVEL_EXPECTS_ONLY )
+# if ! gsl_CHECK_CFG_NO_VALUE_( gsl_CONFIG_CONTRACT_LEVEL_EXPECTS_ONLY )
+# pragma message ("invalid configuration value gsl_CONFIG_CONTRACT_LEVEL_EXPECTS_ONLY=" gsl_STRINGIFY(gsl_CONFIG_CONTRACT_LEVEL_EXPECTS_ONLY) "; macro must be defined without value")
+# endif
+# pragma message ("gsl_CONFIG_CONTRACT_LEVEL_EXPECTS_ONLY is deprecated since gsl-lite 0.36; replace with gsl_CONFIG_CONTRACT_CHECKING_ENSURES_OFF and gsl_CONFIG_CONTRACT_CHECKING_ASSERT_OFF.")
+# define gsl_CONFIG_CONTRACT_CHECKING_ON
+# define gsl_CONFIG_CONTRACT_CHECKING_ENSURES_OFF
+# define gsl_CONFIG_CONTRACT_CHECKING_ASSERT_OFF
+#elif defined( gsl_CONFIG_CONTRACT_LEVEL_ENSURES_ONLY )
+# if ! gsl_CHECK_CFG_NO_VALUE_( gsl_CONFIG_CONTRACT_LEVEL_ENSURES_ONLY )
+# pragma message ("invalid configuration value gsl_CONFIG_CONTRACT_LEVEL_ENSURES_ONLY=" gsl_STRINGIFY(gsl_CONFIG_CONTRACT_LEVEL_ENSURES_ONLY) "; macro must be defined without value")
+# endif
+# pragma message ("gsl_CONFIG_CONTRACT_LEVEL_ENSURES_ONLY is deprecated since gsl-lite 0.36; replace with gsl_CONFIG_CONTRACT_CHECKING_EXPECTS_OFF and gsl_CONFIG_CONTRACT_CHECKING_ASSERT_OFF.")
+# define gsl_CONFIG_CONTRACT_CHECKING_ON
+# define gsl_CONFIG_CONTRACT_CHECKING_EXPECTS_OFF
+# define gsl_CONFIG_CONTRACT_CHECKING_ASSERT_OFF
+#endif
+
+// M-GSL compatibility:
+
+#if defined( GSL_THROW_ON_CONTRACT_VIOLATION )
+# if ! gsl_CHECK_CFG_NO_VALUE_( GSL_THROW_ON_CONTRACT_VIOLATION )
+# pragma message ("invalid configuration value GSL_THROW_ON_CONTRACT_VIOLATION=" gsl_STRINGIFY(GSL_THROW_ON_CONTRACT_VIOLATION) "; macro must be defined without value")
+# endif
+# define gsl_CONFIG_CONTRACT_VIOLATION_THROWS
+#endif
+
+#if defined( GSL_TERMINATE_ON_CONTRACT_VIOLATION )
+# if ! gsl_CHECK_CFG_NO_VALUE_( GSL_TERMINATE_ON_CONTRACT_VIOLATION )
+# pragma message ("invalid configuration value GSL_TERMINATE_ON_CONTRACT_VIOLATION=" gsl_STRINGIFY(GSL_TERMINATE_ON_CONTRACT_VIOLATION) "; macro must be defined without value")
+# endif
+# define gsl_CONFIG_CONTRACT_VIOLATION_TERMINATES
+#endif
+
+#if defined( GSL_UNENFORCED_ON_CONTRACT_VIOLATION )
+# if ! gsl_CHECK_CFG_NO_VALUE_( GSL_UNENFORCED_ON_CONTRACT_VIOLATION )
+# pragma message ("invalid configuration value GSL_UNENFORCED_ON_CONTRACT_VIOLATION=" gsl_STRINGIFY(GSL_UNENFORCED_ON_CONTRACT_VIOLATION) "; macro must be defined without value")
+# endif
+# define gsl_CONFIG_CONTRACT_CHECKING_OFF
+#endif
+
+// Configuration: Features
+
+#if defined( gsl_FEATURE_WITH_CONTAINER_TO_STD )
+# if ! gsl_CHECK_CFG_STD_VALUE_( gsl_FEATURE_WITH_CONTAINER_TO_STD )
+# pragma message ("invalid configuration value gsl_FEATURE_WITH_CONTAINER_TO_STD=" gsl_STRINGIFY(gsl_FEATURE_WITH_CONTAINER_TO_STD) ", must be 98, 3, 11, 14, 17, or 20")
+# endif
+#else
+# define gsl_FEATURE_WITH_CONTAINER_TO_STD 99 // default
+#endif
+#define gsl_FEATURE_WITH_CONTAINER_TO_STD_() gsl_FEATURE_WITH_CONTAINER_TO_STD
+
+#if defined( gsl_FEATURE_MAKE_SPAN_TO_STD )
+# if ! gsl_CHECK_CFG_STD_VALUE_( gsl_FEATURE_MAKE_SPAN_TO_STD )
+# pragma message ("invalid configuration value gsl_FEATURE_MAKE_SPAN_TO_STD=" gsl_STRINGIFY(gsl_FEATURE_MAKE_SPAN_TO_STD) ", must be 98, 3, 11, 14, 17, or 20")
+# endif
+#else
+# define gsl_FEATURE_MAKE_SPAN_TO_STD 99 // default
+#endif
+#define gsl_FEATURE_MAKE_SPAN_TO_STD_() gsl_FEATURE_MAKE_SPAN_TO_STD
+
+#if defined( gsl_FEATURE_BYTE_SPAN_TO_STD )
+# if ! gsl_CHECK_CFG_STD_VALUE_( gsl_FEATURE_BYTE_SPAN_TO_STD )
+# pragma message ("invalid configuration value gsl_FEATURE_BYTE_SPAN_TO_STD=" gsl_STRINGIFY(gsl_FEATURE_BYTE_SPAN_TO_STD) ", must be 98, 3, 11, 14, 17, or 20")
+# endif
+#else
+# define gsl_FEATURE_BYTE_SPAN_TO_STD 99 // default
+#endif
+#define gsl_FEATURE_BYTE_SPAN_TO_STD_() gsl_FEATURE_BYTE_SPAN_TO_STD
+
+#if defined( gsl_FEATURE_IMPLICIT_MACRO )
+# if ! gsl_CHECK_CFG_TOGGLE_VALUE_( gsl_FEATURE_IMPLICIT_MACRO )
+# pragma message ("invalid configuration value gsl_FEATURE_IMPLICIT_MACRO=" gsl_STRINGIFY(gsl_FEATURE_IMPLICIT_MACRO) ", must be 0 or 1")
+# endif
+#else
+# define gsl_FEATURE_IMPLICIT_MACRO 0 // default
+#endif
+#define gsl_FEATURE_IMPLICIT_MACRO_() gsl_FEATURE_IMPLICIT_MACRO
+
+#if defined( gsl_FEATURE_OWNER_MACRO )
+# if ! gsl_CHECK_CFG_TOGGLE_VALUE_( gsl_FEATURE_OWNER_MACRO )
+# pragma message ("invalid configuration value gsl_FEATURE_OWNER_MACRO=" gsl_STRINGIFY(gsl_FEATURE_OWNER_MACRO) ", must be 0 or 1")
+# endif
+#else
+# define gsl_FEATURE_OWNER_MACRO (gsl_CONFIG_DEFAULTS_VERSION == 0) // default
+#endif
+#define gsl_FEATURE_OWNER_MACRO_() gsl_FEATURE_OWNER_MACRO
+
+#if defined( gsl_FEATURE_EXPERIMENTAL_RETURN_GUARD )
+# if ! gsl_CHECK_CFG_TOGGLE_VALUE_( gsl_FEATURE_EXPERIMENTAL_RETURN_GUARD )
+# pragma message ("invalid configuration value gsl_FEATURE_EXPERIMENTAL_RETURN_GUARD=" gsl_STRINGIFY(gsl_FEATURE_EXPERIMENTAL_RETURN_GUARD) ", must be 0 or 1")
+# endif
+#else
+# define gsl_FEATURE_EXPERIMENTAL_RETURN_GUARD 0 // default
+#endif
+# define gsl_FEATURE_EXPERIMENTAL_RETURN_GUARD_() gsl_FEATURE_EXPERIMENTAL_RETURN_GUARD
+
+#if defined( gsl_FEATURE_GSL_LITE_NAMESPACE )
+# if ! gsl_CHECK_CFG_TOGGLE_VALUE_( gsl_FEATURE_GSL_LITE_NAMESPACE )
+# pragma message ("invalid configuration value gsl_FEATURE_GSL_LITE_NAMESPACE=" gsl_STRINGIFY(gsl_FEATURE_GSL_LITE_NAMESPACE) ", must be 0 or 1")
+# endif
+#else
+# define gsl_FEATURE_GSL_LITE_NAMESPACE (gsl_CONFIG_DEFAULTS_VERSION >= 1) // default
+#endif
+#define gsl_FEATURE_GSL_LITE_NAMESPACE_() gsl_FEATURE_GSL_LITE_NAMESPACE
+
+// Configuration: Other
+
+#if defined( gsl_CONFIG_TRANSPARENT_NOT_NULL )
+# if ! gsl_CHECK_CFG_TOGGLE_VALUE_( gsl_CONFIG_TRANSPARENT_NOT_NULL )
+# pragma message ("invalid configuration value gsl_CONFIG_TRANSPARENT_NOT_NULL=" gsl_STRINGIFY(gsl_CONFIG_TRANSPARENT_NOT_NULL) ", must be 0 or 1")
+# endif
+# if gsl_CONFIG_TRANSPARENT_NOT_NULL && defined( gsl_CONFIG_NOT_NULL_GET_BY_CONST_REF )
+# error configuration option gsl_CONFIG_NOT_NULL_GET_BY_CONST_REF is meaningless if gsl_CONFIG_TRANSPARENT_NOT_NULL=1
+# endif
+#else
+# define gsl_CONFIG_TRANSPARENT_NOT_NULL (gsl_CONFIG_DEFAULTS_VERSION >= 1) // default
+#endif
+# define gsl_CONFIG_TRANSPARENT_NOT_NULL_() gsl_CONFIG_TRANSPARENT_NOT_NULL
+
+#if ! defined( gsl_CONFIG_DEPRECATE_TO_LEVEL )
+# if gsl_CONFIG_DEFAULTS_VERSION >= 1
+# define gsl_CONFIG_DEPRECATE_TO_LEVEL 6
+# else
+# define gsl_CONFIG_DEPRECATE_TO_LEVEL 0
+# endif
+#endif
+
+#if ! defined( gsl_CONFIG_SPAN_INDEX_TYPE )
+# define gsl_CONFIG_SPAN_INDEX_TYPE std::size_t
+#endif
+# define gsl_CONFIG_SPAN_INDEX_TYPE_() gsl_CONFIG_SPAN_INDEX_TYPE
+
+#if ! defined( gsl_CONFIG_INDEX_TYPE )
+# if gsl_CONFIG_DEFAULTS_VERSION >= 1
+// p0122r3 uses std::ptrdiff_t
+# define gsl_CONFIG_INDEX_TYPE std::ptrdiff_t
+# else
+# define gsl_CONFIG_INDEX_TYPE gsl_CONFIG_SPAN_INDEX_TYPE
+# endif
+#endif
+# define gsl_CONFIG_INDEX_TYPE_() gsl_CONFIG_INDEX_TYPE
+
+#if defined( gsl_CONFIG_NOT_NULL_EXPLICIT_CTOR )
+# if ! gsl_CHECK_CFG_TOGGLE_VALUE_( gsl_CONFIG_NOT_NULL_EXPLICIT_CTOR )
+# pragma message ("invalid configuration value gsl_CONFIG_NOT_NULL_EXPLICIT_CTOR=" gsl_STRINGIFY(gsl_CONFIG_NOT_NULL_EXPLICIT_CTOR) ", must be 0 or 1")
+# endif
+#else
+# define gsl_CONFIG_NOT_NULL_EXPLICIT_CTOR (gsl_CONFIG_DEFAULTS_VERSION >= 1) // default
+#endif
+#define gsl_CONFIG_NOT_NULL_EXPLICIT_CTOR_() gsl_CONFIG_NOT_NULL_EXPLICIT_CTOR
+
+#if defined( gsl_CONFIG_NOT_NULL_GET_BY_CONST_REF )
+# if ! gsl_CHECK_CFG_TOGGLE_VALUE_( gsl_CONFIG_NOT_NULL_GET_BY_CONST_REF )
+# pragma message ("invalid configuration value gsl_CONFIG_NOT_NULL_GET_BY_CONST_REF=" gsl_STRINGIFY(gsl_CONFIG_NOT_NULL_GET_BY_CONST_REF) ", must be 0 or 1")
+# endif
+#else
+# define gsl_CONFIG_NOT_NULL_GET_BY_CONST_REF 0 // default
+#endif
+#define gsl_CONFIG_NOT_NULL_GET_BY_CONST_REF_() gsl_CONFIG_NOT_NULL_GET_BY_CONST_REF
+
+#if defined( gsl_CONFIG_CONFIRMS_COMPILATION_ERRORS )
+# if ! gsl_CHECK_CFG_TOGGLE_VALUE_( gsl_CONFIG_CONFIRMS_COMPILATION_ERRORS )
+# pragma message ("invalid configuration value gsl_CONFIG_CONFIRMS_COMPILATION_ERRORS=" gsl_STRINGIFY(gsl_CONFIG_CONFIRMS_COMPILATION_ERRORS) ", must be 0 or 1")
+# endif
+#else
+# define gsl_CONFIG_CONFIRMS_COMPILATION_ERRORS 0 // default
+#endif
+#define gsl_CONFIG_CONFIRMS_COMPILATION_ERRORS_() gsl_CONFIG_CONFIRMS_COMPILATION_ERRORS
+
+#if defined( gsl_CONFIG_ALLOWS_SPAN_COMPARISON )
+# if ! gsl_CHECK_CFG_TOGGLE_VALUE_( gsl_CONFIG_ALLOWS_SPAN_COMPARISON )
+# pragma message ("invalid configuration value gsl_CONFIG_ALLOWS_SPAN_COMPARISON=" gsl_STRINGIFY(gsl_CONFIG_ALLOWS_SPAN_COMPARISON) ", must be 0 or 1")
+# endif
+#else
+# define gsl_CONFIG_ALLOWS_SPAN_COMPARISON (gsl_CONFIG_DEFAULTS_VERSION == 0) // default
+#endif
+#define gsl_CONFIG_ALLOWS_SPAN_COMPARISON_() gsl_CONFIG_ALLOWS_SPAN_COMPARISON
+
+#if defined( gsl_CONFIG_ALLOWS_NONSTRICT_SPAN_COMPARISON )
+# if ! gsl_CHECK_CFG_TOGGLE_VALUE_( gsl_CONFIG_ALLOWS_NONSTRICT_SPAN_COMPARISON )
+# pragma message ("invalid configuration value gsl_CONFIG_ALLOWS_NONSTRICT_SPAN_COMPARISON=" gsl_STRINGIFY(gsl_CONFIG_ALLOWS_NONSTRICT_SPAN_COMPARISON) ", must be 0 or 1")
+# endif
+#else
+# define gsl_CONFIG_ALLOWS_NONSTRICT_SPAN_COMPARISON 1 // default
+#endif
+#define gsl_CONFIG_ALLOWS_NONSTRICT_SPAN_COMPARISON_() gsl_CONFIG_ALLOWS_NONSTRICT_SPAN_COMPARISON
+
+#if defined( gsl_CONFIG_ALLOWS_UNCONSTRAINED_SPAN_CONTAINER_CTOR )
+# if ! gsl_CHECK_CFG_TOGGLE_VALUE_( gsl_CONFIG_ALLOWS_UNCONSTRAINED_SPAN_CONTAINER_CTOR )
+# pragma message ("invalid configuration value gsl_CONFIG_ALLOWS_UNCONSTRAINED_SPAN_CONTAINER_CTOR=" gsl_STRINGIFY(gsl_CONFIG_ALLOWS_UNCONSTRAINED_SPAN_CONTAINER_CTOR) ", must be 0 or 1")
+# endif
+#else
+# define gsl_CONFIG_ALLOWS_UNCONSTRAINED_SPAN_CONTAINER_CTOR 0 // default
+#endif
+#define gsl_CONFIG_ALLOWS_UNCONSTRAINED_SPAN_CONTAINER_CTOR_() gsl_CONFIG_ALLOWS_UNCONSTRAINED_SPAN_CONTAINER_CTOR
+
+#if defined( gsl_CONFIG_NARROW_THROWS_ON_TRUNCATION )
+# if ! gsl_CHECK_CFG_TOGGLE_VALUE_( gsl_CONFIG_NARROW_THROWS_ON_TRUNCATION )
+# pragma message ("invalid configuration value gsl_CONFIG_NARROW_THROWS_ON_TRUNCATION=" gsl_STRINGIFY(gsl_CONFIG_NARROW_THROWS_ON_TRUNCATION) ", must be 0 or 1")
+# endif
+#else
+# define gsl_CONFIG_NARROW_THROWS_ON_TRUNCATION (gsl_CONFIG_DEFAULTS_VERSION >= 1) // default
+#endif
+#define gsl_CONFIG_NARROW_THROWS_ON_TRUNCATION_() gsl_CONFIG_NARROW_THROWS_ON_TRUNCATION
+
+#if defined( gsl_CONFIG_CONTRACT_CHECKING_EXPECTS_OFF )
+# if ! gsl_CHECK_CFG_NO_VALUE_( gsl_CONFIG_CONTRACT_CHECKING_EXPECTS_OFF )
+# pragma message ("invalid configuration value gsl_CONFIG_CONTRACT_CHECKING_EXPECTS_OFF=" gsl_STRINGIFY(gsl_CONFIG_CONTRACT_CHECKING_EXPECTS_OFF) "; macro must be defined without value")
+# endif
+#endif
+#if defined( gsl_CONFIG_CONTRACT_CHECKING_ENSURES_OFF )
+# if ! gsl_CHECK_CFG_NO_VALUE_( gsl_CONFIG_CONTRACT_CHECKING_ENSURES_OFF )
+# pragma message ("invalid configuration value gsl_CONFIG_CONTRACT_CHECKING_ENSURES_OFF=" gsl_STRINGIFY(gsl_CONFIG_CONTRACT_CHECKING_ENSURES_OFF) "; macro must be defined without value")
+# endif
+#endif
+#if defined( gsl_CONFIG_CONTRACT_CHECKING_ASSERT_OFF )
+# if ! gsl_CHECK_CFG_NO_VALUE_( gsl_CONFIG_CONTRACT_CHECKING_ASSERT_OFF )
+# pragma message ("invalid configuration value gsl_CONFIG_CONTRACT_CHECKING_ASSERT_OFF=" gsl_STRINGIFY(gsl_CONFIG_CONTRACT_CHECKING_ASSERT_OFF) "; macro must be defined without value")
+# endif
+#endif
+#if defined( gsl_CONFIG_CONTRACT_CHECKING_AUDIT )
+# if ! gsl_CHECK_CFG_NO_VALUE_( gsl_CONFIG_CONTRACT_CHECKING_AUDIT )
+# pragma message ("invalid configuration value gsl_CONFIG_CONTRACT_CHECKING_AUDIT=" gsl_STRINGIFY(gsl_CONFIG_CONTRACT_CHECKING_AUDIT) "; macro must be defined without value")
+# endif
+#endif
+#if defined( gsl_CONFIG_CONTRACT_CHECKING_ON )
+# if ! gsl_CHECK_CFG_NO_VALUE_( gsl_CONFIG_CONTRACT_CHECKING_ON )
+# pragma message ("invalid configuration value gsl_CONFIG_CONTRACT_CHECKING_ON=" gsl_STRINGIFY(gsl_CONFIG_CONTRACT_CHECKING_ON) "; macro must be defined without value")
+# endif
+#endif
+#if defined( gsl_CONFIG_CONTRACT_CHECKING_OFF )
+# if ! gsl_CHECK_CFG_NO_VALUE_( gsl_CONFIG_CONTRACT_CHECKING_OFF )
+# pragma message ("invalid configuration value gsl_CONFIG_CONTRACT_CHECKING_OFF=" gsl_STRINGIFY(gsl_CONFIG_CONTRACT_CHECKING_OFF) "; macro must be defined without value")
+# endif
+#endif
+#if defined( gsl_CONFIG_CONTRACT_VIOLATION_THROWS )
+# if ! gsl_CHECK_CFG_NO_VALUE_( gsl_CONFIG_CONTRACT_VIOLATION_THROWS )
+# pragma message ("invalid configuration value gsl_CONFIG_CONTRACT_VIOLATION_THROWS=" gsl_STRINGIFY(gsl_CONFIG_CONTRACT_VIOLATION_THROWS) "; macro must be defined without value")
+# endif
+#endif
+#if defined( gsl_CONFIG_CONTRACT_VIOLATION_TERMINATES )
+# if ! gsl_CHECK_CFG_NO_VALUE_( gsl_CONFIG_CONTRACT_VIOLATION_TERMINATES )
+# pragma message ("invalid configuration value gsl_CONFIG_CONTRACT_VIOLATION_TERMINATES=" gsl_STRINGIFY(gsl_CONFIG_CONTRACT_VIOLATION_TERMINATES) "; macro must be defined without value")
+# endif
+#endif
+#if defined( gsl_CONFIG_CONTRACT_VIOLATION_ASSERTS )
+# if ! gsl_CHECK_CFG_NO_VALUE_( gsl_CONFIG_CONTRACT_VIOLATION_ASSERTS )
+# pragma message ("invalid configuration value gsl_CONFIG_CONTRACT_VIOLATION_ASSERTS=" gsl_STRINGIFY(gsl_CONFIG_CONTRACT_VIOLATION_ASSERTS) "; macro must be defined without value")
+# endif
+#endif
+#if defined( gsl_CONFIG_CONTRACT_VIOLATION_TRAPS )
+# if ! gsl_CHECK_CFG_NO_VALUE_( gsl_CONFIG_CONTRACT_VIOLATION_TRAPS )
+# pragma message ("invalid configuration value gsl_CONFIG_CONTRACT_VIOLATION_TRAPS=" gsl_STRINGIFY(gsl_CONFIG_CONTRACT_VIOLATION_TRAPS) "; macro must be defined without value")
+# endif
+#endif
+#if defined( gsl_CONFIG_CONTRACT_VIOLATION_CALLS_HANDLER )
+# if ! gsl_CHECK_CFG_NO_VALUE_( gsl_CONFIG_CONTRACT_VIOLATION_CALLS_HANDLER )
+# pragma message ("invalid configuration value gsl_CONFIG_CONTRACT_VIOLATION_CALLS_HANDLER=" gsl_STRINGIFY(gsl_CONFIG_CONTRACT_VIOLATION_CALLS_HANDLER) "; macro must be defined without value")
+# endif
+#endif
+#if defined( gsl_CONFIG_UNENFORCED_CONTRACTS_ASSUME )
+# if ! gsl_CHECK_CFG_NO_VALUE_( gsl_CONFIG_UNENFORCED_CONTRACTS_ASSUME )
+# pragma message ("invalid configuration value gsl_CONFIG_UNENFORCED_CONTRACTS_ASSUME=" gsl_STRINGIFY(gsl_CONFIG_UNENFORCED_CONTRACTS_ASSUME) "; macro must be defined without value")
+# endif
+#endif
+#if defined( gsl_CONFIG_UNENFORCED_CONTRACTS_ELIDE )
+# if ! gsl_CHECK_CFG_NO_VALUE_( gsl_CONFIG_UNENFORCED_CONTRACTS_ELIDE )
+# pragma message ("invalid configuration value gsl_CONFIG_UNENFORCED_CONTRACTS_ELIDE=" gsl_STRINGIFY(gsl_CONFIG_UNENFORCED_CONTRACTS_ELIDE) "; macro must be defined without value")
+# endif
+#endif
+
+#if 1 < defined( gsl_CONFIG_CONTRACT_CHECKING_AUDIT ) + defined( gsl_CONFIG_CONTRACT_CHECKING_ON ) + defined( gsl_CONFIG_CONTRACT_CHECKING_OFF )
+# error only one of gsl_CONFIG_CONTRACT_CHECKING_AUDIT, gsl_CONFIG_CONTRACT_CHECKING_ON, and gsl_CONFIG_CONTRACT_CHECKING_OFF may be defined
+#endif
+#if 1 < defined( gsl_CONFIG_CONTRACT_VIOLATION_THROWS ) + defined( gsl_CONFIG_CONTRACT_VIOLATION_TERMINATES ) + defined( gsl_CONFIG_CONTRACT_VIOLATION_ASSERTS ) + defined( gsl_CONFIG_CONTRACT_VIOLATION_TRAPS ) + defined( gsl_CONFIG_CONTRACT_VIOLATION_CALLS_HANDLER )
+# error only one of gsl_CONFIG_CONTRACT_VIOLATION_THROWS, gsl_CONFIG_CONTRACT_VIOLATION_TERMINATES, gsl_CONFIG_CONTRACT_VIOLATION_ASSERTS, gsl_CONFIG_CONTRACT_VIOLATION_TRAPS, and gsl_CONFIG_CONTRACT_VIOLATION_CALLS_HANDLER may be defined
+#endif
+#if 1 < defined( gsl_CONFIG_UNENFORCED_CONTRACTS_ASSUME ) + defined( gsl_CONFIG_UNENFORCED_CONTRACTS_ELIDE )
+# error only one of gsl_CONFIG_UNENFORCED_CONTRACTS_ASSUME and gsl_CONFIG_UNENFORCED_CONTRACTS_ELIDE may be defined
+#endif
+
+#if 0 == defined( gsl_CONFIG_CONTRACT_CHECKING_AUDIT ) + defined( gsl_CONFIG_CONTRACT_CHECKING_ON ) + defined( gsl_CONFIG_CONTRACT_CHECKING_OFF )
+// select default
+# define gsl_CONFIG_CONTRACT_CHECKING_ON
+#endif
+#if 0 == defined( gsl_CONFIG_CONTRACT_VIOLATION_THROWS ) + defined( gsl_CONFIG_CONTRACT_VIOLATION_TERMINATES ) + defined( gsl_CONFIG_CONTRACT_VIOLATION_ASSERTS ) + defined( gsl_CONFIG_CONTRACT_VIOLATION_TRAPS ) + defined( gsl_CONFIG_CONTRACT_VIOLATION_CALLS_HANDLER )
+// select default
+# define gsl_CONFIG_CONTRACT_VIOLATION_TERMINATES
+#endif
+#if 0 == defined( gsl_CONFIG_UNENFORCED_CONTRACTS_ASSUME ) + defined( gsl_CONFIG_UNENFORCED_CONTRACTS_ELIDE )
+// select default
+# define gsl_CONFIG_UNENFORCED_CONTRACTS_ELIDE
+#endif
+
+// C++ language version detection (C++20 is speculative):
+// Note: VC14.0/1900 (VS2015) lacks too much from C++14.
+
+#ifndef gsl_CPLUSPLUS
+# if defined(_MSVC_LANG ) && !defined(__clang__)
+# define gsl_CPLUSPLUS (_MSC_VER == 1900 ? 201103L : _MSVC_LANG )
+# else
+# define gsl_CPLUSPLUS __cplusplus
+# endif
+#endif
+
+// C++ standard library version:
+
+#ifndef gsl_CPLUSPLUS_STDLIB
+# define gsl_CPLUSPLUS_STDLIB gsl_CPLUSPLUS
+#endif
+
+#define gsl_CPP98_OR_GREATER ( gsl_CPLUSPLUS >= 199711L )
+#define gsl_CPP11_OR_GREATER ( gsl_CPLUSPLUS >= 201103L )
+#define gsl_CPP14_OR_GREATER ( gsl_CPLUSPLUS >= 201402L )
+#define gsl_CPP17_OR_GREATER ( gsl_CPLUSPLUS >= 201703L )
+#define gsl_CPP20_OR_GREATER ( gsl_CPLUSPLUS >= 202000L )
+
+// C++ language version (represent 98 as 3):
+
+#define gsl_CPLUSPLUS_V ( gsl_CPLUSPLUS / 100 - (gsl_CPLUSPLUS > 200000 ? 2000 : 1994) )
+
+// half-open range [lo..hi):
+#define gsl_BETWEEN( v, lo, hi ) ( (lo) <= (v) && (v) < (hi) )
+
+// Compiler versions:
+
+// MSVC++ 6.0 _MSC_VER == 1200 gsl_COMPILER_MSVC_VERSION == 60 (Visual Studio 6.0)
+// MSVC++ 7.0 _MSC_VER == 1300 gsl_COMPILER_MSVC_VERSION == 70 (Visual Studio .NET 2002)
+// MSVC++ 7.1 _MSC_VER == 1310 gsl_COMPILER_MSVC_VERSION == 71 (Visual Studio .NET 2003)
+// MSVC++ 8.0 _MSC_VER == 1400 gsl_COMPILER_MSVC_VERSION == 80 (Visual Studio 2005)
+// MSVC++ 9.0 _MSC_VER == 1500 gsl_COMPILER_MSVC_VERSION == 90 (Visual Studio 2008)
+// MSVC++ 10.0 _MSC_VER == 1600 gsl_COMPILER_MSVC_VERSION == 100 (Visual Studio 2010)
+// MSVC++ 11.0 _MSC_VER == 1700 gsl_COMPILER_MSVC_VERSION == 110 (Visual Studio 2012)
+// MSVC++ 12.0 _MSC_VER == 1800 gsl_COMPILER_MSVC_VERSION == 120 (Visual Studio 2013)
+// MSVC++ 14.0 _MSC_VER == 1900 gsl_COMPILER_MSVC_VERSION == 140 (Visual Studio 2015)
+// MSVC++ 14.1 _MSC_VER >= 1910 gsl_COMPILER_MSVC_VERSION == 141 (Visual Studio 2017)
+// MSVC++ 14.2 _MSC_VER >= 1920 gsl_COMPILER_MSVC_VERSION == 142 (Visual Studio 2019)
+
+#if defined( _MSC_VER ) && ! defined( __clang__ )
+# define gsl_COMPILER_MSVC_VER (_MSC_VER )
+# define gsl_COMPILER_MSVC_VERSION (_MSC_VER / 10 - 10 * ( 5 + (_MSC_VER < 1900 ) ) )
+# define gsl_COMPILER_MSVC_VERSION_FULL (_MSC_VER - 100 * ( 5 + (_MSC_VER < 1900 ) ) )
+#else
+# define gsl_COMPILER_MSVC_VER 0
+# define gsl_COMPILER_MSVC_VERSION 0
+# define gsl_COMPILER_MSVC_VERSION_FULL 0
+#endif
+
+#define gsl_COMPILER_VERSION( major, minor, patch ) ( 10 * ( 10 * (major) + (minor) ) + (patch) )
+
+// AppleClang 7.0.0 __apple_build_version__ == 7000172 gsl_COMPILER_APPLECLANG_VERSION == 700 (Xcode 7.0, 7.0.1) (LLVM 3.7.0)
+// AppleClang 7.0.0 __apple_build_version__ == 7000176 gsl_COMPILER_APPLECLANG_VERSION == 700 (Xcode 7.1) (LLVM 3.7.0)
+// AppleClang 7.0.2 __apple_build_version__ == 7000181 gsl_COMPILER_APPLECLANG_VERSION == 702 (Xcode 7.2, 7.2.1) (LLVM 3.7.0)
+// AppleClang 7.3.0 __apple_build_version__ == 7030029 gsl_COMPILER_APPLECLANG_VERSION == 730 (Xcode 7.3) (LLVM 3.8.0)
+// AppleClang 7.3.0 __apple_build_version__ == 7030031 gsl_COMPILER_APPLECLANG_VERSION == 730 (Xcode 7.3.1) (LLVM 3.8.0)
+// AppleClang 8.0.0 __apple_build_version__ == 8000038 gsl_COMPILER_APPLECLANG_VERSION == 800 (Xcode 8.0) (LLVM 3.9.0)
+// AppleClang 8.0.0 __apple_build_version__ == 8000042 gsl_COMPILER_APPLECLANG_VERSION == 800 (Xcode 8.1, 8.2, 8.2.1) (LLVM 3.9.0)
+// AppleClang 8.1.0 __apple_build_version__ == 8020038 gsl_COMPILER_APPLECLANG_VERSION == 810 (Xcode 8.3) (LLVM 3.9.0)
+// AppleClang 8.1.0 __apple_build_version__ == 8020041 gsl_COMPILER_APPLECLANG_VERSION == 810 (Xcode 8.3.1) (LLVM 3.9.0)
+// AppleClang 8.1.0 __apple_build_version__ == 8020042 gsl_COMPILER_APPLECLANG_VERSION == 810 (Xcode 8.3.2, 8.3.3) (LLVM 3.9.0)
+// AppleClang 9.0.0 __apple_build_version__ == 9000037 gsl_COMPILER_APPLECLANG_VERSION == 900 (Xcode 9.0) (LLVM 4.0.0)
+// AppleClang 9.0.0 __apple_build_version__ == 9000038 gsl_COMPILER_APPLECLANG_VERSION == 900 (Xcode 9.1) (LLVM 4.0.0)
+// AppleClang 9.0.0 __apple_build_version__ == 9000039 gsl_COMPILER_APPLECLANG_VERSION == 900 (Xcode 9.2) (LLVM 4.0.0)
+// AppleClang 9.1.0 __apple_build_version__ == 9020039 gsl_COMPILER_APPLECLANG_VERSION == 910 (Xcode 9.3, 9.3.1) (LLVM 5.0.2)
+// AppleClang 9.1.0 __apple_build_version__ == 9020039 gsl_COMPILER_APPLECLANG_VERSION == 910 (Xcode 9.4, 9.4.1) (LLVM 5.0.2)
+// AppleClang 10.0.0 __apple_build_version__ == 10001145 gsl_COMPILER_APPLECLANG_VERSION == 1000 (Xcode 10.0, 10.1) (LLVM 6.0.1)
+// AppleClang 10.0.1 __apple_build_version__ == 10010046 gsl_COMPILER_APPLECLANG_VERSION == 1001 (Xcode 10.2, 10.2.1, 10.3) (LLVM 7.0.0)
+// AppleClang 11.0.0 __apple_build_version__ == 11000033 gsl_COMPILER_APPLECLANG_VERSION == 1100 (Xcode 11.1, 11.2, 11.3, 11.3.1) (LLVM 8.0.0)
+// AppleClang 11.0.3 __apple_build_version__ == 11030032 gsl_COMPILER_APPLECLANG_VERSION == 1103 (Xcode 11.4, 11.4.1, 11.5, 11.6) (LLVM 9.0.0)
+// AppleClang 12.0.0 __apple_build_version__ == 12000032 gsl_COMPILER_APPLECLANG_VERSION == 1200 (Xcode 12.0–12.4) (LLVM 10.0.0)
+// AppleClang 12.0.5 __apple_build_version__ == 12050022 gsl_COMPILER_APPLECLANG_VERSION == 1205 (Xcode 12.5) (LLVM 10.0.0)
+
+#if defined( __apple_build_version__ )
+# define gsl_COMPILER_APPLECLANG_VERSION gsl_COMPILER_VERSION( __clang_major__, __clang_minor__, __clang_patchlevel__ )
+# define gsl_COMPILER_CLANG_VERSION 0
+#elif defined( __clang__ )
+# define gsl_COMPILER_APPLECLANG_VERSION 0
+# define gsl_COMPILER_CLANG_VERSION gsl_COMPILER_VERSION( __clang_major__, __clang_minor__, __clang_patchlevel__ )
+#else
+# define gsl_COMPILER_APPLECLANG_VERSION 0
+# define gsl_COMPILER_CLANG_VERSION 0
+#endif
+
+#if defined( __GNUC__ ) && ! defined( __clang__ )
+# define gsl_COMPILER_GNUC_VERSION gsl_COMPILER_VERSION( __GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__ )
+#else
+# define gsl_COMPILER_GNUC_VERSION 0
+#endif
+
+#if defined( __NVCC__ )
+# define gsl_COMPILER_NVCC_VERSION ( __CUDACC_VER_MAJOR__ * 10 + __CUDACC_VER_MINOR__ )
+#else
+# define gsl_COMPILER_NVCC_VERSION 0
+#endif
+
+#if defined( __ARMCC_VERSION )
+# define gsl_COMPILER_ARMCC_VERSION ( __ARMCC_VERSION / 10000 )
+# define gsl_COMPILER_ARMCC_VERSION_FULL __ARMCC_VERSION
+#else
+# define gsl_COMPILER_ARMCC_VERSION 0
+# define gsl_COMPILER_ARMCC_VERSION_FULL 0
+#endif
+
+// Compiler non-strict aliasing:
+
+#if defined(__clang__) || defined(__GNUC__)
+# define gsl_may_alias __attribute__((__may_alias__))
+#else
+# define gsl_may_alias
+#endif
+
+// Presence of gsl, language and library features:
+
+#define gsl_IN_STD( v ) ( ((v) == 98 ? 3 : (v)) >= gsl_CPLUSPLUS_V )
+
+#define gsl_DEPRECATE_TO_LEVEL( level ) ( level <= gsl_CONFIG_DEPRECATE_TO_LEVEL )
+#define gsl_FEATURE_TO_STD( feature ) gsl_IN_STD( gsl_FEATURE( feature##_TO_STD ) )
+#define gsl_FEATURE( feature ) gsl_EVALF_( gsl_FEATURE_##feature##_ )
+#define gsl_CONFIG( feature ) gsl_EVALF_( gsl_CONFIG_##feature##_ )
+#define gsl_HAVE( feature ) gsl_EVALF_( gsl_HAVE_##feature##_ )
+
+// Presence of wide character support:
+
+#ifdef __DJGPP__
+# define gsl_HAVE_WCHAR 0
+#else
+# define gsl_HAVE_WCHAR 1
+#endif
+#define gsl_HAVE_WCHAR_() gsl_HAVE_WCHAR
+
+// Presence of language & library features:
+
+#if gsl_COMPILER_CLANG_VERSION || gsl_COMPILER_APPLECLANG_VERSION
+# ifdef __OBJC__
+ // There are a bunch of inconsistencies about __EXCEPTIONS and __has_feature(cxx_exceptions) in Clang 3.4/3.5/3.6.
+ // We're interested in C++ exceptions, which can be checked by __has_feature(cxx_exceptions) in 3.5+.
+ // In pre-3.5, __has_feature(cxx_exceptions) can be true if ObjC exceptions are enabled, but C++ exceptions are disabled.
+ // The recommended way to check is `__EXCEPTIONS && __has_feature(cxx_exceptions)`.
+ // See https://releases.llvm.org/3.6.0/tools/clang/docs/ReleaseNotes.html#the-exceptions-macro
+ // Note: this is only relevant in Objective-C++, thus the ifdef.
+# if __EXCEPTIONS && __has_feature(cxx_exceptions)
+# define gsl_HAVE_EXCEPTIONS 1
+# else
+# define gsl_HAVE_EXCEPTIONS 0
+# endif // __EXCEPTIONS && __has_feature(cxx_exceptions)
+# else
+ // clang-cl doesn't define __EXCEPTIONS for MSVC compatibility (see https://reviews.llvm.org/D4065).
+ // Neither does Clang in MS-compatiblity mode.
+ // Let's hope no one tries to build Objective-C++ code using MS-compatibility mode or clang-cl.
+# if __has_feature(cxx_exceptions)
+# define gsl_HAVE_EXCEPTIONS 1
+# else
+# define gsl_HAVE_EXCEPTIONS 0
+# endif
+# endif
+#elif gsl_COMPILER_GNUC_VERSION
+# if gsl_BETWEEN(gsl_COMPILER_GNUC_VERSION, 1, 500)
+# ifdef __EXCEPTIONS
+# define gsl_HAVE_EXCEPTIONS 1
+# else
+# define gsl_HAVE_EXCEPTIONS 0
+# endif // __EXCEPTIONS
+# else
+# ifdef __cpp_exceptions
+# define gsl_HAVE_EXCEPTIONS 1
+# else
+# define gsl_HAVE_EXCEPTIONS 0
+# endif // __cpp_exceptions
+# endif // gsl_BETWEEN(gsl_COMPILER_GNUC_VERSION, 1, 500)
+#elif gsl_COMPILER_MSVC_VERSION
+# ifdef _CPPUNWIND
+# define gsl_HAVE_EXCEPTIONS 1
+# else
+# define gsl_HAVE_EXCEPTIONS 0
+# endif // _CPPUNWIND
+#else
+// For all other compilers, assume exceptions are always enabled.
+# define gsl_HAVE_EXCEPTIONS 1
+#endif
+#define gsl_HAVE_EXCEPTIONS_() gsl_HAVE_EXCEPTIONS
+
+#if defined( gsl_CONFIG_CONTRACT_VIOLATION_THROWS ) && ! gsl_HAVE_EXCEPTIONS
+# error Cannot use gsl_CONFIG_CONTRACT_VIOLATION_THROWS if exceptions are disabled.
+#endif // defined( gsl_CONFIG_CONTRACT_VIOLATION_THROWS ) && !gsl_HAVE( EXCEPTIONS )
+
+#ifdef _HAS_CPP0X
+# define gsl_HAS_CPP0X _HAS_CPP0X
+#else
+# define gsl_HAS_CPP0X 0
+#endif
+
+#define gsl_CPP11_100 (gsl_CPP11_OR_GREATER || gsl_COMPILER_MSVC_VER >= 1600)
+#define gsl_CPP11_110 (gsl_CPP11_OR_GREATER || gsl_COMPILER_MSVC_VER >= 1700)
+#define gsl_CPP11_120 (gsl_CPP11_OR_GREATER || gsl_COMPILER_MSVC_VER >= 1800)
+#define gsl_CPP11_140 (gsl_CPP11_OR_GREATER || gsl_COMPILER_MSVC_VER >= 1900)
+
+#define gsl_CPP14_000 (gsl_CPP14_OR_GREATER)
+#define gsl_CPP14_120 (gsl_CPP14_OR_GREATER || gsl_COMPILER_MSVC_VER >= 1800)
+#define gsl_CPP14_140 (gsl_CPP14_OR_GREATER || gsl_COMPILER_MSVC_VER >= 1900)
+
+#define gsl_CPP17_000 (gsl_CPP17_OR_GREATER)
+#define gsl_CPP17_140 (gsl_CPP17_OR_GREATER || gsl_COMPILER_MSVC_VER >= 1900)
+
+#define gsl_CPP11_140_CPP0X_90 (gsl_CPP11_140 || (gsl_COMPILER_MSVC_VER >= 1500 && gsl_HAS_CPP0X))
+#define gsl_CPP11_140_CPP0X_100 (gsl_CPP11_140 || (gsl_COMPILER_MSVC_VER >= 1600 && gsl_HAS_CPP0X))
+
+// Presence of C++11 language features:
+
+#define gsl_HAVE_C99_PREPROCESSOR gsl_CPP11_140
+#define gsl_HAVE_AUTO gsl_CPP11_100
+#define gsl_HAVE_RVALUE_REFERENCE gsl_CPP11_100
+#define gsl_HAVE_FUNCTION_REF_QUALIFIER ( gsl_CPP11_140 && ! gsl_BETWEEN( gsl_COMPILER_GNUC_VERSION, 1, 481 ) )
+#define gsl_HAVE_ENUM_CLASS gsl_CPP11_110
+#define gsl_HAVE_ALIAS_TEMPLATE gsl_CPP11_120
+#define gsl_HAVE_DEFAULT_FUNCTION_TEMPLATE_ARG gsl_CPP11_120
+#define gsl_HAVE_EXPLICIT gsl_CPP11_120
+#define gsl_HAVE_VARIADIC_TEMPLATE gsl_CPP11_120
+#define gsl_HAVE_IS_DELETE gsl_CPP11_120
+#define gsl_HAVE_CONSTEXPR_11 gsl_CPP11_140
+#define gsl_HAVE_IS_DEFAULT gsl_CPP11_140
+#define gsl_HAVE_NOEXCEPT gsl_CPP11_140
+#define gsl_HAVE_NORETURN ( gsl_CPP11_140 && ! gsl_BETWEEN( gsl_COMPILER_GNUC_VERSION, 1, 480 ) )
+#define gsl_HAVE_EXPRESSION_SFINAE gsl_CPP11_140
+#define gsl_HAVE_OVERRIDE_FINAL gsl_CPP11_110
+
+#define gsl_HAVE_C99_PREPROCESSOR_() gsl_HAVE_C99_PREPROCESSOR
+#define gsl_HAVE_AUTO_() gsl_HAVE_AUTO
+#define gsl_HAVE_RVALUE_REFERENCE_() gsl_HAVE_RVALUE_REFERENCE
+#define gsl_HAVE_FUNCTION_REF_QUALIFIER_() gsl_HAVE_FUNCTION_REF_QUALIFIER
+#define gsl_HAVE_ENUM_CLASS_() gsl_HAVE_ENUM_CLASS
+#define gsl_HAVE_ALIAS_TEMPLATE_() gsl_HAVE_ALIAS_TEMPLATE
+#define gsl_HAVE_DEFAULT_FUNCTION_TEMPLATE_ARG_() gsl_HAVE_DEFAULT_FUNCTION_TEMPLATE_ARG
+#define gsl_HAVE_EXPLICIT_() gsl_HAVE_EXPLICIT
+#define gsl_HAVE_VARIADIC_TEMPLATE_() gsl_HAVE_VARIADIC_TEMPLATE
+#define gsl_HAVE_IS_DELETE_() gsl_HAVE_IS_DELETE
+#define gsl_HAVE_CONSTEXPR_11_() gsl_HAVE_CONSTEXPR_11
+#define gsl_HAVE_IS_DEFAULT_() gsl_HAVE_IS_DEFAULT
+#define gsl_HAVE_NOEXCEPT_() gsl_HAVE_NOEXCEPT
+#define gsl_HAVE_NORETURN_() gsl_HAVE_NORETURN
+#define gsl_HAVE_EXPRESSION_SFINAE_() gsl_HAVE_EXPRESSION_SFINAE
+#define gsl_HAVE_OVERRIDE_FINAL_() gsl_HAVE_OVERRIDE_FINAL
+
+// Presence of C++14 language features:
+
+#define gsl_HAVE_CONSTEXPR_14 ( gsl_CPP14_000 && ! gsl_BETWEEN( gsl_COMPILER_GNUC_VERSION, 1, 600 ) )
+#define gsl_HAVE_DECLTYPE_AUTO gsl_CPP14_140
+#define gsl_HAVE_DEPRECATED ( gsl_CPP14_140 && ! gsl_BETWEEN( gsl_COMPILER_MSVC_VERSION, 1, 142 ) )
+
+#define gsl_HAVE_CONSTEXPR_14_() gsl_HAVE_CONSTEXPR_14
+#define gsl_HAVE_DECLTYPE_AUTO_() gsl_HAVE_DECLTYPE_AUTO
+#define gsl_HAVE_DEPRECATED_() gsl_HAVE_DEPRECATED
+
+// Presence of C++17 language features:
+// MSVC: template parameter deduction guides since Visual Studio 2017 v15.7
+
+#define gsl_HAVE_ENUM_CLASS_CONSTRUCTION_FROM_UNDERLYING_TYPE gsl_CPP17_000
+#define gsl_HAVE_DEDUCTION_GUIDES ( gsl_CPP17_000 && ! gsl_BETWEEN( gsl_COMPILER_MSVC_VERSION_FULL, 1, 1414 ) )
+#define gsl_HAVE_NODISCARD gsl_CPP17_000
+#define gsl_HAVE_CONSTEXPR_17 gsl_CPP17_OR_GREATER
+
+#define gsl_HAVE_ENUM_CLASS_CONSTRUCTION_FROM_UNDERLYING_TYPE_() gsl_HAVE_ENUM_CLASS_CONSTRUCTION_FROM_UNDERLYING_TYPE
+#define gsl_HAVE_DEDUCTION_GUIDES_() gsl_HAVE_DEDUCTION_GUIDES
+#define gsl_HAVE_NODISCARD_() gsl_HAVE_NODISCARD
+#define gsl_HAVE_CONSTEXPR_17_() gsl_HAVE_CONSTEXPR_17
+
+// Presence of C++20 language features:
+
+#define gsl_HAVE_CONSTEXPR_20 gsl_CPP20_OR_GREATER
+
+#define gsl_HAVE_CONSTEXPR_20_() gsl_HAVE_CONSTEXPR_20
+
+// Presence of C++ library features:
+
+#if gsl_BETWEEN( gsl_COMPILER_ARMCC_VERSION, 1, 600 )
+// Some versions of the ARM compiler apparently ship without a C++11 standard library despite having some C++11 support.
+# define gsl_STDLIB_CPP98_OR_GREATER gsl_CPP98_OR_GREATER
+# define gsl_STDLIB_CPP11_OR_GREATER 0
+# define gsl_STDLIB_CPP14_OR_GREATER 0
+# define gsl_STDLIB_CPP17_OR_GREATER 0
+# define gsl_STDLIB_CPP20_OR_GREATER 0
+#else
+# define gsl_STDLIB_CPP98_OR_GREATER gsl_CPP98_OR_GREATER
+# define gsl_STDLIB_CPP11_OR_GREATER gsl_CPP11_OR_GREATER
+# define gsl_STDLIB_CPP14_OR_GREATER gsl_CPP14_OR_GREATER
+# define gsl_STDLIB_CPP17_OR_GREATER gsl_CPP17_OR_GREATER
+# define gsl_STDLIB_CPP20_OR_GREATER gsl_CPP20_OR_GREATER
+#endif
+
+#define gsl_STDLIB_CPP11_100 (gsl_STDLIB_CPP11_OR_GREATER || gsl_COMPILER_MSVC_VER >= 1600)
+#define gsl_STDLIB_CPP11_110 (gsl_STDLIB_CPP11_OR_GREATER || gsl_COMPILER_MSVC_VER >= 1700)
+#define gsl_STDLIB_CPP11_120 (gsl_STDLIB_CPP11_OR_GREATER || gsl_COMPILER_MSVC_VER >= 1800)
+#define gsl_STDLIB_CPP11_140 (gsl_STDLIB_CPP11_OR_GREATER || gsl_COMPILER_MSVC_VER >= 1900)
+
+#define gsl_STDLIB_CPP14_000 (gsl_STDLIB_CPP14_OR_GREATER)
+#define gsl_STDLIB_CPP14_120 (gsl_STDLIB_CPP14_OR_GREATER || gsl_COMPILER_MSVC_VER >= 1800)
+#define gsl_STDLIB_CPP14_140 (gsl_STDLIB_CPP14_OR_GREATER || gsl_COMPILER_MSVC_VER >= 1900)
+
+#define gsl_STDLIB_CPP17_000 (gsl_STDLIB_CPP17_OR_GREATER)
+#define gsl_STDLIB_CPP17_140 (gsl_STDLIB_CPP17_OR_GREATER || gsl_COMPILER_MSVC_VER >= 1900)
+
+#define gsl_STDLIB_CPP11_140_CPP0X_90 (gsl_STDLIB_CPP11_140 || (gsl_COMPILER_MSVC_VER >= 1500 && gsl_HAS_CPP0X))
+#define gsl_STDLIB_CPP11_140_CPP0X_100 (gsl_STDLIB_CPP11_140 || (gsl_COMPILER_MSVC_VER >= 1600 && gsl_HAS_CPP0X))
+
+#define gsl_HAVE_ADDRESSOF gsl_STDLIB_CPP17_000
+#define gsl_HAVE_ARRAY gsl_STDLIB_CPP11_110
+#define gsl_HAVE_TYPE_TRAITS gsl_STDLIB_CPP11_110
+#define gsl_HAVE_TR1_TYPE_TRAITS gsl_STDLIB_CPP11_110
+#define gsl_HAVE_CONTAINER_DATA_METHOD gsl_STDLIB_CPP11_140_CPP0X_90
+#define gsl_HAVE_STD_DATA gsl_STDLIB_CPP17_000
+#ifdef __cpp_lib_ssize
+# define gsl_HAVE_STD_SSIZE 1
+#else
+# define gsl_HAVE_STD_SSIZE ( gsl_COMPILER_GNUC_VERSION >= 1000 && __cplusplus > 201703L )
+#endif
+#define gsl_HAVE_HASH gsl_STDLIB_CPP11_120
+#define gsl_HAVE_SIZED_TYPES gsl_STDLIB_CPP11_140
+#define gsl_HAVE_MAKE_SHARED gsl_STDLIB_CPP11_140_CPP0X_100
+#define gsl_HAVE_SHARED_PTR gsl_STDLIB_CPP11_140_CPP0X_100
+#define gsl_HAVE_UNIQUE_PTR gsl_STDLIB_CPP11_140_CPP0X_100
+#define gsl_HAVE_MAKE_UNIQUE gsl_STDLIB_CPP14_120
+#define gsl_HAVE_MOVE_FORWARD gsl_STDLIB_CPP11_100
+#define gsl_HAVE_NULLPTR gsl_STDLIB_CPP11_100
+#define gsl_HAVE_UNCAUGHT_EXCEPTIONS gsl_STDLIB_CPP17_140
+#define gsl_HAVE_ADD_CONST gsl_HAVE_TYPE_TRAITS
+#define gsl_HAVE_INITIALIZER_LIST gsl_STDLIB_CPP11_120
+#define gsl_HAVE_INTEGRAL_CONSTANT gsl_HAVE_TYPE_TRAITS
+#define gsl_HAVE_REMOVE_CONST gsl_HAVE_TYPE_TRAITS
+#define gsl_HAVE_REMOVE_REFERENCE gsl_HAVE_TYPE_TRAITS
+#define gsl_HAVE_REMOVE_CVREF gsl_STDLIB_CPP20_OR_GREATER
+#define gsl_HAVE_TR1_ADD_CONST gsl_HAVE_TR1_TYPE_TRAITS
+#define gsl_HAVE_TR1_INTEGRAL_CONSTANT gsl_HAVE_TR1_TYPE_TRAITS
+#define gsl_HAVE_TR1_REMOVE_CONST gsl_HAVE_TR1_TYPE_TRAITS
+#define gsl_HAVE_TR1_REMOVE_REFERENCE gsl_HAVE_TR1_TYPE_TRAITS
+
+#define gsl_HAVE_ADDRESSOF_() gsl_HAVE_ADDRESSOF
+#define gsl_HAVE_ARRAY_() gsl_HAVE_ARRAY
+#define gsl_HAVE_TYPE_TRAITS_() gsl_HAVE_TYPE_TRAITS
+#define gsl_HAVE_TR1_TYPE_TRAITS_() gsl_HAVE_TR1_TYPE_TRAITS
+#define gsl_HAVE_CONTAINER_DATA_METHOD_() gsl_HAVE_CONTAINER_DATA_METHOD
+#define gsl_HAVE_HASH_() gsl_HAVE_HASH
+#define gsl_HAVE_STD_DATA_() gsl_HAVE_STD_DATA
+#define gsl_HAVE_STD_SSIZE_() gsl_HAVE_STD_SSIZE
+#define gsl_HAVE_SIZED_TYPES_() gsl_HAVE_SIZED_TYPES
+#define gsl_HAVE_MAKE_SHARED_() gsl_HAVE_MAKE_SHARED
+#define gsl_HAVE_MOVE_FORWARD_() gsl_HAVE_MOVE_FORWARD
+#define gsl_HAVE_NULLPTR_() gsl_HAVE_NULLPTR // It's a language feature but needs library support, so we list it as a library feature.
+#define gsl_HAVE_SHARED_PTR_() gsl_HAVE_SHARED_PTR
+#define gsl_HAVE_UNIQUE_PTR_() gsl_HAVE_UNIQUE_PTR
+#define gsl_HAVE_MAKE_UNIQUE_() gsl_HAVE_MAKE_UNIQUE
+#define gsl_HAVE_UNCAUGHT_EXCEPTIONS_() gsl_HAVE_UNCAUGHT_EXCEPTIONS
+#define gsl_HAVE_ADD_CONST_() gsl_HAVE_ADD_CONST
+#define gsl_HAVE_INITIALIZER_LIST_() gsl_HAVE_INITIALIZER_LIST // It's a language feature but needs library support, so we list it as a library feature.
+#define gsl_HAVE_INTEGRAL_CONSTANT_() gsl_HAVE_INTEGRAL_CONSTANT
+#define gsl_HAVE_REMOVE_CONST_() gsl_HAVE_REMOVE_CONST
+#define gsl_HAVE_REMOVE_REFERENCE_() gsl_HAVE_REMOVE_REFERENCE
+#define gsl_HAVE_REMOVE_CVREF_() gsl_HAVE_REMOVE_CVREF
+#define gsl_HAVE_TR1_ADD_CONST_() gsl_HAVE_TR1_ADD_CONST
+#define gsl_HAVE_TR1_INTEGRAL_CONSTANT_() gsl_HAVE_TR1_INTEGRAL_CONSTANT
+#define gsl_HAVE_TR1_REMOVE_CONST_() gsl_HAVE_TR1_REMOVE_CONST
+#define gsl_HAVE_TR1_REMOVE_REFERENCE_() gsl_HAVE_TR1_REMOVE_REFERENCE
+
+// C++ feature usage:
+
+#if gsl_HAVE( ADDRESSOF )
+# define gsl_ADDRESSOF(x) std::addressof(x)
+#else
+# define gsl_ADDRESSOF(x) (&x)
+#endif
+
+#if gsl_HAVE( CONSTEXPR_11 )
+# define gsl_constexpr constexpr
+#else
+# define gsl_constexpr /*constexpr*/
+#endif
+
+#if gsl_HAVE( CONSTEXPR_14 )
+# define gsl_constexpr14 constexpr
+#else
+# define gsl_constexpr14 /*constexpr*/
+#endif
+
+#if gsl_HAVE( CONSTEXPR_17 )
+# define gsl_constexpr17 constexpr
+#else
+# define gsl_constexpr17 /*constexpr*/
+#endif
+
+#if gsl_HAVE( CONSTEXPR_20 )
+# define gsl_constexpr20 constexpr
+#else
+# define gsl_constexpr20 /*constexpr*/
+#endif
+
+#if gsl_HAVE( EXPLICIT )
+# define gsl_explicit explicit
+#else
+# define gsl_explicit /*explicit*/
+#endif
+
+#if gsl_FEATURE( IMPLICIT_MACRO )
+# define implicit /*implicit*/
+#endif
+
+#if gsl_HAVE( IS_DELETE )
+# define gsl_is_delete = delete
+#else
+# define gsl_is_delete
+#endif
+
+#if gsl_HAVE( IS_DELETE )
+# define gsl_is_delete_access public
+#else
+# define gsl_is_delete_access private
+#endif
+
+#if gsl_HAVE( NOEXCEPT )
+# define gsl_noexcept noexcept
+# define gsl_noexcept_if( expr ) noexcept( expr )
+#else
+# define gsl_noexcept throw()
+# define gsl_noexcept_if( expr ) /*noexcept( expr )*/
+#endif
+#if defined( gsl_TESTING_ )
+# define gsl_noexcept_not_testing
+#else
+# define gsl_noexcept_not_testing gsl_noexcept
+#endif
+
+#if gsl_HAVE( NULLPTR )
+# define gsl_nullptr nullptr
+#else
+# define gsl_nullptr NULL
+#endif
+
+#if gsl_HAVE( NODISCARD )
+# define gsl_NODISCARD [[nodiscard]]
+#else
+# define gsl_NODISCARD
+#endif
+
+#if gsl_HAVE( NORETURN )
+# define gsl_NORETURN [[noreturn]]
+#elif defined(_MSC_VER)
+# define gsl_NORETURN __declspec(noreturn)
+#elif gsl_COMPILER_GNUC_VERSION || gsl_COMPILER_CLANG_VERSION || gsl_COMPILER_APPLECLANG_VERSION || gsl_COMPILER_ARMCC_VERSION
+# define gsl_NORETURN __attribute__((noreturn))
+#else
+# define gsl_NORETURN
+#endif
+
+#if gsl_HAVE( DEPRECATED ) && ! defined( gsl_TESTING_ )
+# define gsl_DEPRECATED [[deprecated]]
+# define gsl_DEPRECATED_MSG( msg ) [[deprecated( msg )]]
+#else
+# define gsl_DEPRECATED
+# define gsl_DEPRECATED_MSG( msg )
+#endif
+
+#if gsl_HAVE( C99_PREPROCESSOR )
+# if gsl_CPP20_OR_GREATER
+# define gsl_CONSTRAINT(...) __VA_ARGS__
+# else
+# define gsl_CONSTRAINT(...) typename
+# endif
+#endif
+
+#if gsl_HAVE( TYPE_TRAITS )
+# define gsl_STATIC_ASSERT_( cond, msg ) static_assert( cond, msg )
+#else
+# define gsl_STATIC_ASSERT_( cond, msg ) ( ( void )sizeof( char[1 - 2*!!( cond ) ] ) )
+#endif
+
+#if gsl_HAVE( TYPE_TRAITS )
+
+#define gsl_DEFINE_ENUM_BITMASK_OPERATORS_( ENUM ) \
+ gsl_NODISCARD gsl_api inline gsl_constexpr ENUM \
+ operator~( ENUM val ) gsl_noexcept \
+ { \
+ typedef typename ::gsl::std11::underlying_type<ENUM>::type U; \
+ return ENUM( ~U( val ) ); \
+ } \
+ gsl_NODISCARD gsl_api inline gsl_constexpr ENUM \
+ operator|( ENUM lhs, ENUM rhs ) gsl_noexcept \
+ { \
+ typedef typename ::gsl::std11::underlying_type<ENUM>::type U; \
+ return ENUM( U( lhs ) | U( rhs ) ); \
+ } \
+ gsl_NODISCARD gsl_api inline gsl_constexpr ENUM \
+ operator&( ENUM lhs, ENUM rhs ) gsl_noexcept \
+ { \
+ typedef typename ::gsl::std11::underlying_type<ENUM>::type U; \
+ return ENUM( U( lhs ) & U( rhs ) ); \
+ } \
+ gsl_NODISCARD gsl_api inline gsl_constexpr ENUM \
+ operator^( ENUM lhs, ENUM rhs ) gsl_noexcept \
+ { \
+ typedef typename ::gsl::std11::underlying_type<ENUM>::type U; \
+ return ENUM( U( lhs ) ^ U( rhs ) ); \
+ } \
+ gsl_api inline gsl_constexpr14 ENUM & \
+ operator|=( ENUM & lhs, ENUM rhs ) gsl_noexcept \
+ { \
+ return lhs = lhs | rhs; \
+ } \
+ gsl_api inline gsl_constexpr14 ENUM & \
+ operator&=( ENUM & lhs, ENUM rhs ) gsl_noexcept \
+ { \
+ return lhs = lhs & rhs; \
+ } \
+ gsl_api inline gsl_constexpr14 ENUM & \
+ operator^=( ENUM & lhs, ENUM rhs ) gsl_noexcept \
+ { \
+ return lhs = lhs ^ rhs; \
+ }
+
+#define gsl_DEFINE_ENUM_RELATIONAL_OPERATORS_( ENUM ) \
+ gsl_NODISCARD gsl_api inline gsl_constexpr bool \
+ operator<( ENUM lhs, ENUM rhs ) gsl_noexcept \
+ { \
+ typedef typename ::gsl::std11::underlying_type<ENUM>::type U; \
+ return U( lhs ) < U( rhs ); \
+ } \
+ gsl_NODISCARD gsl_api inline gsl_constexpr bool \
+ operator>( ENUM lhs, ENUM rhs ) gsl_noexcept \
+ { \
+ typedef typename ::gsl::std11::underlying_type<ENUM>::type U; \
+ return U( lhs ) > U( rhs ); \
+ } \
+ gsl_NODISCARD gsl_api inline gsl_constexpr bool \
+ operator<=( ENUM lhs, ENUM rhs ) gsl_noexcept \
+ { \
+ typedef typename ::gsl::std11::underlying_type<ENUM>::type U; \
+ return U( lhs ) <= U( rhs ); \
+ } \
+ gsl_NODISCARD gsl_api inline gsl_constexpr bool \
+ operator>=( ENUM lhs, ENUM rhs ) gsl_noexcept \
+ { \
+ typedef typename ::gsl::std11::underlying_type<ENUM>::type U; \
+ return U( lhs ) >= U( rhs ); \
+ }
+
+ //
+ // Defines bitmask operators `|`, `&`, `^`, `~`, `|=`, `&=`, and `^=` for the given enum type.
+ //
+ // enum class Vegetables { tomato = 0b001, onion = 0b010, eggplant = 0b100 };
+ // gsl_DEFINE_ENUM_BITMASK_OPERATORS( Vegetables )
+ //
+#define gsl_DEFINE_ENUM_BITMASK_OPERATORS( ENUM ) gsl_DEFINE_ENUM_BITMASK_OPERATORS_( ENUM )
+
+ //
+ // Defines relational operators `<`, `>`, `<=`, `>=` for the given enum type.
+ //
+ // enum class OperatorPrecedence { additive = 0, multiplicative = 1, power = 2 };
+ // gsl_DEFINE_ENUM_RELATIONAL_OPERATORS( OperatorPrecedence )
+ //
+#define gsl_DEFINE_ENUM_RELATIONAL_OPERATORS( ENUM ) gsl_DEFINE_ENUM_RELATIONAL_OPERATORS_( ENUM )
+
+#endif // gsl_HAVE( TYPE_TRAITS )
+
+#define gsl_DIMENSION_OF( a ) ( sizeof(a) / sizeof(0[a]) )
+
+
+// Method enabling (C++98, VC120 (VS2013) cannot use __VA_ARGS__)
+
+#if gsl_HAVE( EXPRESSION_SFINAE )
+# define gsl_TRAILING_RETURN_TYPE_(T) auto
+# define gsl_RETURN_DECLTYPE_(EXPR) -> decltype( EXPR )
+#else
+# define gsl_TRAILING_RETURN_TYPE_(T) T
+# define gsl_RETURN_DECLTYPE_(EXPR)
+#endif
+
+// NOTE: When using SFINAE in gsl-lite, please note that overloads of function templates must always use SFINAE with non-type default arguments
+// as explained in https://en.cppreference.com/w/cpp/types/enable_if#Notes. `gsl_ENABLE_IF_()` implements graceful fallback to default
+// type arguments (for compilers that don't support non-type default arguments); please verify that this is appropriate in the given
+// situation, and add additional checks if necessary.
+//
+// Also, please note that `gsl_ENABLE_IF_()` doesn't enforce the constraint at all if no compiler/library support is available (i.e. pre-C++11).
+
+#if gsl_HAVE( TYPE_TRAITS ) && gsl_HAVE( DEFAULT_FUNCTION_TEMPLATE_ARG )
+# if !gsl_BETWEEN( gsl_COMPILER_MSVC_VERSION, 1, 140 ) // VS 2013 seems to have trouble with SFINAE for default non-type arguments
+# define gsl_ENABLE_IF_(VA) , typename std::enable_if< ( VA ), int >::type = 0
+# else
+# define gsl_ENABLE_IF_(VA) , typename = typename std::enable_if< ( VA ), ::gsl::detail::enabler >::type
+# endif
+#else
+# define gsl_ENABLE_IF_(VA)
+#endif
+
+
+// Other features:
+
+#define gsl_HAVE_CONSTRAINED_SPAN_CONTAINER_CTOR ( gsl_HAVE_DEFAULT_FUNCTION_TEMPLATE_ARG && gsl_HAVE_CONTAINER_DATA_METHOD )
+#define gsl_HAVE_CONSTRAINED_SPAN_CONTAINER_CTOR_() gsl_HAVE_CONSTRAINED_SPAN_CONTAINER_CTOR
+
+#define gsl_HAVE_UNCONSTRAINED_SPAN_CONTAINER_CTOR ( gsl_CONFIG_ALLOWS_UNCONSTRAINED_SPAN_CONTAINER_CTOR && gsl_COMPILER_NVCC_VERSION == 0 )
+#define gsl_HAVE_UNCONSTRAINED_SPAN_CONTAINER_CTOR_() gsl_HAVE_UNCONSTRAINED_SPAN_CONTAINER_CTOR
+
+// GSL API (e.g. for CUDA platform):
+
+// Guidelines for using `gsl_api`:
+//
+// NVCC imposes the restriction that a function annotated `__host__ __device__` cannot call host-only or device-only functions.
+// This makes `gsl_api` inappropriate for generic functions that call unknown code, e.g. the template constructors of `span<>`
+// or functions like `finally()` which accept an arbitrary function object.
+// It is often preferable to annotate functions only with `gsl_constexpr` or `gsl_constexpr14`. The "extended constexpr" mode
+// of NVCC (currently an experimental feature) will implicitly consider constexpr functions `__host__ __device__` functions
+// but tolerates calls to host-only or device-only functions.
+
+#ifndef gsl_api
+# ifdef __CUDACC__
+# define gsl_api __host__ __device__
+# else
+# define gsl_api /*gsl_api*/
+# endif
+#endif
+
+// Additional includes:
+
+#if ! gsl_CPP11_OR_GREATER
+# include <algorithm> // for swap() before C++11
+#endif // ! gsl_CPP11_OR_GREATER
+
+#if gsl_HAVE( ARRAY )
+# include <array> // indirectly includes reverse_iterator<>
+#endif
+
+#if ! gsl_HAVE( ARRAY )
+# include <iterator> // for reverse_iterator<>
+#endif
+
+#if ! gsl_HAVE( CONSTRAINED_SPAN_CONTAINER_CTOR ) || ! gsl_HAVE( AUTO )
+# include <vector>
+#endif
+
+#if gsl_HAVE( INITIALIZER_LIST )
+# include <initializer_list>
+#endif
+
+#if defined( gsl_CONFIG_CONTRACT_VIOLATION_ASSERTS )
+# include <cassert>
+#endif
+
+#if defined( gsl_CONFIG_CONTRACT_VIOLATION_TRAPS ) && gsl_COMPILER_MSVC_VERSION >= 110 // __fastfail() supported by VS 2012 and later
+# include <intrin.h>
+#endif
+
+#if gsl_HAVE( ENUM_CLASS ) && gsl_COMPILER_ARMCC_VERSION
+# include <endian.h>
+#endif
+
+#if gsl_HAVE( TYPE_TRAITS )
+# include <type_traits> // for enable_if<>,
+ // add_const<>, add_pointer<>, common_type<>, make_signed<>, remove_cv<>, remove_const<>, remove_volatile<>, remove_reference<>, remove_cvref<>, remove_pointer<>, underlying_type<>,
+ // is_assignable<>, is_constructible<>, is_const<>, is_convertible<>, is_integral<>, is_pointer<>, is_signed<>,
+ // integral_constant<>, declval()
+#elif gsl_HAVE( TR1_TYPE_TRAITS )
+# include <tr1/type_traits> // for add_const<>, remove_cv<>, remove_const<>, remove_volatile<>, remove_reference<>, integral_constant<>
+#endif
+
+#if gsl_FEATURE( EXPERIMENTAL_RETURN_GUARD )
+
+// Declare __cxa_get_globals() or equivalent in namespace gsl::detail for uncaught_exceptions():
+
+# if ! gsl_HAVE( UNCAUGHT_EXCEPTIONS )
+# if defined( _MSC_VER ) // MS-STL with either MSVC or clang-cl
+namespace gsl { namespace detail { extern "C" char * __cdecl _getptd(); } }
+# elif gsl_COMPILER_CLANG_VERSION || gsl_COMPILER_GNUC_VERSION || gsl_COMPILER_APPLECLANG_VERSION
+# if defined( __GLIBCXX__ ) || defined( __GLIBCPP__ ) // libstdc++: prototype from cxxabi.h
+# include <cxxabi.h>
+# elif ! defined( BOOST_CORE_UNCAUGHT_EXCEPTIONS_HPP_INCLUDED_ ) // libc++: prototype from Boost?
+# if defined( __FreeBSD__ ) || defined( __OpenBSD__ )
+namespace __cxxabiv1 { struct __cxa_eh_globals; extern "C" __cxa_eh_globals * __cxa_get_globals(); }
+# else
+namespace __cxxabiv1 { struct __cxa_eh_globals; extern "C" __cxa_eh_globals * __cxa_get_globals() gsl_noexcept; }
+# endif
+# endif
+ namespace gsl { namespace detail { using ::__cxxabiv1::__cxa_get_globals; } }
+# endif
+# endif // ! gsl_HAVE( UNCAUGHT_EXCEPTIONS )
+#endif // gsl_FEATURE( EXPERIMENTAL_RETURN_GUARD )
+
+
+// MSVC warning suppression macros:
+
+#if gsl_COMPILER_MSVC_VERSION >= 140 && ! gsl_COMPILER_NVCC_VERSION
+# define gsl_SUPPRESS_MSGSL_WARNING(expr) /* Pimm: note disabled for intel [[gsl::suppress(expr)]]*/
+# define gsl_SUPPRESS_MSVC_WARNING(code, descr) __pragma(warning(suppress: code) )
+# define gsl_DISABLE_MSVC_WARNINGS(codes) __pragma(warning(push)) __pragma(warning(disable: codes))
+# define gsl_RESTORE_MSVC_WARNINGS() __pragma(warning(pop ))
+#else
+// TODO: define for Clang
+# define gsl_SUPPRESS_MSGSL_WARNING(expr)
+# define gsl_SUPPRESS_MSVC_WARNING(code, descr)
+# define gsl_DISABLE_MSVC_WARNINGS(codes)
+# define gsl_RESTORE_MSVC_WARNINGS()
+#endif
+
+// Suppress the following MSVC GSL warnings:
+// - C26432: gsl::c.21 : if you define or delete any default operation in the type '...', define or delete them all
+// - C26410: gsl::r.32 : the parameter 'ptr' is a reference to const unique pointer, use const T* or const T& instead
+// - C26415: gsl::r.30 : smart pointer parameter 'ptr' is used only to access contained pointer. Use T* or T& instead
+// - C26418: gsl::r.36 : shared pointer parameter 'ptr' is not copied or moved. Use T* or T& instead
+// - C26472: gsl::t.1 : don't use a static_cast for arithmetic conversions;
+// use brace initialization, gsl::narrow_cast or gsl::narrow
+// - C26439: gsl::f.6 : special function 'function' can be declared 'noexcept'
+// - C26440: gsl::f.6 : function 'function' can be declared 'noexcept'
+// - C26455: gsl::f.6 : default constructor may not throw. Declare it 'noexcept'
+// - C26473: gsl::t.1 : don't cast between pointer types where the source type and the target type are the same
+// - C26481: gsl::b.1 : don't use pointer arithmetic. Use span instead
+// - C26482: gsl::b.2 : only index into arrays using constant expressions
+// - C26446: gdl::b.4 : prefer to use gsl::at() instead of unchecked subscript operator
+// - C26490: gsl::t.1 : don't use reinterpret_cast
+// - C26487: gsl::l.4 : don't return a pointer '(<some number>'s result)' that may be invalid
+// - C26457: es.48 : (void) should not be used to ignore return values, use 'std::ignore =' instead
+
+gsl_DISABLE_MSVC_WARNINGS( 26432 26410 26415 26418 26472 26439 26440 26455 26473 26481 26482 26446 26490 26487 26457 )
+
+namespace gsl {
+
+// forward declare span<>:
+
+template< class T >
+class span;
+
+// C++98 emulation:
+
+namespace std98 {
+
+// We implement `equal()` and `lexicographical_compare()` here to avoid having to pull in the <algorithm> header.
+template< class InputIt1, class InputIt2 >
+bool equal( InputIt1 first1, InputIt1 last1, InputIt2 first2 )
+{
+ // Implementation borrowed from https://en.cppreference.com/w/cpp/algorithm/equal.
+ for ( ; first1 != last1; ++first1, ++first2 )
+ {
+ if ( ! (*first1 == *first2 ) ) return false;
+ }
+ return true;
+}
+template< class InputIt1, class InputIt2 >
+bool lexicographical_compare( InputIt1 first1, InputIt1 last1, InputIt2 first2, InputIt2 last2 )
+{
+ // Implementation borrowed from https://en.cppreference.com/w/cpp/algorithm/lexicographical_compare.
+ for ( ; first1 != last1 && first2 != last2; ++first1, (void) ++first2 )
+ {
+ if ( *first1 < *first2 ) return true;
+ if ( *first2 < *first1 ) return false;
+ }
+ return first1 == last1 && first2 != last2;
+}
+
+} // namespace std98
+
+// C++11 emulation:
+
+namespace std11 {
+
+#if gsl_HAVE( ADD_CONST )
+
+using std::add_const;
+
+#elif gsl_HAVE( TR1_ADD_CONST )
+
+using std::tr1::add_const;
+
+#else
+
+template< class T > struct add_const { typedef const T type; };
+
+#endif // gsl_HAVE( ADD_CONST )
+
+#if gsl_HAVE( REMOVE_CONST )
+
+using std::remove_cv;
+using std::remove_const;
+using std::remove_volatile;
+
+#elif gsl_HAVE( TR1_REMOVE_CONST )
+
+using std::tr1::remove_cv;
+using std::tr1::remove_const;
+using std::tr1::remove_volatile;
+
+#else
+
+template< class T > struct remove_const { typedef T type; };
+template< class T > struct remove_const<T const> { typedef T type; };
+
+template< class T > struct remove_volatile { typedef T type; };
+template< class T > struct remove_volatile<T volatile> { typedef T type; };
+
+template< class T >
+struct remove_cv
+{
+ typedef typename remove_volatile<typename remove_const<T>::type>::type type;
+};
+
+#endif // gsl_HAVE( REMOVE_CONST )
+
+#if gsl_HAVE( REMOVE_REFERENCE )
+
+using std::remove_reference;
+
+#elif gsl_HAVE( TR1_REMOVE_REFERENCE )
+
+using std::tr1::remove_reference;
+
+#else
+
+template< class T > struct remove_reference { typedef T type; };
+template< class T > struct remove_reference<T&> { typedef T type; };
+# if gsl_HAVE( RVALUE_REFERENCE )
+template< class T > struct remove_reference<T&&> { typedef T type; };
+# endif
+
+#endif // gsl_HAVE( REMOVE_REFERENCE )
+
+
+#if gsl_HAVE( INTEGRAL_CONSTANT )
+
+using std::integral_constant;
+using std::true_type;
+using std::false_type;
+
+#elif gsl_HAVE( TR1_INTEGRAL_CONSTANT )
+
+using std::tr1::integral_constant;
+using std::tr1::true_type;
+using std::tr1::false_type;
+
+#else
+
+template< class T, T v > struct integral_constant { enum { value = v }; };
+typedef integral_constant< bool, true > true_type;
+typedef integral_constant< bool, false > false_type;
+
+#endif
+
+#if gsl_HAVE( TYPE_TRAITS )
+
+using std::underlying_type;
+
+#elif gsl_HAVE( TR1_TYPE_TRAITS )
+
+using std::tr1::underlying_type;
+
+#else
+
+// We could try to define `underlying_type<>` for pre-C++11 here, but let's not until someone actually needs it.
+
+#endif
+
+} // namespace std11
+
+// C++14 emulation:
+
+namespace std14 {
+
+#if gsl_HAVE( UNIQUE_PTR )
+# if gsl_HAVE( MAKE_UNIQUE )
+
+using std::make_unique;
+
+# elif gsl_HAVE( VARIADIC_TEMPLATE )
+
+template< class T, class... Args >
+gsl_NODISCARD std::unique_ptr<T>
+make_unique( Args &&... args )
+{
+ return std::unique_ptr<T>( new T( std::forward<Args>( args )... ) );
+}
+
+# endif // gsl_HAVE( MAKE_UNIQUE ), gsl_HAVE( VARIADIC_TEMPLATE )
+#endif // gsl_HAVE( UNIQUE_PTR )
+
+} // namespace std14
+
+namespace detail {
+
+#if gsl_HAVE( VARIADIC_TEMPLATE )
+
+template < bool V0, class T0, class... Ts > struct conjunction_ { using type = T0; };
+template < class T0, class T1, class... Ts > struct conjunction_<true, T0, T1, Ts...> : conjunction_<T1::value, T1, Ts...> { };
+template < bool V0, class T0, class... Ts > struct disjunction_ { using type = T0; };
+template < class T0, class T1, class... Ts > struct disjunction_<false, T0, T1, Ts...> : disjunction_<T1::value, T1, Ts...> { };
+
+#endif
+
+template <typename> struct dependent_false : std11::integral_constant<bool, false> { };
+
+} // namespace detail
+
+// C++17 emulation:
+
+namespace std17 {
+
+template< bool v > struct bool_constant : std11::integral_constant<bool, v>{};
+
+#if gsl_CPP11_120
+
+template < class... Ts > struct conjunction;
+template < > struct conjunction< > : std11::true_type { };
+template < class T0, class... Ts > struct conjunction<T0, Ts...> : detail::conjunction_<T0::value, T0, Ts...>::type { };
+template < class... Ts > struct disjunction;
+template < > struct disjunction< > : std11::false_type { };
+template < class T0, class... Ts > struct disjunction<T0, Ts...> : detail::disjunction_<T0::value, T0, Ts...>::type { };
+template < class T > struct negation : std11::integral_constant<bool, !T::value> { };
+
+# if gsl_CPP14_OR_GREATER
+
+template < class... Ts > constexpr bool conjunction_v = conjunction<Ts...>::value;
+template < class... Ts > constexpr bool disjunction_v = disjunction<Ts...>::value;
+template < class T > constexpr bool negation_v = negation<T>::value;
+
+# endif // gsl_CPP14_OR_GREATER
+
+template< class... Ts >
+struct make_void { typedef void type; };
+
+template< class... Ts >
+using void_t = typename make_void< Ts... >::type;
+
+#endif // gsl_CPP11_120
+
+#if gsl_HAVE( CONSTRAINED_SPAN_CONTAINER_CTOR )
+
+template< class T, size_t N >
+gsl_NODISCARD gsl_api inline gsl_constexpr auto
+size( T const(&)[N] ) gsl_noexcept -> size_t
+{
+ return N;
+}
+
+template< class C >
+gsl_NODISCARD inline gsl_constexpr auto
+size( C const & cont ) -> decltype( cont.size() )
+{
+ return cont.size();
+}
+
+template< class T, size_t N >
+gsl_NODISCARD gsl_api inline gsl_constexpr auto
+data( T(&arr)[N] ) gsl_noexcept -> T*
+{
+ return &arr[0];
+}
+
+template< class C >
+gsl_NODISCARD inline gsl_constexpr auto
+data( C & cont ) -> decltype( cont.data() )
+{
+ return cont.data();
+}
+
+template< class C >
+gsl_NODISCARD inline gsl_constexpr auto
+data( C const & cont ) -> decltype( cont.data() )
+{
+ return cont.data();
+}
+
+template< class E >
+gsl_NODISCARD inline gsl_constexpr auto
+data( std::initializer_list<E> il ) gsl_noexcept -> E const *
+{
+ return il.begin();
+}
+
+#endif // gsl_HAVE( CONSTRAINED_SPAN_CONTAINER_CTOR )
+
+} // namespace std17
+
+// C++20 emulation:
+
+namespace std20 {
+
+#if gsl_CPP11_100
+
+struct identity
+{
+ template < class T >
+ gsl_constexpr T && operator ()( T && arg ) const gsl_noexcept
+ {
+ return std::forward<T>( arg );
+ }
+};
+
+# if gsl_HAVE( ENUM_CLASS )
+enum class endian
+{
+# if defined( _WIN32 )
+ little = 0,
+ big = 1,
+ native = little
+# elif gsl_COMPILER_GNUC_VERSION || gsl_COMPILER_CLANG_VERSION || gsl_COMPILER_APPLECLANG_VERSION
+ little = __ORDER_LITTLE_ENDIAN__,
+ big = __ORDER_BIG_ENDIAN__,
+ native = __BYTE_ORDER__
+# elif gsl_COMPILER_ARMCC_VERSION
+ // from <endian.h> header file
+ little = __LITTLE_ENDIAN,
+ big = __BIG_ENDIAN,
+ native = __BYTE_ORDER
+# else
+// Do not define any endianness constants for unknown compilers.
+# endif
+};
+# endif // gsl_HAVE( ENUM_CLASS )
+
+#endif // gsl_CPP11_100
+
+template< class T >
+struct type_identity
+{
+ typedef T type;
+};
+#if gsl_HAVE( ALIAS_TEMPLATE )
+template< class T >
+using type_identity_t = typename type_identity<T>::type;
+#endif // gsl_HAVE( ALIAS_TEMPLATE )
+
+#if gsl_HAVE( STD_SSIZE )
+
+using std::ssize;
+
+#elif gsl_HAVE( CONSTRAINED_SPAN_CONTAINER_CTOR )
+
+template < class C >
+gsl_NODISCARD gsl_constexpr auto
+ssize( C const & c )
+ -> typename std::common_type<std::ptrdiff_t, typename std::make_signed<decltype(c.size())>::type>::type
+{
+ using R = typename std::common_type<std::ptrdiff_t, typename std::make_signed<decltype(c.size())>::type>::type;
+ return static_cast<R>( c.size() );
+}
+
+template <class T, std::size_t N>
+gsl_NODISCARD gsl_constexpr auto
+ssize( T const(&)[N] ) gsl_noexcept -> std::ptrdiff_t
+{
+ return std::ptrdiff_t( N );
+}
+
+#endif // gsl_HAVE( STD_SSIZE )
+
+#if gsl_HAVE( REMOVE_CVREF )
+
+using std::remove_cvref;
+
+#else
+
+template< class T > struct remove_cvref { typedef typename std11::remove_cv< typename std11::remove_reference< T >::type >::type type; };
+
+#endif // gsl_HAVE( REMOVE_CVREF )
+
+} // namespace std20
+
+namespace detail {
+
+/// for gsl_ENABLE_IF_()
+
+/*enum*/ class enabler{};
+
+#if gsl_HAVE( TYPE_TRAITS )
+
+template< class Q >
+struct is_span_oracle : std::false_type{};
+
+template< class T>
+struct is_span_oracle< span<T> > : std::true_type{};
+
+template< class Q >
+struct is_span : is_span_oracle< typename std::remove_cv<Q>::type >{};
+
+template< class Q >
+struct is_std_array_oracle : std::false_type{};
+
+# if gsl_HAVE( ARRAY )
+
+template< class T, std::size_t Extent >
+struct is_std_array_oracle< std::array<T, Extent> > : std::true_type{};
+
+# endif
+
+template< class Q >
+struct is_std_array : is_std_array_oracle< typename std::remove_cv<Q>::type >{};
+
+template< class Q >
+struct is_array : std::false_type{};
+
+template< class T >
+struct is_array<T[]> : std::true_type{};
+
+template< class T, std::size_t N >
+struct is_array<T[N]> : std::true_type{};
+
+# if gsl_CPP11_140 && ! gsl_BETWEEN( gsl_COMPILER_GNUC_VERSION, 1, 500 )
+
+template< class, class = void >
+struct has_size_and_data : std::false_type{};
+
+template< class C >
+struct has_size_and_data
+<
+ C, std17::void_t<
+ decltype( std17::size(std::declval<C>()) ),
+ decltype( std17::data(std::declval<C>()) ) >
+> : std::true_type{};
+
+template< class, class, class = void >
+struct is_compatible_element : std::false_type {};
+
+template< class C, class E >
+struct is_compatible_element
+<
+ C, E, std17::void_t<
+ decltype( std17::data(std::declval<C>()) ),
+ typename std::remove_pointer<decltype( std17::data( std::declval<C&>() ) )>::type(*)[] >
+> : std::is_convertible< typename std::remove_pointer<decltype( std17::data( std::declval<C&>() ) )>::type(*)[], E(*)[] >{};
+
+template< class C >
+struct is_container : std17::bool_constant
+<
+ ! is_span< C >::value
+ && ! is_array< C >::value
+ && ! is_std_array< C >::value
+ && has_size_and_data< C >::value
+>{};
+
+template< class C, class E >
+struct is_compatible_container : std17::bool_constant
+<
+ is_container<C>::value
+ && is_compatible_element<C,E>::value
+>{};
+
+# else // ^^^ gsl_CPP11_140 && ! gsl_BETWEEN( gsl_COMPILER_GNUC_VERSION, 1, 500 ) ^^^ / vvv ! gsl_CPP11_140 || gsl_BETWEEN( gsl_COMPILER_GNUC_VERSION, 1, 500 ) vvv
+
+template<
+ class C, class E
+ , typename = typename std::enable_if<
+ ! is_span< C >::value
+ && ! is_array< C >::value
+ && ! is_std_array< C >::value
+ && ( std::is_convertible< typename std::remove_pointer<decltype( std17::data( std::declval<C&>() ) )>::type(*)[], E(*)[] >::value)
+ // && has_size_and_data< C >::value
+ , enabler>::type
+ , class = decltype( std17::size(std::declval<C>()) )
+ , class = decltype( std17::data(std::declval<C>()) )
+>
+# if gsl_BETWEEN( gsl_COMPILER_MSVC_VERSION, 1, 140 )
+// VS2013 has insufficient support for expression SFINAE; we cannot make `is_compatible_container<>` a proper type trait here
+struct is_compatible_container : std::true_type { };
+# else
+struct is_compatible_container_r { is_compatible_container_r(int); };
+template< class C, class E >
+std::true_type is_compatible_container_f( is_compatible_container_r<C, E> );
+template< class C, class E >
+std::false_type is_compatible_container_f( ... );
+
+template< class C, class E >
+struct is_compatible_container : decltype( is_compatible_container_f< C, E >( 0 ) ) { };
+# endif // gsl_BETWEEN( gsl_COMPILER_MSVC_VERSION, 1, 140 )
+
+# endif // gsl_CPP11_140 && ! gsl_BETWEEN( gsl_COMPILER_GNUC_VERSION, 1, 500 )
+
+#endif // gsl_HAVE( TYPE_TRAITS )
+
+} // namespace detail
+
+//
+// GSL.util: utilities
+//
+
+// Integer type for indices (e.g. in a loop).
+typedef gsl_CONFIG_INDEX_TYPE index;
+
+// Integer type for dimensions.
+typedef gsl_CONFIG_INDEX_TYPE dim;
+
+// Integer type for array strides.
+typedef gsl_CONFIG_INDEX_TYPE stride;
+
+// Integer type for pointer, iterator, or index differences.
+typedef gsl_CONFIG_INDEX_TYPE diff;
+
+//
+// GSL.owner: ownership pointers
+//
+#if gsl_HAVE( SHARED_PTR )
+ using std::unique_ptr;
+ using std::shared_ptr;
+ using std::make_shared;
+# if gsl_HAVE( MAKE_UNIQUE ) || gsl_HAVE( VARIADIC_TEMPLATE )
+ using std14::make_unique;
+# endif
+#endif
+
+#if gsl_HAVE( ALIAS_TEMPLATE )
+ template< class T
+#if gsl_HAVE( TYPE_TRAITS )
+ , typename = typename std::enable_if< std::is_pointer<T>::value >::type
+#endif
+ >
+ using owner = T;
+#elif gsl_CONFIG( DEFAULTS_VERSION ) == 0
+ // TODO vNext: remove
+ template< class T > struct owner { typedef T type; };
+#endif
+
+#define gsl_HAVE_OWNER_TEMPLATE gsl_HAVE_ALIAS_TEMPLATE
+#define gsl_HAVE_OWNER_TEMPLATE_() gsl_HAVE_OWNER_TEMPLATE
+
+// TODO vNext: remove
+#if gsl_FEATURE( OWNER_MACRO )
+# if gsl_HAVE( OWNER_TEMPLATE )
+# define Owner(t) ::gsl::owner<t>
+# else
+# define Owner(t) ::gsl::owner<t>::type
+# endif
+#endif
+
+//
+// GSL.assert: assertions
+//
+
+#if gsl_HAVE( TYPE_TRAITS )
+# define gsl_ELIDE_( x ) static_assert( ::std::is_constructible<bool, decltype( x )>::value, "argument of contract check must be convertible to bool" )
+#else
+# define gsl_ELIDE_( x )
+#endif
+#define gsl_NO_OP_() ( static_cast<void>( 0 ) )
+
+#if defined( gsl_CONFIG_UNENFORCED_CONTRACTS_ASSUME )
+# if defined( __CUDACC__ ) && defined( __CUDA_ARCH__ )
+# if gsl_COMPILER_NVCC_VERSION >= 113
+# define gsl_ASSUME_( x ) ( ( x ) ? static_cast<void>(0) : __builtin_unreachable() )
+# define gsl_ASSUME_UNREACHABLE_() __builtin_unreachable()
+# else
+# define gsl_ASSUME_( x ) gsl_ELIDE_( x ) /* there is no assume intrinsic in CUDA device code */
+# define gsl_ASSUME_UNREACHABLE_() gsl_NO_OP_() /* there is no assume intrinsic in CUDA device code */
+# endif
+# elif gsl_COMPILER_MSVC_VERSION >= 140
+# define gsl_ASSUME_( x ) __assume( x )
+# define gsl_ASSUME_UNREACHABLE_() __assume( 0 )
+# elif gsl_COMPILER_GNUC_VERSION
+# define gsl_ASSUME_( x ) ( ( x ) ? static_cast<void>(0) : __builtin_unreachable() )
+# define gsl_ASSUME_UNREACHABLE_() __builtin_unreachable()
+# elif defined(__has_builtin)
+# if __has_builtin(__builtin_unreachable)
+# define gsl_ASSUME_( x ) ( ( x ) ? static_cast<void>(0) : __builtin_unreachable() )
+# define gsl_ASSUME_UNREACHABLE_() __builtin_unreachable()
+# else
+# error gsl_CONFIG_UNENFORCED_CONTRACTS_ASSUME: gsl-lite does not know how to generate UB optimization hints for this compiler; use gsl_CONFIG_UNENFORCED_CONTRACTS_ELIDE instead
+# endif
+# else
+# error gsl_CONFIG_UNENFORCED_CONTRACTS_ASSUME: gsl-lite does not know how to generate UB optimization hints for this compiler; use gsl_CONFIG_UNENFORCED_CONTRACTS_ELIDE instead
+# endif
+#endif // defined( gsl_CONFIG_UNENFORCED_CONTRACTS_ASSUME )
+
+#if defined( gsl_CONFIG_UNENFORCED_CONTRACTS_ASSUME )
+# define gsl_CONTRACT_UNENFORCED_( x ) gsl_ASSUME_( x )
+#else // defined( gsl_CONFIG_UNENFORCED_CONTRACTS_ELIDE ) [default]
+# define gsl_CONTRACT_UNENFORCED_( x ) gsl_ELIDE_( x )
+#endif
+
+#if defined( gsl_CONFIG_CONTRACT_VIOLATION_TRAPS )
+# if defined( __CUDACC__ ) && defined( __CUDA_ARCH__ )
+# define gsl_TRAP_() __trap()
+# elif gsl_COMPILER_MSVC_VERSION >= 110 // __fastfail() supported by VS 2012 and later
+# define gsl_TRAP_() __fastfail( 0 ) /* legacy failure code for buffer-overrun errors, cf. winnt.h, "Fast fail failure codes" */
+# elif gsl_COMPILER_GNUC_VERSION
+# define gsl_TRAP_() __builtin_trap()
+# elif defined(__has_builtin)
+# if __has_builtin(__builtin_trap)
+# define gsl_TRAP_() __builtin_trap()
+# else
+# error gsl_CONFIG_CONTRACT_VIOLATION_TRAPS: gsl-lite does not know how to generate a trap instruction for this compiler; use gsl_CONFIG_CONTRACT_VIOLATION_TERMINATES instead
+# endif
+# else
+# error gsl_CONFIG_CONTRACT_VIOLATION_TRAPS: gsl-lite does not know how to generate a trap instruction for this compiler; use gsl_CONFIG_CONTRACT_VIOLATION_TERMINATES instead
+# endif
+#endif // defined( gsl_CONFIG_CONTRACT_VIOLATION_TRAPS )
+
+#if defined( gsl_CONFIG_CONTRACT_VIOLATION_CALLS_HANDLER )
+# define gsl_CONTRACT_CHECK_( str, x ) ( ( x ) ? static_cast<void>(0) : ::gsl::fail_fast_assert_handler( #x, str, __FILE__, __LINE__ ) )
+# if defined( __CUDACC__ ) && defined( __CUDA_ARCH__ )
+# define gsl_FAILFAST_() ( ::gsl::fail_fast_assert_handler( "", "GSL: failure", __FILE__, __LINE__ ), gsl_TRAP_() ) /* do not let the custom assertion handler continue execution */
+# else
+# define gsl_FAILFAST_() ( ::gsl::fail_fast_assert_handler( "", "GSL: failure", __FILE__, __LINE__ ), ::gsl::detail::fail_fast_terminate() ) /* do not let the custom assertion handler continue execution */
+# endif
+#elif defined( __CUDACC__ ) && defined( __CUDA_ARCH__ )
+# if defined( gsl_CONFIG_CONTRACT_VIOLATION_ASSERTS ) || ! defined( NDEBUG )
+# define gsl_CONTRACT_CHECK_( str, x ) assert( str && ( x ) )
+# else
+# define gsl_CONTRACT_CHECK_( str, x ) ( ( x ) ? static_cast<void>(0) : __trap() )
+#endif
+# define gsl_FAILFAST_() ( __trap() )
+#elif defined( gsl_CONFIG_CONTRACT_VIOLATION_ASSERTS )
+# define gsl_CONTRACT_CHECK_( str, x ) assert( str && ( x ) )
+# if ! defined( NDEBUG )
+# define gsl_FAILFAST_() ( assert( ! "GSL: failure" ), ::gsl::detail::fail_fast_terminate() )
+# else
+# define gsl_FAILFAST_() ( ::gsl::detail::fail_fast_terminate() )
+# endif
+#elif defined( gsl_CONFIG_CONTRACT_VIOLATION_TRAPS )
+# define gsl_CONTRACT_CHECK_( str, x ) ( ( x ) ? static_cast<void>(0) : gsl_TRAP_() )
+# if gsl_COMPILER_MSVC_VERSION
+# define gsl_FAILFAST_() ( gsl_TRAP_(), ::gsl::detail::fail_fast_terminate() )
+# else
+# define gsl_FAILFAST_() ( gsl_TRAP_() )
+# endif
+#elif defined( gsl_CONFIG_CONTRACT_VIOLATION_THROWS )
+# define gsl_CONTRACT_CHECK_( str, x ) ( ( x ) ? static_cast<void>(0) : ::gsl::detail::fail_fast_throw( str ": '" #x "' at " __FILE__ ":" gsl_STRINGIFY(__LINE__) ) )
+# define gsl_FAILFAST_() ( ::gsl::detail::fail_fast_throw( "GSL: failure at " __FILE__ ":" gsl_STRINGIFY(__LINE__) ) )
+#else // defined( gsl_CONFIG_CONTRACT_VIOLATION_TERMINATES ) [default]
+# define gsl_CONTRACT_CHECK_( str, x ) ( ( x ) ? static_cast<void>(0) : ::gsl::detail::fail_fast_terminate() )
+# define gsl_FAILFAST_() ( ::gsl::detail::fail_fast_terminate() )
+#endif
+
+#if defined( gsl_CONFIG_CONTRACT_CHECKING_OFF ) || defined( gsl_CONFIG_CONTRACT_CHECKING_EXPECTS_OFF )
+# define gsl_Expects( x ) gsl_CONTRACT_UNENFORCED_( x )
+#else
+# define gsl_Expects( x ) gsl_CONTRACT_CHECK_( "GSL: Precondition failure", x )
+#endif
+#define Expects( x ) gsl_Expects( x )
+#if !defined( gsl_CONFIG_CONTRACT_CHECKING_AUDIT ) || defined( gsl_CONFIG_CONTRACT_CHECKING_EXPECTS_OFF )
+# define gsl_ExpectsAudit( x ) gsl_ELIDE_( x )
+#else
+# define gsl_ExpectsAudit( x ) gsl_CONTRACT_CHECK_( "GSL: Precondition failure (audit)", x )
+#endif
+
+#if defined( gsl_CONFIG_CONTRACT_CHECKING_OFF ) || defined( gsl_CONFIG_CONTRACT_CHECKING_ENSURES_OFF )
+# define gsl_Ensures( x ) gsl_CONTRACT_UNENFORCED_( x )
+#else
+# define gsl_Ensures( x ) gsl_CONTRACT_CHECK_( "GSL: Postcondition failure", x )
+#endif
+#define Ensures( x ) gsl_Ensures( x )
+#if !defined( gsl_CONFIG_CONTRACT_CHECKING_AUDIT ) || defined( gsl_CONFIG_CONTRACT_CHECKING_ENSURES_OFF )
+# define gsl_EnsuresAudit( x ) gsl_ELIDE_( x )
+#else
+# define gsl_EnsuresAudit( x ) gsl_CONTRACT_CHECK_( "GSL: Postcondition failure (audit)", x )
+#endif
+
+#if defined( gsl_CONFIG_CONTRACT_CHECKING_OFF ) || defined( gsl_CONFIG_CONTRACT_CHECKING_ASSERT_OFF )
+# define gsl_Assert( x ) gsl_CONTRACT_UNENFORCED_( x )
+#else
+# define gsl_Assert( x ) gsl_CONTRACT_CHECK_( "GSL: Assertion failure", x )
+#endif
+#if !defined( gsl_CONFIG_CONTRACT_CHECKING_AUDIT ) || defined( gsl_CONFIG_CONTRACT_CHECKING_ASSERT_OFF )
+# define gsl_AssertAudit( x ) gsl_ELIDE_( x )
+#else
+# define gsl_AssertAudit( x ) gsl_CONTRACT_CHECK_( "GSL: Assertion failure (audit)", x )
+#endif
+
+#define gsl_FailFast() gsl_FAILFAST_()
+
+
+struct fail_fast : public std::logic_error
+{
+ explicit fail_fast( char const * message )
+ : std::logic_error( message ) {}
+};
+
+namespace detail {
+
+
+#if gsl_HAVE( EXCEPTIONS )
+gsl_NORETURN inline void fail_fast_throw( char const * message )
+{
+ throw fail_fast( message );
+}
+#endif // gsl_HAVE( EXCEPTIONS )
+gsl_NORETURN inline void fail_fast_terminate() gsl_noexcept
+{
+ std::terminate();
+}
+
+} // namespace detail
+
+// Should be defined by user
+gsl_api void fail_fast_assert_handler( char const * const expression, char const * const message, char const * const file, int line );
+
+#if defined( gsl_CONFIG_CONTRACT_VIOLATION_THROWS )
+
+# if gsl_HAVE( EXCEPTIONS )
+gsl_DEPRECATED_MSG("don't call gsl::fail_fast_assert() directly; use contract checking macros instead")
+gsl_constexpr14 inline
+void fail_fast_assert( bool cond, char const * const message )
+{
+ if ( !cond )
+ throw fail_fast( message );
+}
+# endif // gsl_HAVE( EXCEPTIONS )
+
+#elif defined( gsl_CONFIG_CONTRACT_VIOLATION_CALLS_HANDLER )
+
+gsl_DEPRECATED_MSG("don't call gsl::fail_fast_assert() directly; use contract checking macros instead")
+gsl_api gsl_constexpr14 inline
+void fail_fast_assert( bool cond, char const * const expression, char const * const message, char const * const file, int line )
+{
+ if ( !cond )
+ ::gsl::fail_fast_assert_handler( expression, message, file, line );
+}
+
+#else // defined( gsl_CONFIG_CONTRACT_VIOLATION_TERMINATES ) [default]
+
+gsl_DEPRECATED_MSG("don't call gsl::fail_fast_assert() directly; use contract checking macros instead")
+gsl_constexpr14 inline
+void fail_fast_assert( bool cond ) gsl_noexcept
+{
+ if ( !cond )
+ std::terminate();
+}
+
+#endif
+
+
+//
+// GSL.util: utilities
+//
+
+#if gsl_FEATURE( EXPERIMENTAL_RETURN_GUARD )
+
+// Add uncaught_exceptions for pre-2017 MSVC, GCC and Clang
+// Return unsigned char to save stack space, uncaught_exceptions can only increase by 1 in a scope
+
+namespace std11 {
+
+# if gsl_HAVE( UNCAUGHT_EXCEPTIONS )
+
+inline unsigned char uncaught_exceptions() gsl_noexcept
+{
+ return static_cast<unsigned char>( std::uncaught_exceptions() );
+}
+
+# else // ! gsl_HAVE( UNCAUGHT_EXCEPTIONS )
+# if defined( _MSC_VER ) // MS-STL with either MSVC or clang-cl
+
+inline unsigned char uncaught_exceptions() gsl_noexcept
+{
+ return static_cast<unsigned char>( *reinterpret_cast<unsigned const*>( detail::_getptd() + (sizeof(void *) == 8 ? 0x100 : 0x90 ) ) );
+}
+
+# elif gsl_COMPILER_CLANG_VERSION || gsl_COMPILER_GNUC_VERSION || gsl_COMPILER_APPLECLANG_VERSION
+
+inline unsigned char uncaught_exceptions() gsl_noexcept
+{
+ return static_cast<unsigned char>( ( *reinterpret_cast<unsigned const *>( reinterpret_cast<unsigned char const *>(detail::__cxa_get_globals()) + sizeof(void *) ) ) );
+}
+
+# endif
+# endif
+
+} // namespace std11
+
+#endif // gsl_FEATURE( EXPERIMENTAL_RETURN_GUARD )
+
+#if gsl_STDLIB_CPP11_110
+
+gsl_DISABLE_MSVC_WARNINGS( 4702 ) // unreachable code
+
+template< class F >
+class final_action
+{
+public:
+ explicit final_action( F action ) gsl_noexcept
+ : action_( std::move( action ) )
+ , invoke_( true )
+ {}
+
+ final_action( final_action && other ) gsl_noexcept
+ : action_( std::move( other.action_ ) )
+ , invoke_( other.invoke_ )
+ {
+ other.invoke_ = false;
+ }
+
+ gsl_SUPPRESS_MSGSL_WARNING(f.6)
+ virtual ~final_action() gsl_noexcept
+ {
+ if ( invoke_ )
+ action_();
+ }
+
+gsl_is_delete_access:
+ final_action( final_action const & ) gsl_is_delete;
+ final_action & operator=( final_action const & ) gsl_is_delete;
+ final_action & operator=( final_action && ) gsl_is_delete;
+
+protected:
+ void dismiss() gsl_noexcept
+ {
+ invoke_ = false;
+ }
+
+private:
+ F action_;
+ bool invoke_;
+};
+
+template< class F >
+gsl_NODISCARD inline final_action<F>
+finally( F const & action ) gsl_noexcept
+{
+ return final_action<F>( action );
+}
+
+template< class F >
+gsl_NODISCARD inline final_action<F>
+finally( F && action ) gsl_noexcept
+{
+ return final_action<F>( std::forward<F>( action ) );
+}
+
+# if gsl_FEATURE( EXPERIMENTAL_RETURN_GUARD )
+
+template< class F >
+class final_action_return : public final_action<F>
+{
+public:
+ explicit final_action_return( F && action ) gsl_noexcept
+ : final_action<F>( std::move( action ) )
+ , exception_count( std11::uncaught_exceptions() )
+ {}
+
+ final_action_return( final_action_return && other ) gsl_noexcept
+ : final_action<F>( std::move( other ) )
+ , exception_count( std11::uncaught_exceptions() )
+ {}
+
+ ~final_action_return() override
+ {
+ if ( std11::uncaught_exceptions() != exception_count )
+ this->dismiss();
+ }
+
+gsl_is_delete_access:
+ final_action_return( final_action_return const & ) gsl_is_delete;
+ final_action_return & operator=( final_action_return const & ) gsl_is_delete;
+
+private:
+ unsigned char exception_count;
+};
+
+template< class F >
+gsl_NODISCARD inline final_action_return<F>
+on_return( F const & action ) gsl_noexcept
+{
+ return final_action_return<F>( action );
+}
+
+template< class F >
+gsl_NODISCARD inline final_action_return<F>
+on_return( F && action ) gsl_noexcept
+{
+ return final_action_return<F>( std::forward<F>( action ) );
+}
+
+template< class F >
+class final_action_error : public final_action<F>
+{
+public:
+ explicit final_action_error( F && action ) gsl_noexcept
+ : final_action<F>( std::move( action ) )
+ , exception_count( std11::uncaught_exceptions() )
+ {}
+
+ final_action_error( final_action_error && other ) gsl_noexcept
+ : final_action<F>( std::move( other ) )
+ , exception_count( std11::uncaught_exceptions() )
+ {}
+
+ ~final_action_error() override
+ {
+ if ( std11::uncaught_exceptions() == exception_count )
+ this->dismiss();
+ }
+
+gsl_is_delete_access:
+ final_action_error( final_action_error const & ) gsl_is_delete;
+ final_action_error & operator=( final_action_error const & ) gsl_is_delete;
+
+private:
+ unsigned char exception_count;
+};
+
+template< class F >
+gsl_NODISCARD inline final_action_error<F>
+on_error( F const & action ) gsl_noexcept
+{
+ return final_action_error<F>( action );
+}
+
+template< class F >
+gsl_NODISCARD inline final_action_error<F>
+on_error( F && action ) gsl_noexcept
+{
+ return final_action_error<F>( std::forward<F>( action ) );
+}
+
+# endif // gsl_FEATURE( EXPERIMENTAL_RETURN_GUARD )
+
+gsl_RESTORE_MSVC_WARNINGS()
+
+#else // ! gsl_STDLIB_CPP11_110
+
+class final_action
+{
+public:
+ typedef void (*Action)();
+
+ final_action( Action action )
+ : action_( action )
+ , invoke_( true )
+ {}
+
+ final_action( final_action const & other )
+ : action_( other.action_ )
+ , invoke_( other.invoke_ )
+ {
+ other.invoke_ = false;
+ }
+
+ virtual ~final_action()
+ {
+ if ( invoke_ )
+ action_();
+ }
+
+protected:
+ void dismiss()
+ {
+ invoke_ = false;
+ }
+
+private:
+ final_action & operator=( final_action const & );
+
+private:
+ Action action_;
+ mutable bool invoke_;
+};
+
+template< class F >
+inline final_action finally( F const & f )
+{
+ return final_action(( f ));
+}
+
+#if gsl_FEATURE( EXPERIMENTAL_RETURN_GUARD )
+
+class final_action_return : public final_action
+{
+public:
+ explicit final_action_return( Action action )
+ : final_action( action )
+ , exception_count( std11::uncaught_exceptions() )
+ {}
+
+ ~final_action_return()
+ {
+ if ( std11::uncaught_exceptions() != exception_count )
+ this->dismiss();
+ }
+
+private:
+ final_action_return & operator=( final_action_return const & );
+
+private:
+ unsigned char exception_count;
+};
+
+template< class F >
+inline final_action_return on_return( F const & action )
+{
+ return final_action_return( action );
+}
+
+class final_action_error : public final_action
+{
+public:
+ explicit final_action_error( Action action )
+ : final_action( action )
+ , exception_count( std11::uncaught_exceptions() )
+ {}
+
+ ~final_action_error()
+ {
+ if ( std11::uncaught_exceptions() == exception_count )
+ this->dismiss();
+ }
+
+private:
+ final_action_error & operator=( final_action_error const & );
+
+private:
+ unsigned char exception_count;
+};
+
+template< class F >
+inline final_action_error on_error( F const & action )
+{
+ return final_action_error( action );
+}
+
+# endif // gsl_FEATURE( EXPERIMENTAL_RETURN_GUARD )
+
+#endif // gsl_STDLIB_CPP11_110
+
+#if gsl_STDLIB_CPP11_120
+
+template< class T, class U >
+gsl_NODISCARD gsl_api inline gsl_constexpr T
+narrow_cast( U && u ) gsl_noexcept
+{
+ return static_cast<T>( std::forward<U>( u ) );
+}
+
+#else // ! gsl_STDLIB_CPP11_120
+
+template< class T, class U >
+gsl_api inline T
+narrow_cast( U u ) gsl_noexcept
+{
+ return static_cast<T>( u );
+}
+
+#endif // gsl_STDLIB_CPP11_120
+
+struct narrowing_error : public std::exception
+{
+ char const * what() const gsl_noexcept
+#if gsl_HAVE( OVERRIDE_FINAL )
+ override
+#endif
+ {
+ return "narrowing_error";
+ }
+};
+
+#if gsl_HAVE( TYPE_TRAITS )
+
+namespace detail {
+
+ template< class T, class U >
+ struct is_same_signedness : public std::integral_constant<bool, std::is_signed<T>::value == std::is_signed<U>::value> {};
+
+# if gsl_COMPILER_NVCC_VERSION
+ // We do this to circumvent NVCC warnings about pointless unsigned comparisons with 0.
+ template< class T >
+ gsl_constexpr gsl_api bool is_negative( T value, std::true_type /*isSigned*/ ) gsl_noexcept
+ {
+ return value < T();
+ }
+ template< class T >
+ gsl_constexpr gsl_api bool is_negative( T /*value*/, std::false_type /*isUnsigned*/ ) gsl_noexcept
+ {
+ return false;
+ }
+ template< class T, class U >
+ gsl_constexpr gsl_api bool have_same_sign( T, U, std::true_type /*isSameSignedness*/ ) gsl_noexcept
+ {
+ return true;
+ }
+ template< class T, class U >
+ gsl_constexpr gsl_api bool have_same_sign( T t, U u, std::false_type /*isSameSignedness*/ ) gsl_noexcept
+ {
+ return detail::is_negative( t, std::is_signed<T>() ) == detail::is_negative( u, std::is_signed<U>() );
+ }
+# endif // gsl_COMPILER_NVCC_VERSION
+
+} // namespace detail
+
+#endif
+
+template< class T, class U >
+gsl_NODISCARD
+#if !gsl_CONFIG( NARROW_THROWS_ON_TRUNCATION ) && !defined( gsl_CONFIG_CONTRACT_VIOLATION_THROWS )
+gsl_api
+#endif
+inline T
+narrow( U u )
+{
+#if gsl_CONFIG( NARROW_THROWS_ON_TRUNCATION ) && ! gsl_HAVE( EXCEPTIONS )
+ gsl_STATIC_ASSERT_( detail::dependent_false< T >::value,
+ "According to the GSL specification, narrow<>() throws an exception of type narrowing_error on truncation. Therefore "
+ "it cannot be used if exceptions are disabled. Consider using narrow_failfast<>() instead which raises a precondition "
+ "violation if the given value cannot be represented in the target type." );
+#endif
+
+ T t = static_cast<T>( u );
+
+ if ( static_cast<U>( t ) != u )
+ {
+#if gsl_HAVE( EXCEPTIONS ) && ( gsl_CONFIG( NARROW_THROWS_ON_TRUNCATION ) || defined( gsl_CONFIG_CONTRACT_VIOLATION_THROWS ) )
+ throw narrowing_error();
+#else
+ std::terminate();
+#endif
+ }
+
+#if gsl_HAVE( TYPE_TRAITS )
+# if gsl_COMPILER_NVCC_VERSION
+ if ( ! detail::have_same_sign( t, u, detail::is_same_signedness<T, U>() ) )
+# else
+ gsl_SUPPRESS_MSVC_WARNING( 4127, "conditional expression is constant" )
+ if ( ! detail::is_same_signedness<T, U>::value && ( t < T() ) != ( u < U() ) )
+# endif
+#else
+ // Don't assume T() works:
+ gsl_SUPPRESS_MSVC_WARNING( 4127, "conditional expression is constant" )
+ if ( ( t < 0 ) != ( u < 0 ) )
+#endif
+ {
+#if gsl_HAVE( EXCEPTIONS ) && ( gsl_CONFIG( NARROW_THROWS_ON_TRUNCATION ) || defined( gsl_CONFIG_CONTRACT_VIOLATION_THROWS ) )
+ throw narrowing_error();
+#else
+ std::terminate();
+#endif
+ }
+
+ return t;
+}
+
+template< class T, class U >
+gsl_NODISCARD gsl_api inline T
+narrow_failfast( U u )
+{
+ T t = static_cast<T>( u );
+
+ gsl_Expects( static_cast<U>( t ) == u );
+
+#if gsl_HAVE( TYPE_TRAITS )
+# if gsl_COMPILER_NVCC_VERSION
+ gsl_Expects( ::gsl::detail::have_same_sign( t, u, ::gsl::detail::is_same_signedness<T, U>() ) );
+# else
+ gsl_SUPPRESS_MSVC_WARNING( 4127, "conditional expression is constant" )
+ gsl_Expects( ( ::gsl::detail::is_same_signedness<T, U>::value || ( t < T() ) == ( u < U() ) ) );
+# endif
+#else
+ // Don't assume T() works:
+ gsl_SUPPRESS_MSVC_WARNING( 4127, "conditional expression is constant" )
+ gsl_Expects( ( t < 0 ) == ( u < 0 ) );
+#endif
+
+ return t;
+}
+
+
+//
+// at() - Bounds-checked way of accessing static arrays, std::array, std::vector.
+//
+
+template< class T, size_t N >
+gsl_NODISCARD gsl_api inline gsl_constexpr14 T &
+at( T(&arr)[N], size_t pos )
+{
+ gsl_Expects( pos < N );
+ return arr[pos];
+}
+
+template< class Container >
+gsl_NODISCARD gsl_api inline gsl_constexpr14 typename Container::value_type &
+at( Container & cont, size_t pos )
+{
+ gsl_Expects( pos < cont.size() );
+ return cont[pos];
+}
+
+template< class Container >
+gsl_NODISCARD gsl_api inline gsl_constexpr14 typename Container::value_type const &
+at( Container const & cont, size_t pos )
+{
+ gsl_Expects( pos < cont.size() );
+ return cont[pos];
+}
+
+#if gsl_HAVE( INITIALIZER_LIST )
+
+template< class T >
+gsl_NODISCARD gsl_api inline const gsl_constexpr14 T
+at( std::initializer_list<T> cont, size_t pos )
+{
+ gsl_Expects( pos < cont.size() );
+ return *( cont.begin() + pos );
+}
+#endif
+
+template< class T >
+gsl_NODISCARD gsl_api inline gsl_constexpr14 T &
+at( span<T> s, size_t pos )
+{
+ return s[ pos ];
+}
+
+//
+// GSL.views: views
+//
+
+//
+// not_null<> - Wrap any indirection and enforce non-null.
+//
+
+template< class T >
+class not_null;
+
+namespace detail {
+
+// helper class to figure out the pointed-to type of a pointer
+#if gsl_STDLIB_CPP11_OR_GREATER
+template< class T, class E = void >
+struct element_type_helper
+{
+ // For types without a member element_type (this will handle raw pointers)
+ typedef typename std::remove_reference< decltype( *std::declval<T>() ) >::type type;
+};
+
+template< class T >
+struct element_type_helper< T, std17::void_t< typename T::element_type > >
+{
+ // For types with a member element_type
+ typedef typename T::element_type type;
+};
+#else // ! gsl_STDLIB_CPP11_OR_GREATER
+// Pre-C++11, we cannot have decltype, so we cannot handle types without a member element_type
+template< class T, class E = void >
+struct element_type_helper
+{
+ typedef typename T::element_type type;
+};
+
+template< class T >
+struct element_type_helper< T* >
+{
+ typedef T type;
+};
+#endif // gsl_STDLIB_CPP11_OR_GREATER
+
+template< class T >
+struct is_not_null_or_bool_oracle : std11::false_type { };
+template< class T >
+struct is_not_null_or_bool_oracle< not_null<T> > : std11::true_type { };
+template<>
+struct is_not_null_or_bool_oracle< bool > : std11::true_type { };
+
+
+template< class T, bool IsCopyable = true >
+struct not_null_data;
+#if gsl_HAVE( MOVE_FORWARD )
+template< class T >
+struct not_null_data< T, false >
+{
+ T ptr_;
+
+ gsl_api gsl_constexpr14 not_null_data( T && _ptr ) gsl_noexcept
+ : ptr_( std::move( _ptr ) )
+ {
+ }
+
+ gsl_api gsl_constexpr14 not_null_data( not_null_data && other ) gsl_noexcept
+ : ptr_( std::move( other.ptr_ ) )
+ {
+ }
+ gsl_api gsl_constexpr14 not_null_data & operator=( not_null_data && other ) gsl_noexcept
+ {
+ ptr_ = std::move( other.ptr_ );
+ return *this;
+ }
+
+gsl_is_delete_access:
+ not_null_data( not_null_data const & ) gsl_is_delete;
+ not_null_data & operator=( not_null_data const & ) gsl_is_delete;
+};
+# if gsl_CONFIG_DEFAULTS_VERSION >= 1
+# endif // gsl_CONFIG_DEFAULTS_VERSION >= 1
+#endif // gsl_HAVE( MOVE_FORWARD )
+template< class T >
+struct not_null_data< T, true >
+{
+ T ptr_;
+
+ gsl_api gsl_constexpr14 not_null_data( T const & _ptr ) gsl_noexcept
+ : ptr_( _ptr )
+ {
+ }
+
+#if gsl_HAVE( MOVE_FORWARD )
+ gsl_api gsl_constexpr14 not_null_data( T && _ptr ) gsl_noexcept
+ : ptr_( std::move( _ptr ) )
+ {
+ }
+
+ gsl_api gsl_constexpr14 not_null_data( not_null_data && other ) gsl_noexcept
+ : ptr_( std::move( other.ptr_ ) )
+ {
+ }
+ gsl_api gsl_constexpr14 not_null_data & operator=( not_null_data && other ) gsl_noexcept
+ {
+ ptr_ = std::move( other.ptr_ );
+ return *this;
+ }
+#endif // gsl_HAVE( MOVE_FORWARD )
+
+ gsl_api gsl_constexpr14 not_null_data( not_null_data const & other )
+ : ptr_( other.ptr_ )
+ {
+ gsl_Expects( ptr_ != gsl_nullptr );
+ }
+ gsl_api gsl_constexpr14 not_null_data & operator=( not_null_data const & other )
+ {
+ gsl_Expects( other.ptr_ != gsl_nullptr );
+ ptr_ = other.ptr_;
+ return *this;
+ }
+};
+#if gsl_CONFIG_DEFAULTS_VERSION >= 1
+template< class T >
+struct not_null_data< T *, true >
+{
+ T * ptr_;
+
+ gsl_api gsl_constexpr14 not_null_data( T * _ptr ) gsl_noexcept
+ : ptr_( _ptr )
+ {
+ }
+};
+#endif // gsl_CONFIG_DEFAULTS_VERSION >= 1
+template< class T >
+struct is_copyable
+#if gsl_HAVE( TYPE_TRAITS )
+: std11::integral_constant< bool, std::is_copy_constructible<T>::value && std::is_copy_assignable<T>::value >
+#else
+: std11::true_type
+#endif
+{
+};
+#if gsl_HAVE( TYPE_TRAITS ) && gsl_HAVE( UNIQUE_PTR ) && gsl_BETWEEN( gsl_COMPILER_MSVC_VERSION, 1, 140 )
+// Type traits are buggy in VC++ 2013, so we explicitly declare `unique_ptr<>` non-copyable.
+template< class T, class Deleter >
+struct is_copyable< std::unique_ptr< T, Deleter > > : std11::false_type
+{
+};
+#endif
+
+template< class T >
+struct not_null_accessor;
+
+} // namespace detail
+
+template< class T >
+class not_null
+{
+private:
+ detail::not_null_data< T, detail::is_copyable< T >::value > data_;
+
+ // need to access `not_null<U>::data_`
+ template< class U >
+ friend class not_null;
+
+ template< class U >
+ friend struct detail::not_null_accessor;
+
+public:
+ typedef typename detail::element_type_helper<T>::type element_type;
+
+#if gsl_HAVE( TYPE_TRAITS )
+ static_assert( std::is_assignable<typename std::remove_const<typename std::remove_reference<T>::type>::type&, std::nullptr_t>::value, "T cannot be assigned nullptr." );
+#endif
+
+#if gsl_CONFIG( NOT_NULL_EXPLICIT_CTOR )
+# if gsl_HAVE( MOVE_FORWARD )
+ template< class U
+ // In Clang 3.x, `is_constructible<not_null<unique_ptr<X>>, unique_ptr<X>>` tries to instantiate the copy constructor of `unique_ptr<>`, triggering an error.
+ // Note that Apple Clang's `__clang_major__` etc. are different from regular Clang.
+# if gsl_HAVE( TYPE_TRAITS ) && gsl_HAVE( DEFAULT_FUNCTION_TEMPLATE_ARG ) && ! gsl_BETWEEN( gsl_COMPILER_CLANG_VERSION, 1, 400 ) && ! gsl_BETWEEN( gsl_COMPILER_APPLECLANG_VERSION, 1, 1001 )
+ // We *have* to use SFINAE with an NTTP arg here, otherwise the overload is ambiguous.
+ , typename std::enable_if< ( std::is_constructible<T, U>::value ), int >::type = 0
+# endif
+ >
+ gsl_api gsl_constexpr14 explicit not_null( U other )
+ : data_( T( std::move( other ) ) )
+ {
+ gsl_Expects( data_.ptr_ != gsl_nullptr );
+ }
+# else // a.k.a. ! gsl_HAVE( MOVE_FORWARD )
+ template< class U >
+ gsl_api gsl_constexpr14 explicit not_null( U const& other )
+ : data_( T( other ) )
+ {
+ gsl_Expects( data_.ptr_ != gsl_nullptr );
+ }
+# endif // gsl_HAVE( MOVE_FORWARD )
+#else // a.k.a. !gsl_CONFIG( NOT_NULL_EXPLICIT_CTOR )
+# if gsl_HAVE( MOVE_FORWARD )
+ // In Clang 3.x, `is_constructible<not_null<unique_ptr<X>>, unique_ptr<X>>` tries to instantiate the copy constructor of `unique_ptr<>`, triggering an error.
+ // Note that Apple Clang's `__clang_major__` etc. are different from regular Clang.
+# if gsl_HAVE( TYPE_TRAITS ) && gsl_HAVE( DEFAULT_FUNCTION_TEMPLATE_ARG ) && ! gsl_BETWEEN( gsl_COMPILER_CLANG_VERSION, 1, 400 ) && ! gsl_BETWEEN( gsl_COMPILER_APPLECLANG_VERSION, 1, 1001 )
+ template< class U
+ // We *have* to use SFINAE with an NTTP arg here, otherwise the overload is ambiguous.
+ , typename std::enable_if< ( std::is_constructible<T, U>::value && !std::is_convertible<U, T>::value ), int >::type = 0
+ >
+ gsl_api gsl_constexpr14 explicit not_null( U other )
+ : data_( T( std::move( other ) ) )
+ {
+ gsl_Expects( data_.ptr_ != gsl_nullptr );
+ }
+
+ template< class U
+ // We *have* to use SFINAE with an NTTP arg here, otherwise the overload is ambiguous.
+ , typename std::enable_if< ( std::is_convertible<U, T>::value ), int >::type = 0
+ >
+ gsl_api gsl_constexpr14 not_null( U other )
+ : data_( std::move( other ) )
+ {
+ gsl_Expects( data_.ptr_ != gsl_nullptr );
+ }
+# else // a.k.a. !( gsl_HAVE( TYPE_TRAITS ) && gsl_HAVE( DEFAULT_FUNCTION_TEMPLATE_ARG ) && ! gsl_BETWEEN( gsl_COMPILER_CLANG_VERSION, 1, 400 ) && ! gsl_BETWEEN( gsl_COMPILER_APPLECLANG_VERSION, 1, 1001 )
+ // If type_traits are not available, then we can't distinguish `is_convertible<>` and `is_constructible<>`, so we unconditionally permit implicit construction.
+ template< class U >
+ gsl_api gsl_constexpr14 not_null( U other )
+ : data_( T( std::move( other ) ) )
+ {
+ gsl_Expects( data_.ptr_ != gsl_nullptr );
+ }
+# endif // gsl_HAVE( TYPE_TRAITS ) && gsl_HAVE( DEFAULT_FUNCTION_TEMPLATE_ARG ) && ! gsl_BETWEEN( gsl_COMPILER_CLANG_VERSION, 1, 400 ) && ! gsl_BETWEEN( gsl_COMPILER_APPLECLANG_VERSION, 1, 1001 )
+# else // a.k.a. ! gsl_HAVE( MOVE_FORWARD )
+ template< class U >
+ gsl_api gsl_constexpr14 not_null( U const& other )
+ : data_( T( other ) )
+ {
+ gsl_Expects( data_.ptr_ != gsl_nullptr );
+ }
+# endif // gsl_HAVE( MOVE_FORWARD )
+#endif // gsl_CONFIG( NOT_NULL_EXPLICIT_CTOR )
+
+public:
+#if gsl_HAVE( MOVE_FORWARD )
+ // In Clang 3.x, `is_constructible<not_null<unique_ptr<X>>, unique_ptr<X>>` tries to instantiate the copy constructor of `unique_ptr<>`, triggering an error.
+ // Note that Apple Clang's `__clang_major__` etc. are different from regular Clang.
+# if gsl_HAVE( TYPE_TRAITS ) && gsl_HAVE( DEFAULT_FUNCTION_TEMPLATE_ARG ) && ! gsl_BETWEEN( gsl_COMPILER_CLANG_VERSION, 1, 400 ) && ! gsl_BETWEEN( gsl_COMPILER_APPLECLANG_VERSION, 1, 1001 )
+ template< class U
+ // We *have* to use SFINAE with an NTTP arg here, otherwise the overload is ambiguous.
+ , typename std::enable_if< ( std::is_constructible<T, U>::value && !std::is_convertible<U, T>::value ), int >::type = 0
+ >
+ gsl_api gsl_constexpr14 explicit not_null( not_null<U> other )
+ : data_( T( std::move( other.data_.ptr_ ) ) )
+ {
+ gsl_Expects( data_.ptr_ != gsl_nullptr );
+ }
+
+ template< class U
+ // We *have* to use SFINAE with an NTTP arg here, otherwise the overload is ambiguous.
+ , typename std::enable_if< ( std::is_convertible<U, T>::value ), int >::type = 0
+ >
+ gsl_api gsl_constexpr14 not_null( not_null<U> other )
+ : data_( T( std::move( other.data_.ptr_ ) ) )
+ {
+ gsl_Expects( data_.ptr_ != gsl_nullptr );
+ }
+# else // a.k.a. ! ( gsl_HAVE( TYPE_TRAITS ) && gsl_HAVE( DEFAULT_FUNCTION_TEMPLATE_ARG ) && ! gsl_BETWEEN( gsl_COMPILER_CLANG_VERSION, 1, 400 ) && ! gsl_BETWEEN( gsl_COMPILER_APPLECLANG_VERSION, 1, 1001 )
+ // If type_traits are not available, then we can't distinguish `is_convertible<>` and `is_constructible<>`, so we unconditionally permit implicit construction.
+ template< class U >
+ gsl_api gsl_constexpr14 not_null( not_null<U> other )
+ : data_( T( std::move( other.data_.ptr_ ) ) )
+ {
+ gsl_Expects( data_.ptr_ != gsl_nullptr );
+ }
+ template< class U >
+ gsl_api gsl_constexpr14 not_null<T>& operator=( not_null<U> other )
+ {
+ gsl_Expects( other.data_.ptr_ != gsl_nullptr );
+ data_.ptr_ = std::move( other.data_.ptr_ );
+ return *this;
+ }
+# endif // gsl_HAVE( TYPE_TRAITS ) && gsl_HAVE( DEFAULT_FUNCTION_TEMPLATE_ARG ) && ! gsl_BETWEEN( gsl_COMPILER_CLANG_VERSION, 1, 400 ) && ! gsl_BETWEEN( gsl_COMPILER_APPLECLANG_VERSION, 1, 1001 )
+#else // a.k.a. ! gsl_HAVE( MOVE_FORWARD )
+ template< class U >
+ gsl_api gsl_constexpr14 not_null( not_null<U> const& other )
+ : data_( T( other.data_.ptr_ ) )
+ {
+ gsl_Expects( data_.ptr_ != gsl_nullptr );
+ }
+ template< class U >
+ gsl_api gsl_constexpr14 not_null<T>& operator=( not_null<U> const & other )
+ {
+ gsl_Expects( other.data_.ptr_ != gsl_nullptr );
+ data_.ptr_ = other.data_.ptr_;
+ return *this;
+ }
+#endif // gsl_HAVE( MOVE_FORWARD )
+
+#if gsl_CONFIG( TRANSPARENT_NOT_NULL )
+ gsl_NODISCARD gsl_api gsl_constexpr14 element_type *
+ get() const
+ {
+ element_type * result = data_.ptr_.get();
+ gsl_Ensures( result != gsl_nullptr );
+ return result;
+ }
+#else
+# if gsl_CONFIG( NOT_NULL_GET_BY_CONST_REF )
+ gsl_NODISCARD gsl_api gsl_constexpr14 T const &
+ get() const
+ {
+ T const & result = data_.ptr_;
+ gsl_Ensures( result != gsl_nullptr );
+ return result;
+ }
+# else
+ gsl_NODISCARD gsl_api gsl_constexpr14 T
+ get() const
+ {
+ T result = data_.ptr_;
+ gsl_Ensures( result != gsl_nullptr );
+ return result;
+ }
+# endif
+#endif
+
+ // We want an implicit conversion operator that can be used to convert from both lvalues (by
+ // const reference or by copy) and rvalues (by move). So it seems like we could define
+ //
+ // template< class U >
+ // operator U const &() const & { ... }
+ // template< class U >
+ // operator U &&() && { ... }
+ //
+ // However, having two conversion operators with different return types renders the assignment
+ // operator of the result type ambiguous:
+ //
+ // not_null<std::unique_ptr<T>> p( ... );
+ // std::unique_ptr<U> q;
+ // q = std::move( p ); // ambiguous
+ //
+ // To avoid this ambiguity, we have both overloads of the conversion operator return `U`
+ // rather than `U const &` or `U &&`. This implies that converting an lvalue always induces
+ // a copy, which can cause unnecessary copies or even fail to compile in some situations:
+ //
+ // not_null<std::shared_ptr<T>> sp( ... );
+ // std::shared_ptr<U> const & rs = sp; // unnecessary copy
+ // std::unique_ptr<U> const & ru = p; // error: cannot copy `unique_ptr<T>`
+ //
+ // However, these situations are rather unusual, and the following, more frequent situations
+ // remain unimpaired:
+ //
+ // std::shared_ptr<U> vs = sp; // no extra copy
+ // std::unique_ptr<U> vu = std::move( p );
+
+#if gsl_HAVE( MOVE_FORWARD ) && gsl_HAVE( TYPE_TRAITS ) && gsl_HAVE( DEFAULT_FUNCTION_TEMPLATE_ARG ) && gsl_HAVE( EXPLICIT )
+ // explicit conversion operator
+
+ template< class U
+ // We *have* to use SFINAE with an NTTP arg here, otherwise the overload is ambiguous.
+ , typename std::enable_if< ( std::is_constructible<U, T const &>::value && !std::is_convertible<T, U>::value && !detail::is_not_null_or_bool_oracle<U>::value ), int >::type = 0
+ >
+ gsl_NODISCARD gsl_api gsl_constexpr14 explicit
+ operator U() const
+# if gsl_HAVE( FUNCTION_REF_QUALIFIER )
+ &
+# endif
+ {
+ U result( data_.ptr_ );
+ gsl_Ensures( result != gsl_nullptr );
+ return result;
+ }
+# if gsl_HAVE( FUNCTION_REF_QUALIFIER )
+ template< class U
+ // We *have* to use SFINAE with an NTTP arg here, otherwise the overload is ambiguous.
+ , typename std::enable_if< ( std::is_constructible<U, T>::value && !std::is_convertible<T, U>::value && !detail::is_not_null_or_bool_oracle<U>::value ), int >::type = 0
+ >
+ gsl_NODISCARD gsl_api gsl_constexpr14 explicit
+ operator U() &&
+ {
+ U result( std::move( data_.ptr_ ) );
+ gsl_Ensures( result != gsl_nullptr );
+ return result;
+ }
+# endif
+
+ // implicit conversion operator
+ template< class U
+ // We *have* to use SFINAE with an NTTP arg here, otherwise the overload is ambiguous.
+ , typename std::enable_if< ( std::is_constructible<U, T const &>::value && std::is_convertible<T, U>::value && !detail::is_not_null_or_bool_oracle<U>::value ), int >::type = 0
+ >
+ gsl_NODISCARD gsl_api gsl_constexpr14
+ operator U() const
+# if gsl_HAVE( FUNCTION_REF_QUALIFIER )
+ &
+# endif
+ {
+ U result( data_.ptr_ );
+ gsl_Ensures( result != gsl_nullptr );
+ return result;
+ }
+# if gsl_HAVE( FUNCTION_REF_QUALIFIER )
+ template< class U
+ // We *have* to use SFINAE with an NTTP arg here, otherwise the overload is ambiguous.
+ , typename std::enable_if< ( std::is_convertible<T, U>::value && !detail::is_not_null_or_bool_oracle<U>::value ), int >::type = 0
+ >
+ gsl_NODISCARD gsl_api gsl_constexpr14
+ operator U() &&
+ {
+ U result( std::move( data_.ptr_ ) );
+ gsl_Ensures( result != gsl_nullptr );
+ return result;
+ }
+# endif
+#else // a.k.a. #if !( gsl_HAVE( MOVE_FORWARD ) && gsl_HAVE( TYPE_TRAITS ) && gsl_HAVE( DEFAULT_FUNCTION_TEMPLATE_ARG ) && gsl_HAVE( EXPLICIT ) )
+ template< class U >
+ gsl_NODISCARD gsl_api gsl_constexpr14
+ operator U() const
+ {
+ U result( data_.ptr_ );
+ gsl_Ensures( result != gsl_nullptr );
+ return result;
+ }
+#endif // gsl_HAVE( MOVE_FORWARD ) && gsl_HAVE( TYPE_TRAITS ) && gsl_HAVE( DEFAULT_FUNCTION_TEMPLATE_ARG ) && gsl_HAVE( EXPLICIT )
+
+ gsl_NODISCARD gsl_api gsl_constexpr14 T const &
+ operator->() const
+ {
+ T const & result( data_.ptr_ );
+ gsl_Ensures( result != gsl_nullptr );
+ return result;
+ }
+
+ gsl_NODISCARD gsl_api gsl_constexpr14 element_type &
+ operator*() const
+ {
+ gsl_Expects( data_.ptr_ != gsl_nullptr );
+ return *data_.ptr_;
+ }
+
+#if gsl_HAVE( MOVE_FORWARD )
+ // Visual C++ 2013 doesn't generate default move constructors, so we declare them explicitly.
+ gsl_api gsl_constexpr14 not_null( not_null && other )
+ gsl_noexcept_not_testing // we want to be nothrow-movable despite the precondition check
+ : data_( std::move( other.data_ ) )
+ {
+ gsl_Expects( data_.ptr_ != gsl_nullptr );
+ }
+ gsl_api gsl_constexpr14 not_null & operator=( not_null && other )
+ gsl_noexcept_not_testing // we want to be nothrow-movable despite the precondition check
+ {
+ gsl_Expects( other.data_.ptr_ != gsl_nullptr || &other == this );
+ data_ = std::move( other.data_ );
+ return *this;
+ }
+#endif // gsl_HAVE( MOVE_FORWARD )
+
+#if gsl_HAVE( IS_DEFAULT )
+ gsl_constexpr14 not_null( not_null const & ) = default;
+ gsl_constexpr14 not_null & operator=( not_null const & ) = default;
+#endif
+
+ gsl_api gsl_constexpr20 friend void swap( not_null & lhs, not_null & rhs )
+ gsl_noexcept_not_testing // we want to be nothrow-swappable despite the precondition check
+ {
+ gsl_Expects( lhs.data_.ptr_ != gsl_nullptr && rhs.data_.ptr_ != gsl_nullptr );
+ using std::swap;
+ swap( lhs.data_.ptr_, rhs.data_.ptr_ );
+ }
+
+gsl_is_delete_access:
+ not_null() gsl_is_delete;
+ // prevent compilation when initialized with a nullptr or literal 0:
+#if gsl_HAVE( NULLPTR )
+ not_null( std::nullptr_t ) gsl_is_delete;
+ not_null & operator=( std::nullptr_t ) gsl_is_delete;
+#else
+ not_null( int ) gsl_is_delete;
+ not_null & operator=( int ) gsl_is_delete;
+#endif
+
+ // unwanted operators...pointers only point to single objects!
+ not_null & operator++() gsl_is_delete;
+ not_null & operator--() gsl_is_delete;
+ not_null operator++( int ) gsl_is_delete;
+ not_null operator--( int ) gsl_is_delete;
+ not_null & operator+ ( size_t ) gsl_is_delete;
+ not_null & operator+=( size_t ) gsl_is_delete;
+ not_null & operator- ( size_t ) gsl_is_delete;
+ not_null & operator-=( size_t ) gsl_is_delete;
+ not_null & operator+=( std::ptrdiff_t ) gsl_is_delete;
+ not_null & operator-=( std::ptrdiff_t ) gsl_is_delete;
+ void operator[]( std::ptrdiff_t ) const gsl_is_delete;
+};
+#if gsl_CONFIG_DEFAULTS_VERSION >= 1
+template< class T >
+class not_null< T * >
+{
+private:
+ detail::not_null_data<T *, true> data_;
+
+ // need to access `not_null<U>::data_`
+ template< class U >
+ friend class not_null;
+
+ template< class U >
+ friend struct detail::not_null_accessor;
+
+public:
+ typedef T element_type;
+
+ gsl_api gsl_constexpr14
+#if gsl_CONFIG( NOT_NULL_EXPLICIT_CTOR )
+ explicit
+#endif // gsl_CONFIG( NOT_NULL_EXPLICIT_CTOR )
+ not_null( T * other )
+ : data_( other )
+ {
+ gsl_Expects( data_.ptr_ != gsl_nullptr );
+ }
+
+#if gsl_HAVE( MOVE_FORWARD )
+ // In Clang 3.x, `is_constructible<not_null<unique_ptr<X>>, unique_ptr<X>>` tries to instantiate the copy constructor of `unique_ptr<>`, triggering an error.
+ // Note that Apple Clang's `__clang_major__` etc. are different from regular Clang.
+# if gsl_HAVE( TYPE_TRAITS ) && gsl_HAVE( DEFAULT_FUNCTION_TEMPLATE_ARG ) && ! gsl_BETWEEN( gsl_COMPILER_CLANG_VERSION, 1, 400 ) && ! gsl_BETWEEN( gsl_COMPILER_APPLECLANG_VERSION, 1, 1001 )
+ template< class U
+ // We *have* to use SFINAE with an NTTP arg here, otherwise the overload is ambiguous.
+ , typename std::enable_if< ( std::is_constructible<T*, U>::value && !std::is_convertible<U, T*>::value ), int >::type = 0
+ >
+ gsl_api gsl_constexpr14 explicit not_null( not_null<U> other )
+ : data_( static_cast<T*>( std::move( other.data_.ptr_ ) ) )
+ {
+ gsl_Expects( data_.ptr_ != gsl_nullptr );
+ }
+
+ template< class U
+ // We *have* to use SFINAE with an NTTP arg here, otherwise the overload is ambiguous.
+ , typename std::enable_if< ( std::is_convertible<U, T*>::value ), int >::type = 0
+ >
+ gsl_api gsl_constexpr14 not_null( not_null<U> other )
+ : data_( std::move( other.data_.ptr_ ) )
+ {
+ gsl_Expects( data_.ptr_ != gsl_nullptr );
+ }
+# else // a.k.a. ! ( gsl_HAVE( TYPE_TRAITS ) && gsl_HAVE( DEFAULT_FUNCTION_TEMPLATE_ARG ) && ! gsl_BETWEEN( gsl_COMPILER_CLANG_VERSION, 1, 400 ) && ! gsl_BETWEEN( gsl_COMPILER_APPLECLANG_VERSION, 1, 1001 )
+ // If type_traits are not available, then we can't distinguish `is_convertible<>` and `is_constructible<>`, so we unconditionally permit implicit construction.
+ template< class U >
+ gsl_api gsl_constexpr14 not_null( not_null<U> other )
+ : data_( std::move( other.data_.ptr_ ) )
+ {
+ gsl_Expects( data_.ptr_ != gsl_nullptr );
+ }
+ template< class U >
+ gsl_api gsl_constexpr14 not_null<T*>& operator=( not_null<U> other )
+ {
+ gsl_Expects( other.data_.ptr_ != gsl_nullptr );
+ data_.ptr_ = std::move( other.data_.ptr_ );
+ return *this;
+ }
+# endif // gsl_HAVE( TYPE_TRAITS ) && gsl_HAVE( DEFAULT_FUNCTION_TEMPLATE_ARG ) && ! gsl_BETWEEN( gsl_COMPILER_CLANG_VERSION, 1, 400 ) && ! gsl_BETWEEN( gsl_COMPILER_APPLECLANG_VERSION, 1, 1001 )
+#else // a.k.a. ! gsl_HAVE( MOVE_FORWARD )
+ template< class U >
+ gsl_api gsl_constexpr14 not_null( not_null<U> const& other )
+ : data_( other.data_.ptr_ )
+ {
+ gsl_Expects( data_.ptr_ != gsl_nullptr );
+ }
+ template< class U >
+ gsl_api gsl_constexpr14 not_null<T*>& operator=( not_null<U> const & other )
+ {
+ gsl_Expects( other.data_.ptr_ != gsl_nullptr );
+ data_.ptr_ = other.data_.ptr_;
+ return *this;
+ }
+#endif // gsl_HAVE( MOVE_FORWARD )
+
+#if ! gsl_CONFIG( TRANSPARENT_NOT_NULL )
+ gsl_NODISCARD gsl_api gsl_constexpr14 T*
+ get() const
+ {
+ return data_.ptr_;
+ }
+#endif
+
+#if gsl_HAVE( TYPE_TRAITS ) && gsl_HAVE( DEFAULT_FUNCTION_TEMPLATE_ARG ) && gsl_HAVE( EXPLICIT )
+ // explicit conversion operator
+ template< class U
+ // We *have* to use SFINAE with an NTTP arg here, otherwise the overload is ambiguous.
+ , typename std::enable_if< ( std::is_constructible<U, T*>::value && !std::is_convertible<T*, U>::value && !detail::is_not_null_or_bool_oracle<U>::value ), int >::type = 0
+ >
+ gsl_NODISCARD gsl_api gsl_constexpr14 explicit
+ operator U() const
+ {
+ return U( data_.ptr_ );
+ }
+
+ // implicit conversion operator
+ template< class U
+ // We *have* to use SFINAE with an NTTP arg here, otherwise the overload is ambiguous.
+ , typename std::enable_if< ( std::is_constructible<U, T*>::value && std::is_convertible<T*, U>::value && !detail::is_not_null_or_bool_oracle<U>::value ), int >::type = 0
+ >
+ gsl_NODISCARD gsl_api gsl_constexpr14
+ operator U() const
+ {
+ return data_.ptr_;
+ }
+#else // a.k.a. #if !( gsl_HAVE( MOVE_FORWARD ) && gsl_HAVE( TYPE_TRAITS ) && gsl_HAVE( DEFAULT_FUNCTION_TEMPLATE_ARG ) && gsl_HAVE( EXPLICIT ) )
+ template< class U >
+ gsl_NODISCARD gsl_api gsl_constexpr14
+ operator U() const
+ {
+ return data_.ptr_;
+ }
+#endif // gsl_HAVE( MOVE_FORWARD ) && gsl_HAVE( TYPE_TRAITS ) && gsl_HAVE( DEFAULT_FUNCTION_TEMPLATE_ARG ) && gsl_HAVE( EXPLICIT )
+
+ gsl_NODISCARD gsl_api gsl_constexpr14 T*
+ operator->() const
+ {
+ return data_.ptr_;
+ }
+
+ gsl_NODISCARD gsl_api gsl_constexpr14 element_type &
+ operator*() const
+ {
+ return *data_.ptr_;
+ }
+
+#if gsl_HAVE( IS_DEFAULT )
+ gsl_constexpr14 not_null( not_null const & ) = default;
+ gsl_constexpr14 not_null & operator=( not_null const & ) = default;
+#endif
+
+ gsl_api gsl_constexpr20 friend void swap( not_null & lhs, not_null & rhs ) gsl_noexcept
+ {
+ using std::swap;
+ swap( lhs.data_.ptr_, rhs.data_.ptr_ );
+ }
+
+gsl_is_delete_access:
+ not_null() gsl_is_delete;
+ // prevent compilation when initialized with a nullptr or literal 0:
+#if gsl_HAVE( NULLPTR )
+ not_null( std::nullptr_t ) gsl_is_delete;
+ not_null & operator=( std::nullptr_t ) gsl_is_delete;
+#else
+ not_null( int ) gsl_is_delete;
+ not_null & operator=( int ) gsl_is_delete;
+#endif
+
+ // unwanted operators...pointers only point to single objects!
+ not_null & operator++() gsl_is_delete;
+ not_null & operator--() gsl_is_delete;
+ not_null operator++( int ) gsl_is_delete;
+ not_null operator--( int ) gsl_is_delete;
+ not_null & operator+ ( size_t ) gsl_is_delete;
+ not_null & operator+=( size_t ) gsl_is_delete;
+ not_null & operator- ( size_t ) gsl_is_delete;
+ not_null & operator-=( size_t ) gsl_is_delete;
+ not_null & operator+=( std::ptrdiff_t ) gsl_is_delete;
+ not_null & operator-=( std::ptrdiff_t ) gsl_is_delete;
+ void operator[]( std::ptrdiff_t ) const gsl_is_delete;
+};
+#endif // gsl_CONFIG_DEFAULTS_VERSION >= 1
+#if gsl_HAVE( DEDUCTION_GUIDES )
+template< class U >
+not_null( U ) -> not_null<U>;
+template< class U >
+not_null( not_null<U> ) -> not_null<U>;
+#endif
+
+#if gsl_HAVE( NULLPTR )
+void make_not_null( std::nullptr_t ) gsl_is_delete;
+#endif // gsl_HAVE( NULLPTR )
+#if gsl_HAVE( MOVE_FORWARD )
+template< class U >
+gsl_NODISCARD gsl_api gsl_constexpr14 not_null<U>
+make_not_null( U u )
+{
+ return not_null<U>( std::move( u ) );
+}
+template< class U >
+gsl_NODISCARD gsl_api gsl_constexpr14 not_null<U>
+make_not_null( not_null<U> u )
+{
+ return std::move( u );
+}
+#else // a.k.a. ! gsl_HAVE( MOVE_FORWARD )
+template< class U >
+gsl_NODISCARD gsl_api not_null<U>
+make_not_null( U const & u )
+{
+ return not_null<U>( u );
+}
+template< class U >
+gsl_NODISCARD gsl_api not_null<U>
+make_not_null( not_null<U> const & u )
+{
+ return u;
+}
+#endif // gsl_HAVE( MOVE_FORWARD )
+
+namespace detail {
+
+template< class T >
+struct as_nullable_helper
+{
+ typedef T type;
+};
+template< class T >
+struct as_nullable_helper< not_null<T> >
+{
+};
+
+template< class T >
+struct not_null_accessor
+{
+#if gsl_HAVE( MOVE_FORWARD )
+ static gsl_api T get( not_null<T>&& p ) gsl_noexcept
+ {
+ return std::move( p.data_.ptr_ );
+ }
+#endif
+ static gsl_api T const & get( not_null<T> const & p ) gsl_noexcept
+ {
+ return p.data_.ptr_;
+ }
+};
+
+namespace no_adl {
+
+#if gsl_HAVE( MOVE_FORWARD )
+template< class T >
+gsl_NODISCARD gsl_api gsl_constexpr auto as_nullable( T && p )
+gsl_noexcept_if( std::is_nothrow_move_constructible<T>::value )
+-> typename detail::as_nullable_helper<typename std20::remove_cvref<T>::type>::type
+{
+ return std::move( p );
+}
+template< class T >
+gsl_NODISCARD gsl_api gsl_constexpr14 T as_nullable( not_null<T> && p )
+{
+ T result = detail::not_null_accessor<T>::get( std::move( p ) );
+ gsl_Expects( result != gsl_nullptr );
+ return result;
+}
+#else // ! gsl_HAVE( MOVE_FORWARD )
+template< class T >
+gsl_NODISCARD gsl_api gsl_constexpr T const & as_nullable( T const & p ) gsl_noexcept
+{
+ return p;
+}
+#endif // gsl_HAVE( MOVE_FORWARD )
+template< class T >
+gsl_NODISCARD gsl_api gsl_constexpr14 T const & as_nullable( not_null<T> const & p )
+{
+ T const & result = detail::not_null_accessor<T>::get( p );
+ gsl_Expects( result != gsl_nullptr );
+ return result;
+}
+template< class T >
+gsl_NODISCARD gsl_api gsl_constexpr T* as_nullable( not_null<T*> p ) gsl_noexcept
+{
+ return detail::not_null_accessor<T*>::get( p );
+}
+
+} // namespace no_adl
+} // namespace detail
+
+using namespace detail::no_adl;
+
+// not_null with implicit constructor, allowing copy-initialization:
+
+template< class T >
+class not_null_ic : public not_null<T>
+{
+public:
+ template< class U
+ gsl_ENABLE_IF_(( std::is_constructible<T, U>::value ))
+ >
+ gsl_api gsl_constexpr14
+#if gsl_HAVE( MOVE_FORWARD )
+ not_null_ic( U && u )
+ : not_null<T>( std::forward<U>( u ) )
+#else // ! gsl_HAVE( MOVE_FORWARD )
+ not_null_ic( U const & u )
+ : not_null<T>( u )
+#endif // gsl_HAVE( MOVE_FORWARD )
+ {}
+};
+
+// more not_null unwanted operators
+
+template< class T, class U >
+std::ptrdiff_t operator-( not_null<T> const &, not_null<U> const & ) gsl_is_delete;
+
+template< class T >
+not_null<T> operator-( not_null<T> const &, std::ptrdiff_t ) gsl_is_delete;
+
+template< class T >
+not_null<T> operator+( not_null<T> const &, std::ptrdiff_t ) gsl_is_delete;
+
+template< class T >
+not_null<T> operator+( std::ptrdiff_t, not_null<T> const & ) gsl_is_delete;
+
+// not_null comparisons
+
+#if gsl_HAVE( NULLPTR ) && gsl_HAVE( IS_DELETE )
+template< class T >
+gsl_constexpr bool
+operator==( not_null<T> const &, std::nullptr_t ) = delete;
+template< class T >
+gsl_constexpr bool
+operator==( std::nullptr_t , not_null<T> const & ) = delete;
+template< class T >
+gsl_constexpr bool
+operator!=( not_null<T> const &, std::nullptr_t ) = delete;
+template< class T >
+gsl_constexpr bool
+operator!=( std::nullptr_t , not_null<T> const & ) = delete;
+#endif // gsl_HAVE( NULLPTR ) && gsl_HAVE( IS_DELETE )
+
+template< class T, class U >
+gsl_NODISCARD inline gsl_api gsl_constexpr gsl_TRAILING_RETURN_TYPE_( bool )
+operator==( not_null<T> const & l, not_null<U> const & r )
+gsl_RETURN_DECLTYPE_( l.operator->() == r.operator->() )
+{
+ return l.operator->() == r.operator->();
+}
+template< class T, class U >
+gsl_NODISCARD inline gsl_api gsl_constexpr gsl_TRAILING_RETURN_TYPE_( bool )
+operator==( not_null<T> const & l, U const & r )
+gsl_RETURN_DECLTYPE_(l.operator->() == r )
+{
+ return l.operator->() == r;
+}
+template< class T, class U >
+gsl_NODISCARD inline gsl_api gsl_constexpr gsl_TRAILING_RETURN_TYPE_( bool )
+operator==( T const & l, not_null<U> const & r )
+gsl_RETURN_DECLTYPE_( l == r.operator->() )
+{
+ return l == r.operator->();
+}
+
+template< class T, class U >
+gsl_NODISCARD inline gsl_api gsl_constexpr gsl_TRAILING_RETURN_TYPE_( bool )
+operator<( not_null<T> const & l, not_null<U> const & r )
+gsl_RETURN_DECLTYPE_( l.operator->() < r.operator->() )
+{
+ return l.operator->() < r.operator->();
+}
+template< class T, class U >
+gsl_NODISCARD inline gsl_api gsl_constexpr gsl_TRAILING_RETURN_TYPE_( bool )
+operator<( not_null<T> const & l, U const & r )
+gsl_RETURN_DECLTYPE_( l.operator->() < r )
+{
+ return l.operator->() < r;
+}
+template< class T, class U >
+gsl_NODISCARD inline gsl_api gsl_constexpr gsl_TRAILING_RETURN_TYPE_( bool )
+operator<( T const & l, not_null<U> const & r )
+gsl_RETURN_DECLTYPE_( l < r.operator->() )
+{
+ return l < r.operator->();
+}
+
+template< class T, class U >
+gsl_NODISCARD inline gsl_api gsl_constexpr gsl_TRAILING_RETURN_TYPE_( bool )
+operator!=( not_null<T> const & l, not_null<U> const & r )
+gsl_RETURN_DECLTYPE_( !( l == r ) )
+{
+ return !( l == r );
+}
+template< class T, class U >
+gsl_NODISCARD inline gsl_api gsl_constexpr gsl_TRAILING_RETURN_TYPE_( bool )
+operator!=( not_null<T> const & l, U const & r )
+gsl_RETURN_DECLTYPE_( !( l == r ) )
+{
+ return !( l == r );
+}
+template< class T, class U >
+gsl_NODISCARD inline gsl_api gsl_constexpr gsl_TRAILING_RETURN_TYPE_( bool )
+operator!=( T const & l, not_null<U> const & r )
+gsl_RETURN_DECLTYPE_( !( l == r ) )
+{
+ return !( l == r );
+}
+
+template< class T, class U >
+gsl_NODISCARD inline gsl_api gsl_constexpr gsl_TRAILING_RETURN_TYPE_( bool )
+operator<=( not_null<T> const & l, not_null<U> const & r )
+gsl_RETURN_DECLTYPE_( !( r < l ) )
+{
+ return !( r < l );
+}
+template< class T, class U >
+gsl_NODISCARD inline gsl_api gsl_constexpr gsl_TRAILING_RETURN_TYPE_( bool )
+operator<=( not_null<T> const & l, U const & r )
+gsl_RETURN_DECLTYPE_( !( r < l ) )
+{
+ return !( r < l );
+}
+template< class T, class U >
+gsl_NODISCARD inline gsl_api gsl_constexpr gsl_TRAILING_RETURN_TYPE_( bool )
+operator<=( T const & l, not_null<U> const & r )
+gsl_RETURN_DECLTYPE_( !( r < l ) )
+{
+ return !( r < l );
+}
+
+template< class T, class U >
+gsl_NODISCARD inline gsl_api gsl_constexpr gsl_TRAILING_RETURN_TYPE_( bool )
+operator>( not_null<T> const & l, not_null<U> const & r )
+gsl_RETURN_DECLTYPE_( r < l )
+{
+ return r < l;
+}
+template< class T, class U >
+gsl_NODISCARD inline gsl_api gsl_constexpr gsl_TRAILING_RETURN_TYPE_( bool )
+operator>( not_null<T> const & l, U const & r )
+gsl_RETURN_DECLTYPE_( r < l )
+{
+ return r < l;
+}
+template< class T, class U >
+gsl_NODISCARD inline gsl_api gsl_constexpr gsl_TRAILING_RETURN_TYPE_( bool )
+operator>( T const & l, not_null<U> const & r )
+gsl_RETURN_DECLTYPE_( r < l )
+{
+ return r < l;
+}
+
+template< class T, class U >
+gsl_NODISCARD inline gsl_api gsl_constexpr gsl_TRAILING_RETURN_TYPE_( bool )
+operator>=( not_null<T> const & l, not_null<U> const & r )
+gsl_RETURN_DECLTYPE_( !( l < r ) )
+{
+ return !( l < r );
+}
+template< class T, class U >
+gsl_NODISCARD inline gsl_api gsl_constexpr gsl_TRAILING_RETURN_TYPE_( bool )
+operator>=( not_null<T> const & l, U const & r )
+gsl_RETURN_DECLTYPE_( !( l < r ) )
+{
+ return !( l < r );
+}
+template< class T, class U >
+gsl_NODISCARD inline gsl_api gsl_constexpr gsl_TRAILING_RETURN_TYPE_( bool )
+operator>=( T const & l, not_null<U> const & r )
+gsl_RETURN_DECLTYPE_( !( l < r ) )
+{
+ return !( l < r );
+}
+
+// print not_null
+
+template< class CharType, class Traits, class T >
+std::basic_ostream< CharType, Traits > & operator<<( std::basic_ostream< CharType, Traits > & os, not_null<T> const & p )
+{
+ return os << p.operator->();
+}
+
+
+//
+// Byte-specific type.
+//
+#if gsl_HAVE( ENUM_CLASS_CONSTRUCTION_FROM_UNDERLYING_TYPE )
+ enum class gsl_may_alias byte : unsigned char {};
+#else
+ struct gsl_may_alias byte { typedef unsigned char type; type v; };
+#endif
+
+template< class T >
+gsl_NODISCARD gsl_api inline gsl_constexpr byte
+to_byte( T v ) gsl_noexcept
+{
+#if gsl_HAVE( ENUM_CLASS_CONSTRUCTION_FROM_UNDERLYING_TYPE )
+ return static_cast<byte>( v );
+#elif gsl_HAVE( CONSTEXPR_11 )
+ return { static_cast<typename byte::type>( v ) };
+#else
+ byte b = { static_cast<typename byte::type>( v ) }; return b;
+#endif
+}
+
+template< class IntegerType gsl_ENABLE_IF_(( std::is_integral<IntegerType>::value )) >
+gsl_NODISCARD gsl_api inline gsl_constexpr IntegerType
+to_integer( byte b ) gsl_noexcept
+{
+#if gsl_HAVE( ENUM_CLASS_CONSTRUCTION_FROM_UNDERLYING_TYPE )
+ return static_cast<typename std::underlying_type<byte>::type>( b );
+#else
+ return b.v;
+#endif
+}
+
+gsl_NODISCARD gsl_api inline gsl_constexpr unsigned char
+to_uchar( byte b ) gsl_noexcept
+{
+ return to_integer<unsigned char>( b );
+}
+
+gsl_NODISCARD gsl_api inline gsl_constexpr unsigned char
+to_uchar( int i ) gsl_noexcept
+{
+ return static_cast<unsigned char>( i );
+}
+
+template< class IntegerType gsl_ENABLE_IF_(( std::is_integral<IntegerType>::value )) >
+gsl_api inline gsl_constexpr14 byte &
+operator<<=( byte & b, IntegerType shift ) gsl_noexcept
+{
+#if gsl_HAVE( ENUM_CLASS_CONSTRUCTION_FROM_UNDERLYING_TYPE )
+ return b = ::gsl::to_byte( ::gsl::to_uchar( b ) << shift );
+#else
+ b.v = ::gsl::to_uchar( b.v << shift ); return b;
+#endif
+}
+
+template< class IntegerType gsl_ENABLE_IF_(( std::is_integral<IntegerType>::value )) >
+gsl_NODISCARD gsl_api inline gsl_constexpr byte
+operator<<( byte b, IntegerType shift ) gsl_noexcept
+{
+ return ::gsl::to_byte( ::gsl::to_uchar( b ) << shift );
+}
+
+template< class IntegerType gsl_ENABLE_IF_(( std::is_integral<IntegerType>::value )) >
+gsl_NODISCARD gsl_api inline gsl_constexpr14 byte &
+operator>>=( byte & b, IntegerType shift ) gsl_noexcept
+{
+#if gsl_HAVE( ENUM_CLASS_CONSTRUCTION_FROM_UNDERLYING_TYPE )
+ return b = ::gsl::to_byte( ::gsl::to_uchar( b ) >> shift );
+#else
+ b.v = ::gsl::to_uchar( b.v >> shift ); return b;
+#endif
+}
+
+template< class IntegerType gsl_ENABLE_IF_(( std::is_integral<IntegerType>::value )) >
+gsl_NODISCARD gsl_api inline gsl_constexpr byte
+operator>>( byte b, IntegerType shift ) gsl_noexcept
+{
+ return ::gsl::to_byte( ::gsl::to_uchar( b ) >> shift );
+}
+
+#if gsl_HAVE( ENUM_CLASS_CONSTRUCTION_FROM_UNDERLYING_TYPE )
+gsl_DEFINE_ENUM_BITMASK_OPERATORS( byte )
+gsl_DEFINE_ENUM_RELATIONAL_OPERATORS( byte )
+#else // a.k.a. !gsl_HAVE( ENUM_CLASS_CONSTRUCTION_FROM_UNDERLYING_TYPE )
+gsl_api inline gsl_constexpr bool operator==( byte l, byte r ) gsl_noexcept
+{
+ return l.v == r.v;
+}
+
+gsl_api inline gsl_constexpr bool operator!=( byte l, byte r ) gsl_noexcept
+{
+ return !( l == r );
+}
+
+gsl_api inline gsl_constexpr bool operator< ( byte l, byte r ) gsl_noexcept
+{
+ return l.v < r.v;
+}
+
+gsl_api inline gsl_constexpr bool operator<=( byte l, byte r ) gsl_noexcept
+{
+ return !( r < l );
+}
+
+gsl_api inline gsl_constexpr bool operator> ( byte l, byte r ) gsl_noexcept
+{
+ return ( r < l );
+}
+
+gsl_api inline gsl_constexpr bool operator>=( byte l, byte r ) gsl_noexcept
+{
+ return !( l < r );
+}
+
+gsl_api inline gsl_constexpr14 byte & operator|=( byte & l, byte r ) gsl_noexcept
+{
+ l.v |= r.v; return l;
+}
+
+gsl_api inline gsl_constexpr byte operator|( byte l, byte r ) gsl_noexcept
+{
+ return ::gsl::to_byte( l.v | r.v );
+}
+
+gsl_api inline gsl_constexpr14 byte & operator&=( byte & l, byte r ) gsl_noexcept
+{
+ l.v &= r.v; return l;
+}
+
+gsl_api inline gsl_constexpr byte operator&( byte l, byte r ) gsl_noexcept
+{
+ return ::gsl::to_byte( l.v & r.v );
+}
+
+gsl_api inline gsl_constexpr14 byte & operator^=( byte & l, byte r ) gsl_noexcept
+{
+ l.v ^= r.v; return l;
+}
+
+gsl_api inline gsl_constexpr byte operator^( byte l, byte r ) gsl_noexcept
+{
+ return ::gsl::to_byte( l.v ^ r.v );
+}
+
+gsl_api inline gsl_constexpr byte operator~( byte b ) gsl_noexcept
+{
+ return ::gsl::to_byte( ~b.v );
+}
+#endif // gsl_HAVE( ENUM_CLASS_CONSTRUCTION_FROM_UNDERLYING_TYPE )
+
+#if gsl_FEATURE_TO_STD( WITH_CONTAINER )
+
+// Tag to select span constructor taking a container:
+
+struct with_container_t { gsl_constexpr with_container_t( ) gsl_noexcept { } };
+const gsl_constexpr with_container_t with_container; // TODO: this can lead to ODR violations because the symbol will be defined in multiple translation units
+
+#endif
+
+namespace detail {
+
+template< class T >
+gsl_api gsl_constexpr14 T * endptr( T * data, gsl_CONFIG_SPAN_INDEX_TYPE size )
+{
+ // Be sure to run the check before doing pointer arithmetics, which would be UB for `nullptr` and non-0 integers.
+ gsl_Expects( size == 0 || data != gsl_nullptr );
+ return data + size;
+}
+
+} // namespace detail
+
+//
+// span<> - A 1D view of contiguous T's, replace (*,len).
+//
+template< class T >
+class span
+{
+ template< class U > friend class span;
+
+public:
+ typedef gsl_CONFIG_SPAN_INDEX_TYPE index_type;
+
+ typedef T element_type;
+ typedef typename std11::remove_cv< T >::type value_type;
+
+ typedef T & reference;
+ typedef T * pointer;
+ typedef T const * const_pointer;
+ typedef T const & const_reference;
+
+ typedef pointer iterator;
+ typedef const_pointer const_iterator;
+
+ typedef std::reverse_iterator< iterator > reverse_iterator;
+ typedef std::reverse_iterator< const_iterator > const_reverse_iterator;
+
+ typedef gsl_CONFIG_SPAN_INDEX_TYPE size_type;
+ typedef std::ptrdiff_t difference_type;
+
+ // 26.7.3.2 Constructors, copy, and assignment [span.cons]
+
+ gsl_api gsl_constexpr span() gsl_noexcept
+ : first_( gsl_nullptr )
+ , last_ ( gsl_nullptr )
+ {
+ }
+
+#if ! gsl_DEPRECATE_TO_LEVEL( 5 )
+
+#if gsl_HAVE( NULLPTR )
+ gsl_api gsl_constexpr14 span( std::nullptr_t, index_type size_in )
+ : first_( nullptr )
+ , last_ ( nullptr )
+ {
+ gsl_Expects( size_in == 0 );
+ }
+#endif
+
+#if gsl_HAVE( IS_DELETE )
+ gsl_DEPRECATED
+ gsl_api gsl_constexpr span( reference data_in )
+ : span( &data_in, 1 )
+ {}
+
+ gsl_api gsl_constexpr span( element_type && ) = delete;
+#endif
+
+#endif // deprecate
+
+ gsl_api gsl_constexpr14 span( pointer data_in, index_type size_in )
+ : first_( data_in )
+ , last_( detail::endptr( data_in, size_in ) )
+ {
+ }
+
+ gsl_api gsl_constexpr14 span( pointer first_in, pointer last_in )
+ : first_( first_in )
+ , last_ ( last_in )
+ {
+ gsl_Expects( first_in <= last_in );
+ }
+
+#if ! gsl_DEPRECATE_TO_LEVEL( 5 )
+
+ template< class U >
+ gsl_api gsl_constexpr14 span( U * data_in, index_type size_in )
+ : first_( data_in )
+ , last_( detail::endptr( data_in, size_in ) )
+ {
+ }
+
+#endif // deprecate
+
+#if ! gsl_DEPRECATE_TO_LEVEL( 5 )
+ template< class U, size_t N >
+ gsl_api gsl_constexpr span( U (&arr)[N] ) gsl_noexcept
+ : first_( gsl_ADDRESSOF( arr[0] ) )
+ , last_ ( gsl_ADDRESSOF( arr[0] ) + N )
+ {}
+#else
+ template< size_t N
+ gsl_ENABLE_IF_(( std::is_convertible<value_type(*)[], element_type(*)[] >::value ))
+ >
+ gsl_api gsl_constexpr span( element_type (&arr)[N] ) gsl_noexcept
+ : first_( gsl_ADDRESSOF( arr[0] ) )
+ , last_ ( gsl_ADDRESSOF( arr[0] ) + N )
+ {}
+#endif // deprecate
+
+#if gsl_HAVE( ARRAY )
+#if ! gsl_DEPRECATE_TO_LEVEL( 5 )
+
+ template< class U, size_t N >
+ gsl_api gsl_constexpr span( std::array< U, N > & arr )
+ : first_( arr.data() )
+ , last_ ( arr.data() + N )
+ {}
+
+ template< class U, size_t N >
+ gsl_api gsl_constexpr span( std::array< U, N > const & arr )
+ : first_( arr.data() )
+ , last_ ( arr.data() + N )
+ {}
+
+#else
+
+ template< size_t N
+ gsl_ENABLE_IF_(( std::is_convertible<value_type(*)[], element_type(*)[] >::value ))
+ >
+ gsl_constexpr span( std::array< value_type, N > & arr )
+ : first_( arr.data() )
+ , last_ ( arr.data() + N )
+ {}
+
+ template< size_t N
+ gsl_ENABLE_IF_(( std::is_convertible<value_type(*)[], element_type(*)[] >::value ))
+ >
+ gsl_constexpr span( std::array< value_type, N > const & arr )
+ : first_( arr.data() )
+ , last_ ( arr.data() + N )
+ {}
+
+#endif // deprecate
+#endif // gsl_HAVE( ARRAY )
+
+#if gsl_HAVE( CONSTRAINED_SPAN_CONTAINER_CTOR )
+ template< class Container
+ gsl_ENABLE_IF_(( detail::is_compatible_container< Container, element_type >::value ))
+ >
+ gsl_api gsl_constexpr span( Container & cont ) gsl_noexcept
+ : first_( std17::data( cont ) )
+ , last_ ( std17::data( cont ) + std17::size( cont ) )
+ {}
+
+ template< class Container
+ gsl_ENABLE_IF_((
+ std::is_const< element_type >::value
+ && detail::is_compatible_container< Container, element_type >::value
+ ))
+ >
+ gsl_api gsl_constexpr span( Container const & cont ) gsl_noexcept
+ : first_( std17::data( cont ) )
+ , last_ ( std17::data( cont ) + std17::size( cont ) )
+ {}
+
+#elif gsl_HAVE( UNCONSTRAINED_SPAN_CONTAINER_CTOR )
+
+ template< class Container >
+ gsl_constexpr span( Container & cont )
+ : first_( cont.size() == 0 ? gsl_nullptr : gsl_ADDRESSOF( cont[0] ) )
+ , last_ ( cont.size() == 0 ? gsl_nullptr : gsl_ADDRESSOF( cont[0] ) + cont.size() )
+ {}
+
+ template< class Container >
+ gsl_constexpr span( Container const & cont )
+ : first_( cont.size() == 0 ? gsl_nullptr : gsl_ADDRESSOF( cont[0] ) )
+ , last_ ( cont.size() == 0 ? gsl_nullptr : gsl_ADDRESSOF( cont[0] ) + cont.size() )
+ {}
+
+#endif
+
+#if gsl_FEATURE_TO_STD( WITH_CONTAINER )
+
+ template< class Container >
+ gsl_constexpr span( with_container_t, Container & cont ) gsl_noexcept
+ : first_( cont.size() == 0 ? gsl_nullptr : gsl_ADDRESSOF( cont[0] ) )
+ , last_ ( cont.size() == 0 ? gsl_nullptr : gsl_ADDRESSOF( cont[0] ) + cont.size() )
+ {}
+
+ template< class Container >
+ gsl_constexpr span( with_container_t, Container const & cont ) gsl_noexcept
+ : first_( cont.size() == 0 ? gsl_nullptr : gsl_ADDRESSOF( cont[0] ) )
+ , last_ ( cont.size() == 0 ? gsl_nullptr : gsl_ADDRESSOF( cont[0] ) + cont.size() )
+ {}
+
+#endif
+
+#if !gsl_DEPRECATE_TO_LEVEL( 4 )
+ // constructor taking shared_ptr deprecated since 0.29.0
+
+# if gsl_HAVE( SHARED_PTR )
+ gsl_DEPRECATED
+ gsl_constexpr span( shared_ptr<element_type> const & ptr )
+ : first_( ptr.get() )
+ , last_ ( ptr.get() ? ptr.get() + 1 : gsl_nullptr )
+ {}
+# endif
+
+ // constructors taking unique_ptr deprecated since 0.29.0
+
+# if gsl_HAVE( UNIQUE_PTR )
+# if gsl_HAVE( DEFAULT_FUNCTION_TEMPLATE_ARG )
+ template< class ArrayElementType = typename std::add_pointer<element_type>::type >
+# else
+ template< class ArrayElementType >
+# endif
+ gsl_DEPRECATED
+ gsl_constexpr span( unique_ptr<ArrayElementType> const & ptr, index_type count )
+ : first_( ptr.get() )
+ , last_ ( ptr.get() + count )
+ {}
+
+ gsl_DEPRECATED
+ gsl_constexpr span( unique_ptr<element_type> const & ptr )
+ : first_( ptr.get() )
+ , last_ ( ptr.get() ? ptr.get() + 1 : gsl_nullptr )
+ {}
+# endif
+
+#endif // deprecate shared_ptr, unique_ptr
+
+#if gsl_HAVE( IS_DEFAULT ) && ! gsl_BETWEEN( gsl_COMPILER_GNUC_VERSION, 430, 600)
+ gsl_constexpr span( span && ) gsl_noexcept = default;
+ gsl_constexpr span( span const & ) = default;
+#else
+ gsl_api gsl_constexpr span( span const & other )
+ : first_( other.begin() )
+ , last_ ( other.end() )
+ {}
+#endif
+
+#if gsl_HAVE( IS_DEFAULT )
+ gsl_constexpr14 span & operator=( span && ) gsl_noexcept = default;
+ gsl_constexpr14 span & operator=( span const & ) gsl_noexcept = default;
+#else
+ gsl_constexpr14 span & operator=( span other ) gsl_noexcept
+ {
+ first_ = other.first_;
+ last_ = other.last_;
+ return *this;
+ }
+#endif
+
+ template< class U
+ gsl_ENABLE_IF_(( std::is_convertible<U(*)[], element_type(*)[]>::value ))
+ >
+ gsl_api gsl_constexpr span( span<U> const & other )
+ : first_( other.begin() )
+ , last_ ( other.end() )
+ {}
+
+#if 0
+ // Converting from other span ?
+ template< class U > operator=();
+#endif
+
+ // 26.7.3.3 Subviews [span.sub]
+
+ gsl_NODISCARD gsl_api gsl_constexpr14 span
+ first( index_type count ) const
+ {
+ gsl_Expects( std::size_t( count ) <= std::size_t( this->size() ) );
+ return span( this->data(), count );
+ }
+
+ gsl_NODISCARD gsl_api gsl_constexpr14 span
+ last( index_type count ) const
+ {
+ gsl_Expects( std::size_t( count ) <= std::size_t( this->size() ) );
+ return span( this->data() + this->size() - count, count );
+ }
+
+ gsl_NODISCARD gsl_api gsl_constexpr14 span
+ subspan( index_type offset ) const
+ {
+ gsl_Expects( std::size_t( offset ) <= std::size_t( this->size() ) );
+ return span( this->data() + offset, this->size() - offset );
+ }
+
+ gsl_NODISCARD gsl_api gsl_constexpr14 span
+ subspan( index_type offset, index_type count ) const
+ {
+ gsl_Expects(
+ std::size_t( offset ) <= std::size_t( this->size() ) &&
+ std::size_t( count ) <= std::size_t( this->size() - offset ) );
+ return span( this->data() + offset, count );
+ }
+
+ // 26.7.3.4 Observers [span.obs]
+
+ gsl_NODISCARD gsl_api gsl_constexpr index_type
+ size() const gsl_noexcept
+ {
+ return narrow_cast<index_type>( last_ - first_ );
+ }
+
+ gsl_NODISCARD gsl_api gsl_constexpr std::ptrdiff_t
+ ssize() const gsl_noexcept
+ {
+ return narrow_cast<std::ptrdiff_t>( last_ - first_ );
+ }
+
+ gsl_NODISCARD gsl_api gsl_constexpr index_type
+ size_bytes() const gsl_noexcept
+ {
+ return size() * narrow_cast<index_type>( sizeof( element_type ) );
+ }
+
+ gsl_NODISCARD gsl_api gsl_constexpr bool
+ empty() const gsl_noexcept
+ {
+ return size() == 0;
+ }
+
+ // 26.7.3.5 Element access [span.elem]
+
+ gsl_NODISCARD gsl_api gsl_constexpr14 reference
+ operator[]( index_type pos ) const
+ {
+ gsl_Expects( pos < size() );
+ return first_[ pos ];
+ }
+
+#if ! gsl_DEPRECATE_TO_LEVEL( 6 )
+ gsl_DEPRECATED_MSG("use subscript indexing instead")
+ gsl_api gsl_constexpr14 reference
+ operator()( index_type pos ) const
+ {
+ return (*this)[ pos ];
+ }
+
+ gsl_DEPRECATED_MSG("use subscript indexing instead")
+ gsl_api gsl_constexpr14 reference
+ at( index_type pos ) const
+ {
+ return (*this)[ pos ];
+ }
+#endif // deprecate
+
+ gsl_NODISCARD gsl_api gsl_constexpr14 reference
+ front() const
+ {
+ gsl_Expects( first_ != last_ );
+ return *first_;
+ }
+
+ gsl_NODISCARD gsl_api gsl_constexpr14 reference
+ back() const
+ {
+ gsl_Expects( first_ != last_ );
+ return *(last_ - 1);
+ }
+
+ gsl_NODISCARD gsl_api gsl_constexpr pointer
+ data() const gsl_noexcept
+ {
+ return first_;
+ }
+
+ // 26.7.3.6 Iterator support [span.iterators]
+
+ gsl_NODISCARD gsl_api gsl_constexpr iterator
+ begin() const gsl_noexcept
+ {
+ return iterator( first_ );
+ }
+
+ gsl_NODISCARD gsl_api gsl_constexpr iterator
+ end() const gsl_noexcept
+ {
+ return iterator( last_ );
+ }
+
+ gsl_NODISCARD gsl_api gsl_constexpr const_iterator
+ cbegin() const gsl_noexcept
+ {
+#if gsl_CPP11_OR_GREATER
+ return { begin() };
+#else
+ return const_iterator( begin() );
+#endif
+ }
+
+ gsl_NODISCARD gsl_api gsl_constexpr const_iterator
+ cend() const gsl_noexcept
+ {
+#if gsl_CPP11_OR_GREATER
+ return { end() };
+#else
+ return const_iterator( end() );
+#endif
+ }
+
+ gsl_NODISCARD gsl_constexpr17 reverse_iterator
+ rbegin() const gsl_noexcept
+ {
+ return reverse_iterator( end() );
+ }
+
+ gsl_NODISCARD gsl_constexpr17 reverse_iterator
+ rend() const gsl_noexcept
+ {
+ return reverse_iterator( begin() );
+ }
+
+ gsl_NODISCARD gsl_constexpr17 const_reverse_iterator
+ crbegin() const gsl_noexcept
+ {
+ return const_reverse_iterator( cend() );
+ }
+
+ gsl_NODISCARD gsl_constexpr17 const_reverse_iterator
+ crend() const gsl_noexcept
+ {
+ return const_reverse_iterator( cbegin() );
+ }
+
+ gsl_constexpr14 void swap( span & other ) gsl_noexcept
+ {
+ std::swap( first_, other.first_ );
+ std::swap( last_ , other.last_ );
+ }
+
+#if ! gsl_DEPRECATE_TO_LEVEL( 3 )
+ // member length() deprecated since 0.29.0
+
+ gsl_DEPRECATED_MSG("use size() instead")
+ gsl_api gsl_constexpr index_type length() const gsl_noexcept
+ {
+ return size();
+ }
+
+ // member length_bytes() deprecated since 0.29.0
+
+ gsl_DEPRECATED_MSG("use size_bytes() instead")
+ gsl_api gsl_constexpr index_type length_bytes() const gsl_noexcept
+ {
+ return size_bytes();
+ }
+#endif
+
+#if ! gsl_DEPRECATE_TO_LEVEL( 2 )
+ // member as_bytes(), as_writeable_bytes deprecated since 0.17.0
+
+ gsl_DEPRECATED_MSG("use free function gsl::as_bytes() instead")
+ gsl_api span< const byte > as_bytes() const gsl_noexcept
+ {
+ return span< const byte >( reinterpret_cast<const byte *>( data() ), size_bytes() ); // NOLINT
+ }
+
+ gsl_DEPRECATED_MSG("use free function gsl::as_writable_bytes() instead")
+ gsl_api span< byte > as_writeable_bytes() const gsl_noexcept
+ {
+ return span< byte >( reinterpret_cast<byte *>( data() ), size_bytes() ); // NOLINT
+ }
+
+#endif
+
+ template< class U >
+ gsl_NODISCARD gsl_api span< U >
+ as_span() const
+ {
+ gsl_Expects( ( this->size_bytes() % sizeof(U) ) == 0 );
+ return span< U >( reinterpret_cast<U *>( this->data() ), this->size_bytes() / sizeof( U ) ); // NOLINT
+ }
+
+private:
+ pointer first_;
+ pointer last_;
+};
+
+// class template argument deduction guides:
+
+#if gsl_HAVE( DEDUCTION_GUIDES ) // gsl_CPP17_OR_GREATER
+
+template< class T, size_t N >
+span( T (&)[N] ) -> span<T /*, N*/>;
+
+template< class T, size_t N >
+span( std::array<T, N> & ) -> span<T /*, N*/>;
+
+template< class T, size_t N >
+span( std::array<T, N> const & ) -> span<const T /*, N*/>;
+
+template< class Container >
+span( Container& ) -> span<typename Container::value_type>;
+
+template< class Container >
+span( Container const & ) -> span<const typename Container::value_type>;
+
+#endif // gsl_HAVE( DEDUCTION_GUIDES )
+
+// 26.7.3.7 Comparison operators [span.comparison]
+
+#if gsl_CONFIG( ALLOWS_SPAN_COMPARISON )
+# if gsl_CONFIG( ALLOWS_NONSTRICT_SPAN_COMPARISON )
+
+template< class T, class U >
+gsl_SUPPRESS_MSGSL_WARNING(stl.1)
+gsl_NODISCARD inline gsl_constexpr bool operator==( span<T> const & l, span<U> const & r )
+{
+ return l.size() == r.size()
+ && (l.begin() == r.begin() || std98::equal( l.begin(), l.end(), r.begin() ) );
+}
+
+template< class T, class U >
+gsl_SUPPRESS_MSGSL_WARNING(stl.1)
+gsl_NODISCARD inline gsl_constexpr bool operator< ( span<T> const & l, span<U> const & r )
+{
+ return std98::lexicographical_compare( l.begin(), l.end(), r.begin(), r.end() );
+}
+
+# else // a.k.a. !gsl_CONFIG( ALLOWS_NONSTRICT_SPAN_COMPARISON )
+
+template< class T >
+gsl_SUPPRESS_MSGSL_WARNING(stl.1)
+gsl_NODISCARD inline gsl_constexpr bool operator==( span<T> const & l, span<T> const & r )
+{
+ return l.size() == r.size()
+ && (l.begin() == r.begin() || std98::equal( l.begin(), l.end(), r.begin() ) );
+}
+
+template< class T >
+gsl_SUPPRESS_MSGSL_WARNING(stl.1)
+gsl_NODISCARD inline gsl_constexpr bool operator< ( span<T> const & l, span<T> const & r )
+{
+ return std98::lexicographical_compare( l.begin(), l.end(), r.begin(), r.end() );
+}
+# endif // gsl_CONFIG( ALLOWS_NONSTRICT_SPAN_COMPARISON )
+
+template< class T, class U >
+gsl_NODISCARD inline gsl_constexpr bool operator!=( span<T> const & l, span<U> const & r )
+{
+ return !( l == r );
+}
+
+template< class T, class U >
+gsl_NODISCARD inline gsl_constexpr bool operator<=( span<T> const & l, span<U> const & r )
+{
+ return !( r < l );
+}
+
+template< class T, class U >
+gsl_NODISCARD inline gsl_constexpr bool operator> ( span<T> const & l, span<U> const & r )
+{
+ return ( r < l );
+}
+
+template< class T, class U >
+gsl_NODISCARD inline gsl_constexpr bool operator>=( span<T> const & l, span<U> const & r )
+{
+ return !( l < r );
+}
+#endif // gsl_CONFIG( ALLOWS_SPAN_COMPARISON )
+
+// span algorithms
+
+template< class T >
+gsl_NODISCARD gsl_api inline gsl_constexpr std::size_t
+size( span<T> const & spn )
+{
+ return static_cast<std::size_t>( spn.size() );
+}
+
+template< class T >
+gsl_NODISCARD gsl_api inline gsl_constexpr std::ptrdiff_t
+ssize( span<T> const & spn )
+{
+ return spn.ssize();
+}
+
+namespace detail {
+
+template< class II, class N, class OI >
+gsl_api gsl_constexpr14 inline OI copy_n( II first, N count, OI result )
+{
+ if ( count > 0 )
+ {
+ *result++ = *first;
+ for ( N i = 1; i < count; ++i )
+ {
+ *result++ = *++first;
+ }
+ }
+ return result;
+}
+}
+
+template< class T, class U >
+gsl_api gsl_constexpr14 inline void copy( span<T> src, span<U> dest )
+{
+#if gsl_CPP14_OR_GREATER // gsl_HAVE( TYPE_TRAITS ) (circumvent Travis clang 3.4)
+ static_assert( std::is_assignable<U &, T const &>::value, "Cannot assign elements of source span to elements of destination span" );
+#endif
+ gsl_Expects( dest.size() >= src.size() );
+ detail::copy_n( src.data(), src.size(), dest.data() );
+}
+
+// span creator functions (see ctors)
+
+template< class T >
+gsl_NODISCARD gsl_api inline span< const byte >
+as_bytes( span<T> spn ) gsl_noexcept
+{
+ return span< const byte >( reinterpret_cast<const byte *>( spn.data() ), spn.size_bytes() ); // NOLINT
+}
+
+template< class T>
+gsl_NODISCARD gsl_api inline span< byte >
+as_writable_bytes( span<T> spn ) gsl_noexcept
+{
+ return span< byte >( reinterpret_cast<byte *>( spn.data() ), spn.size_bytes() ); // NOLINT
+}
+
+#if ! gsl_DEPRECATE_TO_LEVEL( 6 )
+template< class T>
+gsl_DEPRECATED_MSG("use as_writable_bytes() (different spelling) instead")
+gsl_api inline span< byte > as_writeable_bytes( span<T> spn ) gsl_noexcept
+{
+ return span< byte >( reinterpret_cast<byte *>( spn.data() ), spn.size_bytes() ); // NOLINT
+}
+#endif // deprecate
+
+#if gsl_FEATURE_TO_STD( MAKE_SPAN )
+
+template< class T >
+gsl_NODISCARD gsl_api inline gsl_constexpr span<T>
+make_span( T * ptr, typename span<T>::index_type count )
+{
+ return span<T>( ptr, count );
+}
+
+template< class T >
+gsl_NODISCARD gsl_api inline gsl_constexpr span<T>
+make_span( T * first, T * last )
+{
+ return span<T>( first, last );
+}
+
+template< class T, size_t N >
+gsl_NODISCARD inline gsl_constexpr span<T>
+make_span( T (&arr)[N] )
+{
+ return span<T>( gsl_ADDRESSOF( arr[0] ), N );
+}
+
+#if gsl_HAVE( ARRAY )
+
+template< class T, size_t N >
+gsl_NODISCARD inline gsl_constexpr span<T>
+make_span( std::array<T,N> & arr )
+{
+ return span<T>( arr );
+}
+
+template< class T, size_t N >
+gsl_NODISCARD inline gsl_constexpr span<const T>
+make_span( std::array<T,N> const & arr )
+{
+ return span<const T>( arr );
+}
+#endif
+
+#if gsl_HAVE( CONSTRAINED_SPAN_CONTAINER_CTOR ) && gsl_HAVE( AUTO )
+
+template< class Container, class EP = decltype( std17::data(std::declval<Container&>())) >
+gsl_NODISCARD inline gsl_constexpr auto
+make_span( Container & cont ) -> span< typename std::remove_pointer<EP>::type >
+{
+ return span< typename std::remove_pointer<EP>::type >( cont );
+}
+
+template< class Container, class EP = decltype( std17::data(std::declval<Container&>())) >
+gsl_NODISCARD inline gsl_constexpr auto
+make_span( Container const & cont ) -> span< const typename std::remove_pointer<EP>::type >
+{
+ return span< const typename std::remove_pointer<EP>::type >( cont );
+}
+
+#else
+
+template< class T >
+inline span<T>
+make_span( std::vector<T> & cont )
+{
+ return span<T>( with_container, cont );
+}
+
+template< class T >
+inline span<const T>
+make_span( std::vector<T> const & cont )
+{
+ return span<const T>( with_container, cont );
+}
+#endif
+
+#if gsl_FEATURE_TO_STD( WITH_CONTAINER )
+
+template< class Container >
+gsl_NODISCARD inline gsl_constexpr span<typename Container::value_type>
+make_span( with_container_t, Container & cont ) gsl_noexcept
+{
+ return span< typename Container::value_type >( with_container, cont );
+}
+
+template< class Container >
+gsl_NODISCARD inline gsl_constexpr span<const typename Container::value_type>
+make_span( with_container_t, Container const & cont ) gsl_noexcept
+{
+ return span< const typename Container::value_type >( with_container, cont );
+}
+
+#endif // gsl_FEATURE_TO_STD( WITH_CONTAINER )
+
+#if !gsl_DEPRECATE_TO_LEVEL( 4 )
+template< class Ptr >
+gsl_DEPRECATED
+inline span<typename Ptr::element_type>
+make_span( Ptr & ptr )
+{
+ return span<typename Ptr::element_type>( ptr );
+}
+#endif // !gsl_DEPRECATE_TO_LEVEL( 4 )
+
+template< class Ptr >
+gsl_DEPRECATED
+inline span<typename Ptr::element_type>
+make_span( Ptr & ptr, typename span<typename Ptr::element_type>::index_type count )
+{
+ return span<typename Ptr::element_type>( ptr, count );
+}
+
+#endif // gsl_FEATURE_TO_STD( MAKE_SPAN )
+
+#if gsl_FEATURE_TO_STD( BYTE_SPAN )
+
+template< class T >
+gsl_NODISCARD gsl_api inline gsl_constexpr span<byte>
+byte_span( T & t ) gsl_noexcept
+{
+ return span<byte>( reinterpret_cast<byte *>( &t ), sizeof(T) );
+}
+
+template< class T >
+gsl_NODISCARD gsl_api inline gsl_constexpr span<const byte>
+byte_span( T const & t ) gsl_noexcept
+{
+ return span<const byte>( reinterpret_cast<byte const *>( &t ), sizeof(T) );
+}
+
+#endif // gsl_FEATURE_TO_STD( BYTE_SPAN )
+
+//
+// basic_string_span:
+//
+
+template< class T >
+class basic_string_span;
+
+namespace detail {
+
+template< class T >
+struct is_basic_string_span_oracle : std11::false_type {};
+
+template< class T >
+struct is_basic_string_span_oracle< basic_string_span<T> > : std11::true_type {};
+
+template< class T >
+struct is_basic_string_span : is_basic_string_span_oracle< typename std11::remove_cv<T>::type > {};
+
+template< class T >
+gsl_api inline gsl_constexpr14 std::size_t string_length( T * ptr, std::size_t max )
+{
+ if ( ptr == gsl_nullptr || max <= 0 )
+ return 0;
+
+ std::size_t len = 0;
+ while ( len < max && ptr[len] ) // NOLINT
+ ++len;
+
+ return len;
+}
+
+} // namespace detail
+
+//
+// basic_string_span<> - A view of contiguous characters, replace (*,len).
+//
+template< class T >
+class basic_string_span
+{
+public:
+ typedef T element_type;
+ typedef span<T> span_type;
+
+ typedef typename span_type::size_type size_type;
+ typedef typename span_type::index_type index_type;
+ typedef typename span_type::difference_type difference_type;
+
+ typedef typename span_type::pointer pointer ;
+ typedef typename span_type::reference reference ;
+
+ typedef typename span_type::iterator iterator ;
+ typedef typename span_type::const_iterator const_iterator ;
+ typedef typename span_type::reverse_iterator reverse_iterator;
+ typedef typename span_type::const_reverse_iterator const_reverse_iterator;
+
+ // construction:
+
+#if gsl_HAVE( IS_DEFAULT )
+ gsl_constexpr basic_string_span() gsl_noexcept = default;
+#else
+ gsl_api gsl_constexpr basic_string_span() gsl_noexcept {}
+#endif
+
+#if gsl_HAVE( NULLPTR )
+ gsl_api gsl_constexpr basic_string_span( std::nullptr_t ) gsl_noexcept
+ : span_( nullptr, static_cast<index_type>( 0 ) )
+ {}
+#endif
+
+#ifdef __CUDACC_RELAXED_CONSTEXPR__
+ gsl_api
+#endif // __CUDACC_RELAXED_CONSTEXPR__
+ gsl_constexpr basic_string_span( pointer ptr )
+ : span_( remove_z( ptr, (std::numeric_limits<index_type>::max)() ) )
+ {}
+
+ gsl_api gsl_constexpr basic_string_span( pointer ptr, index_type count )
+ : span_( ptr, count )
+ {}
+
+ gsl_api gsl_constexpr basic_string_span( pointer firstElem, pointer lastElem )
+ : span_( firstElem, lastElem )
+ {}
+
+ template< std::size_t N >
+ gsl_constexpr basic_string_span( element_type (&arr)[N] )
+ : span_( remove_z( gsl_ADDRESSOF( arr[0] ), N ) )
+ {}
+
+#if gsl_HAVE( ARRAY )
+
+ template< std::size_t N >
+ gsl_constexpr basic_string_span( std::array< typename std11::remove_const<element_type>::type, N> & arr )
+ : span_( remove_z( arr ) )
+ {}
+
+ template< std::size_t N >
+ gsl_constexpr basic_string_span( std::array< typename std11::remove_const<element_type>::type, N> const & arr )
+ : span_( remove_z( arr ) )
+ {}
+
+#endif
+
+#if gsl_HAVE( CONSTRAINED_SPAN_CONTAINER_CTOR )
+
+ // Exclude: array, [basic_string,] basic_string_span
+
+ template< class Container
+ gsl_ENABLE_IF_((
+ ! detail::is_std_array< Container >::value
+ && ! detail::is_basic_string_span< Container >::value
+ && std::is_convertible< typename Container::pointer, pointer >::value
+ && std::is_convertible< typename Container::pointer, decltype(std::declval<Container>().data()) >::value
+ ))
+ >
+ gsl_constexpr basic_string_span( Container & cont )
+ : span_( ( cont ) )
+ {}
+
+ // Exclude: array, [basic_string,] basic_string_span
+
+ template< class Container
+ gsl_ENABLE_IF_((
+ ! detail::is_std_array< Container >::value
+ && ! detail::is_basic_string_span< Container >::value
+ && std::is_convertible< typename Container::pointer, pointer >::value
+ && std::is_convertible< typename Container::pointer, decltype(std::declval<Container const &>().data()) >::value
+ ))
+ >
+ gsl_constexpr basic_string_span( Container const & cont )
+ : span_( ( cont ) )
+ {}
+
+#elif gsl_HAVE( UNCONSTRAINED_SPAN_CONTAINER_CTOR )
+
+ template< class Container >
+ gsl_constexpr basic_string_span( Container & cont )
+ : span_( cont )
+ {}
+
+ template< class Container >
+ gsl_constexpr basic_string_span( Container const & cont )
+ : span_( cont )
+ {}
+
+#else
+
+ template< class U >
+ gsl_api gsl_constexpr basic_string_span( span<U> const & rhs )
+ : span_( rhs )
+ {}
+
+#endif
+
+#if gsl_FEATURE_TO_STD( WITH_CONTAINER )
+
+ template< class Container >
+ gsl_constexpr basic_string_span( with_container_t, Container & cont )
+ : span_( with_container, cont )
+ {}
+#endif
+
+#if gsl_HAVE( IS_DEFAULT )
+# if gsl_BETWEEN( gsl_COMPILER_GNUC_VERSION, 440, 600 )
+ gsl_constexpr basic_string_span( basic_string_span const & ) = default;
+
+ gsl_constexpr basic_string_span( basic_string_span && ) = default;
+# else
+ gsl_constexpr basic_string_span( basic_string_span const & ) gsl_noexcept = default;
+
+ gsl_constexpr basic_string_span( basic_string_span && ) gsl_noexcept = default;
+# endif
+#endif
+
+ template< class U
+ gsl_ENABLE_IF_(( std::is_convertible<typename basic_string_span<U>::pointer, pointer>::value ))
+ >
+ gsl_api gsl_constexpr basic_string_span( basic_string_span<U> const & rhs )
+ : span_( reinterpret_cast<pointer>( rhs.data() ), rhs.length() ) // NOLINT
+ {}
+
+#if gsl_STDLIB_CPP11_120
+ template< class U
+ gsl_ENABLE_IF_(( std::is_convertible<typename basic_string_span<U>::pointer, pointer>::value ))
+ >
+ gsl_api gsl_constexpr basic_string_span( basic_string_span<U> && rhs )
+ : span_( reinterpret_cast<pointer>( rhs.data() ), rhs.length() ) // NOLINT
+ {}
+#endif // gsl_STDLIB_CPP11_120
+
+ template< class CharTraits, class Allocator >
+ gsl_constexpr basic_string_span(
+ std::basic_string< typename std11::remove_const<element_type>::type, CharTraits, Allocator > & str )
+ : span_( gsl_ADDRESSOF( str[0] ), str.length() )
+ {}
+
+ template< class CharTraits, class Allocator >
+ gsl_constexpr basic_string_span(
+ std::basic_string< typename std11::remove_const<element_type>::type, CharTraits, Allocator > const & str )
+ : span_( gsl_ADDRESSOF( str[0] ), str.length() )
+ {}
+
+ // assignment:
+
+#if gsl_HAVE( IS_DEFAULT )
+ gsl_constexpr14 basic_string_span & operator=( basic_string_span const & ) gsl_noexcept = default;
+
+ gsl_constexpr14 basic_string_span & operator=( basic_string_span && ) gsl_noexcept = default;
+#endif
+
+ // sub span:
+
+ /*gsl_api*/ // currently disabled due to an apparent NVCC bug
+ gsl_NODISCARD gsl_constexpr14 basic_string_span
+ first( index_type count ) const
+ {
+ return span_.first( count );
+ }
+
+ /*gsl_api*/ // currently disabled due to an apparent NVCC bug
+ gsl_NODISCARD gsl_constexpr14 basic_string_span
+ last( index_type count ) const
+ {
+ return span_.last( count );
+ }
+
+ /*gsl_api*/ // currently disabled due to an apparent NVCC bug
+ gsl_NODISCARD gsl_constexpr14 basic_string_span
+ subspan( index_type offset ) const
+ {
+ return span_.subspan( offset );
+ }
+
+ /*gsl_api*/ // currently disabled due to an apparent NVCC bug
+ gsl_NODISCARD gsl_constexpr14 basic_string_span
+ subspan( index_type offset, index_type count ) const
+ {
+ return span_.subspan( offset, count );
+ }
+
+ // observers:
+
+ gsl_NODISCARD gsl_api gsl_constexpr index_type
+ length() const gsl_noexcept
+ {
+ return span_.size();
+ }
+
+ gsl_NODISCARD gsl_api gsl_constexpr index_type
+ size() const gsl_noexcept
+ {
+ return span_.size();
+ }
+
+ gsl_NODISCARD gsl_api gsl_constexpr index_type
+ length_bytes() const gsl_noexcept
+ {
+ return span_.size_bytes();
+ }
+
+ gsl_NODISCARD gsl_api gsl_constexpr index_type
+ size_bytes() const gsl_noexcept
+ {
+ return span_.size_bytes();
+ }
+
+ gsl_NODISCARD gsl_api gsl_constexpr bool
+ empty() const gsl_noexcept
+ {
+ return size() == 0;
+ }
+
+ gsl_NODISCARD gsl_api gsl_constexpr14 reference
+ operator[]( index_type idx ) const
+ {
+ return span_[idx];
+ }
+
+#if ! gsl_DEPRECATE_TO_LEVEL( 6 )
+ gsl_DEPRECATED_MSG("use subscript indexing instead")
+ gsl_api gsl_constexpr14 reference operator()( index_type idx ) const
+ {
+ return span_[idx];
+ }
+#endif // deprecate
+
+ gsl_NODISCARD gsl_api gsl_constexpr14 reference
+ front() const
+ {
+ return span_.front();
+ }
+
+ gsl_NODISCARD gsl_api gsl_constexpr14 reference
+ back() const
+ {
+ return span_.back();
+ }
+
+ gsl_NODISCARD gsl_api gsl_constexpr pointer
+ data() const gsl_noexcept
+ {
+ return span_.data();
+ }
+
+ gsl_NODISCARD gsl_api gsl_constexpr iterator
+ begin() const gsl_noexcept
+ {
+ return span_.begin();
+ }
+
+ gsl_NODISCARD gsl_api gsl_constexpr iterator
+ end() const gsl_noexcept
+ {
+ return span_.end();
+ }
+
+ gsl_NODISCARD gsl_constexpr17 reverse_iterator
+ rbegin() const gsl_noexcept
+ {
+ return span_.rbegin();
+ }
+
+ gsl_NODISCARD gsl_constexpr17 reverse_iterator
+ rend() const gsl_noexcept
+ {
+ return span_.rend();
+ }
+
+ // const version not in p0123r2:
+
+ gsl_NODISCARD gsl_api gsl_constexpr const_iterator
+ cbegin() const gsl_noexcept
+ {
+ return span_.cbegin();
+ }
+
+ gsl_NODISCARD gsl_api gsl_constexpr const_iterator
+ cend() const gsl_noexcept
+ {
+ return span_.cend();
+ }
+
+ gsl_NODISCARD gsl_constexpr17 const_reverse_iterator
+ crbegin() const gsl_noexcept
+ {
+ return span_.crbegin();
+ }
+
+ gsl_NODISCARD gsl_constexpr17 const_reverse_iterator
+ crend() const gsl_noexcept
+ {
+ return span_.crend();
+ }
+
+private:
+ gsl_api static gsl_constexpr14 span_type remove_z( pointer sz, std::size_t max )
+ {
+ return span_type( sz, detail::string_length( sz, max ) );
+ }
+
+#if gsl_HAVE( ARRAY )
+ template< size_t N >
+ gsl_NODISCARD static gsl_constexpr14 span_type
+ remove_z( std::array<typename std11::remove_const<element_type>::type, N> & arr )
+ {
+ return remove_z( gsl_ADDRESSOF( arr[0] ), narrow_cast< std::size_t >( N ) );
+ }
+
+ template< size_t N >
+ gsl_NODISCARD static gsl_constexpr14 span_type
+ remove_z( std::array<typename std11::remove_const<element_type>::type, N> const & arr )
+ {
+ return remove_z( gsl_ADDRESSOF( arr[0] ), narrow_cast< std::size_t >( N ) );
+ }
+#endif
+
+private:
+ span_type span_;
+};
+
+// basic_string_span comparison functions:
+
+#if gsl_CONFIG( ALLOWS_NONSTRICT_SPAN_COMPARISON )
+
+template< class T, class U >
+gsl_SUPPRESS_MSGSL_WARNING(stl.1)
+gsl_NODISCARD inline gsl_constexpr14 bool
+operator==( basic_string_span<T> const & l, U const & u ) gsl_noexcept
+{
+ const basic_string_span< typename std11::add_const<T>::type > r( u );
+
+ return l.size() == r.size()
+ && std98::equal( l.begin(), l.end(), r.begin() );
+}
+
+template< class T, class U >
+gsl_SUPPRESS_MSGSL_WARNING(stl.1)
+gsl_NODISCARD inline gsl_constexpr14 bool
+operator<( basic_string_span<T> const & l, U const & u ) gsl_noexcept
+{
+ const basic_string_span< typename std11::add_const<T>::type > r( u );
+
+ return std98::lexicographical_compare( l.begin(), l.end(), r.begin(), r.end() );
+}
+
+#if gsl_HAVE( DEFAULT_FUNCTION_TEMPLATE_ARG )
+
+template< class T, class U
+ gsl_ENABLE_IF_(( !detail::is_basic_string_span<U>::value ))
+>
+gsl_SUPPRESS_MSGSL_WARNING(stl.1)
+gsl_NODISCARD inline gsl_constexpr14 bool
+operator==( U const & u, basic_string_span<T> const & r ) gsl_noexcept
+{
+ const basic_string_span< typename std11::add_const<T>::type > l( u );
+
+ return l.size() == r.size()
+ && std98::equal( l.begin(), l.end(), r.begin() );
+}
+
+template< class T, class U
+ gsl_ENABLE_IF_(( !detail::is_basic_string_span<U>::value ))
+>
+gsl_SUPPRESS_MSGSL_WARNING(stl.1)
+gsl_NODISCARD inline gsl_constexpr14 bool
+operator<( U const & u, basic_string_span<T> const & r ) gsl_noexcept
+{
+ const basic_string_span< typename std11::add_const<T>::type > l( u );
+
+ return std98::lexicographical_compare( l.begin(), l.end(), r.begin(), r.end() );
+}
+#endif
+
+#else //gsl_CONFIG( ALLOWS_NONSTRICT_SPAN_COMPARISON )
+
+template< class T >
+gsl_SUPPRESS_MSGSL_WARNING(stl.1)
+gsl_NODISCARD inline gsl_constexpr14 bool
+operator==( basic_string_span<T> const & l, basic_string_span<T> const & r ) gsl_noexcept
+{
+ return l.size() == r.size()
+ && std98::equal( l.begin(), l.end(), r.begin() );
+}
+
+template< class T >
+gsl_SUPPRESS_MSGSL_WARNING(stl.1)
+gsl_NODISCARD inline gsl_constexpr14 bool
+operator<( basic_string_span<T> const & l, basic_string_span<T> const & r ) gsl_noexcept
+{
+ return std98::lexicographical_compare( l.begin(), l.end(), r.begin(), r.end() );
+}
+
+#endif // gsl_CONFIG( ALLOWS_NONSTRICT_SPAN_COMPARISON )
+
+template< class T, class U >
+gsl_NODISCARD inline gsl_constexpr14 bool
+operator!=( basic_string_span<T> const & l, U const & r ) gsl_noexcept
+{
+ return !( l == r );
+}
+
+template< class T, class U >
+gsl_NODISCARD inline gsl_constexpr14 bool
+operator<=( basic_string_span<T> const & l, U const & r ) gsl_noexcept
+{
+#if gsl_HAVE( DEFAULT_FUNCTION_TEMPLATE_ARG ) || ! gsl_CONFIG( ALLOWS_NONSTRICT_SPAN_COMPARISON )
+ return !( r < l );
+#else
+ basic_string_span< typename std11::add_const<T>::type > rr( r );
+ return !( rr < l );
+#endif
+}
+
+template< class T, class U >
+gsl_NODISCARD inline gsl_constexpr14 bool
+operator>( basic_string_span<T> const & l, U const & r ) gsl_noexcept
+{
+#if gsl_HAVE( DEFAULT_FUNCTION_TEMPLATE_ARG ) || ! gsl_CONFIG( ALLOWS_NONSTRICT_SPAN_COMPARISON )
+ return ( r < l );
+#else
+ basic_string_span< typename std11::add_const<T>::type > rr( r );
+ return ( rr < l );
+#endif
+}
+
+template< class T, class U >
+gsl_NODISCARD inline gsl_constexpr14 bool
+operator>=( basic_string_span<T> const & l, U const & r ) gsl_noexcept
+{
+ return !( l < r );
+}
+
+#if gsl_HAVE( DEFAULT_FUNCTION_TEMPLATE_ARG )
+
+template< class T, class U
+ gsl_ENABLE_IF_(( !detail::is_basic_string_span<U>::value ))
+>
+gsl_NODISCARD inline gsl_constexpr14 bool
+operator!=( U const & l, basic_string_span<T> const & r ) gsl_noexcept
+{
+ return !( l == r );
+}
+
+template< class T, class U
+ gsl_ENABLE_IF_(( !detail::is_basic_string_span<U>::value ))
+>
+gsl_NODISCARD inline gsl_constexpr14 bool
+operator<=( U const & l, basic_string_span<T> const & r ) gsl_noexcept
+{
+ return !( r < l );
+}
+
+template< class T, class U
+ gsl_ENABLE_IF_(( !detail::is_basic_string_span<U>::value ))
+>
+gsl_NODISCARD inline gsl_constexpr14 bool
+operator>( U const & l, basic_string_span<T> const & r ) gsl_noexcept
+{
+ return ( r < l );
+}
+
+template< class T, class U
+ gsl_ENABLE_IF_(( !detail::is_basic_string_span<U>::value ))
+>
+gsl_NODISCARD inline gsl_constexpr14 bool
+operator>=( U const & l, basic_string_span<T> const & r ) gsl_noexcept
+{
+ return !( l < r );
+}
+
+#endif // gsl_HAVE( DEFAULT_FUNCTION_TEMPLATE_ARG )
+
+// convert basic_string_span to byte span:
+
+template< class T >
+gsl_NODISCARD gsl_api inline span< const byte >
+as_bytes( basic_string_span<T> spn ) gsl_noexcept
+{
+ return span< const byte >( reinterpret_cast<const byte *>( spn.data() ), spn.size_bytes() ); // NOLINT
+}
+
+//
+// String types:
+//
+
+typedef char * zstring;
+typedef const char * czstring;
+
+#if gsl_HAVE( WCHAR )
+typedef wchar_t * wzstring;
+typedef const wchar_t * cwzstring;
+#endif
+
+typedef basic_string_span< char > string_span;
+typedef basic_string_span< char const > cstring_span;
+
+#if gsl_HAVE( WCHAR )
+typedef basic_string_span< wchar_t > wstring_span;
+typedef basic_string_span< wchar_t const > cwstring_span;
+#endif
+
+// to_string() allow (explicit) conversions from string_span to string
+
+#if 0
+
+template< class T >
+inline std::basic_string< typename std::remove_const<T>::type > to_string( basic_string_span<T> spn )
+{
+ std::string( spn.data(), spn.length() );
+}
+
+#else
+
+gsl_NODISCARD inline std::string
+to_string( string_span const & spn )
+{
+ return std::string( spn.data(), static_cast<std::size_t>( spn.length() ) );
+}
+
+gsl_NODISCARD inline std::string
+to_string( cstring_span const & spn )
+{
+ return std::string( spn.data(), static_cast<std::size_t>( spn.length() ) );
+}
+
+#if gsl_HAVE( WCHAR )
+
+gsl_NODISCARD inline std::wstring
+to_string( wstring_span const & spn )
+{
+ return std::wstring( spn.data(), static_cast<std::size_t>( spn.length() ) );
+}
+
+gsl_NODISCARD inline std::wstring
+to_string( cwstring_span const & spn )
+{
+ return std::wstring( spn.data(), static_cast<std::size_t>( spn.length() ) );
+}
+
+#endif // gsl_HAVE( WCHAR )
+#endif // to_string()
+
+//
+// Stream output for string_span types
+//
+
+namespace detail {
+
+template< class Stream >
+void write_padding( Stream & os, std::streamsize n )
+{
+ for ( std::streamsize i = 0; i < n; ++i )
+ os.rdbuf()->sputc( os.fill() );
+}
+
+template< class Stream, class Span >
+Stream & write_to_stream( Stream & os, Span const & spn )
+{
+ typename Stream::sentry sentry( os );
+
+ if ( !os )
+ return os;
+
+ const std::streamsize length = gsl::narrow_failfast<std::streamsize>( spn.length() );
+
+ // Whether, and how, to pad
+ const bool pad = ( length < os.width() );
+ const bool left_pad = pad && ( os.flags() & std::ios_base::adjustfield ) == std::ios_base::right;
+
+ if ( left_pad )
+ detail::write_padding( os, os.width() - length );
+
+ // Write span characters
+ os.rdbuf()->sputn( spn.begin(), length );
+
+ if ( pad && !left_pad )
+ detail::write_padding( os, os.width() - length );
+
+ // Reset output stream width
+ os.width(0);
+
+ return os;
+}
+
+} // namespace detail
+
+template< typename Traits >
+std::basic_ostream< char, Traits > & operator<<( std::basic_ostream< char, Traits > & os, string_span const & spn )
+{
+ return detail::write_to_stream( os, spn );
+}
+
+template< typename Traits >
+std::basic_ostream< char, Traits > & operator<<( std::basic_ostream< char, Traits > & os, cstring_span const & spn )
+{
+ return detail::write_to_stream( os, spn );
+}
+
+#if gsl_HAVE( WCHAR )
+
+template< typename Traits >
+std::basic_ostream< wchar_t, Traits > & operator<<( std::basic_ostream< wchar_t, Traits > & os, wstring_span const & spn )
+{
+ return detail::write_to_stream( os, spn );
+}
+
+template< typename Traits >
+std::basic_ostream< wchar_t, Traits > & operator<<( std::basic_ostream< wchar_t, Traits > & os, cwstring_span const & spn )
+{
+ return detail::write_to_stream( os, spn );
+}
+
+#endif // gsl_HAVE( WCHAR )
+
+//
+// ensure_sentinel()
+//
+// Provides a way to obtain a span from a contiguous sequence
+// that ends with a (non-inclusive) sentinel value.
+//
+// Will fail-fast if sentinel cannot be found before max elements are examined.
+//
+namespace detail {
+
+template< class T, class SizeType, const T Sentinel >
+gsl_constexpr14 static span<T> ensure_sentinel( T * seq, SizeType max = (std::numeric_limits<SizeType>::max)() )
+{
+ typedef T * pointer;
+
+ gsl_SUPPRESS_MSVC_WARNING( 26429, "f.23: symbol 'cur' is never tested for nullness, it can be marked as not_null" )
+ pointer cur = seq;
+
+ while ( static_cast<SizeType>( cur - seq ) < max && *cur != Sentinel )
+ ++cur;
+
+ gsl_Expects( *cur == Sentinel );
+
+ return span<T>( seq, gsl::narrow_cast< typename span<T>::index_type >( cur - seq ) );
+}
+} // namespace detail
+
+//
+// ensure_z - creates a string_span for a czstring or cwzstring.
+// Will fail fast if a null-terminator cannot be found before
+// the limit of size_type.
+//
+
+template< class T >
+gsl_NODISCARD inline gsl_constexpr14 span<T>
+ensure_z( T * const & sz, size_t max = (std::numeric_limits<size_t>::max)() )
+{
+ return detail::ensure_sentinel<T, size_t, 0>( sz, max );
+}
+
+template< class T, size_t N >
+gsl_NODISCARD inline gsl_constexpr14 span<T>
+ensure_z( T (&sz)[N] )
+{
+ return ::gsl::ensure_z( gsl_ADDRESSOF( sz[0] ), N );
+}
+
+# if gsl_HAVE( TYPE_TRAITS )
+
+template< class Container >
+gsl_NODISCARD inline gsl_constexpr14 span< typename std::remove_pointer<typename Container::pointer>::type >
+ensure_z( Container & cont )
+{
+ return ::gsl::ensure_z( cont.data(), cont.length() );
+}
+# endif
+
+//
+// basic_zstring_span<> - A view of contiguous null-terminated characters, replace (*,len).
+//
+
+template <typename T>
+class basic_zstring_span
+{
+public:
+ typedef T element_type;
+ typedef span<T> span_type;
+
+ typedef typename span_type::index_type index_type;
+ typedef typename span_type::difference_type difference_type;
+
+ typedef element_type * czstring_type;
+ typedef basic_string_span<element_type> string_span_type;
+
+ gsl_api gsl_constexpr14 basic_zstring_span( span_type s )
+ : span_( s )
+ {
+ // expects a zero-terminated span
+ gsl_Expects( s.back() == '\0' );
+ }
+
+#if gsl_HAVE( IS_DEFAULT )
+ gsl_constexpr basic_zstring_span( basic_zstring_span const & ) = default;
+ gsl_constexpr basic_zstring_span( basic_zstring_span && ) = default;
+ gsl_constexpr14 basic_zstring_span & operator=( basic_zstring_span const & ) = default;
+ gsl_constexpr14 basic_zstring_span & operator=( basic_zstring_span && ) = default;
+#else
+ gsl_api gsl_constexpr basic_zstring_span( basic_zstring_span const & other) : span_ ( other.span_ ) {}
+ gsl_api gsl_constexpr basic_zstring_span & operator=( basic_zstring_span const & other ) { span_ = other.span_; return *this; }
+#endif
+
+ gsl_NODISCARD gsl_api gsl_constexpr bool
+ empty() const gsl_noexcept
+ {
+ return false;
+ }
+
+ gsl_NODISCARD gsl_api gsl_constexpr string_span_type
+ as_string_span() const gsl_noexcept
+ {
+ return string_span_type( span_.data(), span_.size() - 1 );
+ }
+
+ /*gsl_api*/ // currently disabled due to an apparent NVCC bug
+ gsl_NODISCARD gsl_constexpr string_span_type
+ ensure_z() const
+ {
+ return ::gsl::ensure_z(span_.data(), span_.size());
+ }
+
+ gsl_NODISCARD gsl_api gsl_constexpr czstring_type
+ assume_z() const gsl_noexcept
+ {
+ return span_.data();
+ }
+
+private:
+ span_type span_;
+};
+
+//
+// zString types:
+//
+
+typedef basic_zstring_span< char > zstring_span;
+typedef basic_zstring_span< char const > czstring_span;
+
+#if gsl_HAVE( WCHAR )
+typedef basic_zstring_span< wchar_t > wzstring_span;
+typedef basic_zstring_span< wchar_t const > cwzstring_span;
+#endif
+
+} // namespace gsl
+
+#if gsl_HAVE( HASH )
+
+//
+// std::hash specializations for GSL types
+//
+
+namespace gsl {
+
+namespace detail {
+
+//
+// Helper struct for std::hash specializations
+//
+
+template<bool Condition>
+struct conditionally_enabled_hash
+{
+
+};
+
+// disabled as described in [unord.hash]
+template<>
+struct conditionally_enabled_hash< false >
+{
+gsl_is_delete_access:
+ conditionally_enabled_hash() gsl_is_delete;
+ conditionally_enabled_hash( conditionally_enabled_hash const & ) gsl_is_delete;
+ conditionally_enabled_hash( conditionally_enabled_hash && ) gsl_is_delete;
+ conditionally_enabled_hash & operator=( conditionally_enabled_hash const & ) gsl_is_delete;
+ conditionally_enabled_hash & operator=( conditionally_enabled_hash && ) gsl_is_delete;
+};
+
+} // namespace detail
+
+} // namespace gsl
+
+namespace std {
+
+template< class T >
+struct hash< ::gsl::not_null< T > > : public ::gsl::detail::conditionally_enabled_hash<is_default_constructible<hash<T>>::value>
+{
+public:
+ gsl_NODISCARD gsl_constexpr std::size_t
+ operator()( ::gsl::not_null<T> const & v ) const
+ // hash function is not `noexcept` because `as_nullable()` has preconditions
+ {
+ return hash<T>()( ::gsl::as_nullable( v ) );
+ }
+};
+template< class T >
+struct hash< ::gsl::not_null< T* > >
+{
+public:
+ gsl_NODISCARD gsl_constexpr std::size_t
+ operator()( ::gsl::not_null< T* > const & v ) const gsl_noexcept
+ {
+ return hash<T*>()( ::gsl::as_nullable( v ) );
+ }
+};
+
+template<>
+struct hash< ::gsl::byte >
+{
+public:
+ gsl_NODISCARD gsl_constexpr std::size_t operator()( ::gsl::byte v ) const gsl_noexcept
+ {
+ return ::gsl::to_integer<std::size_t>( v );
+ }
+};
+
+} // namespace std
+
+#endif // gsl_HAVE( HASH )
+
+#if gsl_FEATURE( GSL_LITE_NAMESPACE )
+
+// gsl_lite namespace:
+
+// gsl-lite currently keeps all symbols in the namespace `gsl`. The `gsl_lite` namespace contains all the symbols in the
+// `gsl` namespace, plus some extensions that are not specified in the Core Guidelines.
+//
+// Going forward, we want to support coexistence of gsl-lite with M-GSL, so we want to encourage using the `gsl_lite`
+// namespace when consuming gsl-lite. Typical use in library code would be:
+//
+// #include <gsl-lite/gsl-lite.hpp> // instead of <gsl/gsl-lite.hpp>
+//
+// namespace foo {
+// namespace gsl = ::gsl_lite; // convenience alias
+// double mean( gsl::span<double const> elements )
+// {
+// gsl_Expects( ! elements.empty() ); // instead of Expects()
+// ...
+// }
+// } // namespace foo
+//
+// In a future version, the new <gsl-lite/gsl-lite.hpp> header will only define the `gsl_lite` namespace and no
+// unprefixed `Expects()` and `Ensures()` macros to avoid collision with M-GSL. To ensure backward compatibility, the
+// old header <gsl/gsl-lite.hpp> will keep defining the `gsl` namespace and the `Expects()` and `Ensures()` macros.
+
+namespace gsl_lite {
+
+namespace std11 = ::gsl::std11;
+namespace std14 = ::gsl::std14;
+namespace std17 = ::gsl::std17;
+namespace std20 = ::gsl::std20;
+
+using namespace std11;
+using namespace std14;
+using namespace std17;
+using namespace std20;
+
+using namespace ::gsl::detail::no_adl;
+
+# if gsl_HAVE( SHARED_PTR )
+using std::unique_ptr;
+using std::shared_ptr;
+using std::make_shared;
+# endif
+
+using ::gsl::index;
+using ::gsl::dim;
+using ::gsl::stride;
+using ::gsl::diff;
+
+# if gsl_HAVE( ALIAS_TEMPLATE )
+# if gsl_BETWEEN( gsl_COMPILER_MSVC_VERSION, 1, 141 ) // VS 2015 and earlier have trouble with `using` for alias templates
+ template< class T
+# if gsl_HAVE( TYPE_TRAITS )
+ , typename = typename std::enable_if< std::is_pointer<T>::value >::type
+# endif
+ >
+ using owner = T;
+# else
+using ::gsl::owner;
+# endif
+# endif
+
+using ::gsl::fail_fast;
+
+using ::gsl::finally;
+# if gsl_FEATURE( EXPERIMENTAL_RETURN_GUARD )
+using ::gsl::on_return;
+using ::gsl::on_error;
+# endif // gsl_FEATURE( EXPERIMENTAL_RETURN_GUARD )
+
+using ::gsl::narrow_cast;
+using ::gsl::narrowing_error;
+using ::gsl::narrow;
+using ::gsl::narrow_failfast;
+
+using ::gsl::at;
+
+using ::gsl::not_null;
+using ::gsl::not_null_ic;
+using ::gsl::make_not_null;
+
+using ::gsl::byte;
+
+using ::gsl::to_byte;
+using ::gsl::to_integer;
+using ::gsl::to_uchar;
+using ::gsl::to_string;
+
+using ::gsl::with_container_t;
+using ::gsl::with_container;
+
+using ::gsl::span;
+using ::gsl::make_span;
+using ::gsl::byte_span;
+using ::gsl::copy;
+using ::gsl::as_bytes;
+using ::gsl::as_writable_bytes;
+# if ! gsl_DEPRECATE_TO_LEVEL( 6 )
+using ::gsl::as_writeable_bytes;
+# endif
+
+using ::gsl::basic_string_span;
+using ::gsl::string_span;
+using ::gsl::cstring_span;
+
+using ::gsl::basic_zstring_span;
+using ::gsl::zstring_span;
+using ::gsl::czstring_span;
+
+using ::gsl::zstring;
+using ::gsl::czstring;
+
+# if gsl_HAVE( WCHAR )
+using ::gsl::wzstring;
+using ::gsl::cwzstring;
+
+using ::gsl::wzstring_span;
+using ::gsl::cwzstring_span;
+# endif // gsl_HAVE( WCHAR )
+
+using ::gsl::ensure_z;
+
+} // namespace gsl_lite
+
+#endif // gsl_FEATURE( GSL_LITE_NAMESPACE )
+
+gsl_RESTORE_MSVC_WARNINGS()
+
+// #undef internal macros
+#undef gsl_STATIC_ASSERT_
+#undef gsl_ENABLE_IF_
+#undef gsl_TRAILING_RETURN_TYPE_
+#undef gsl_RETURN_DECLTYPE_
+
+#endif // GSL_GSL_LITE_HPP_INCLUDED
+
+// end of file
diff --git a/vbz/CMakeLists.txt b/vbz/CMakeLists.txt
index 0791655..964b765 100644
--- a/vbz/CMakeLists.txt
+++ b/vbz/CMakeLists.txt
@@ -31,7 +31,9 @@ add_dependencies(vbz
streamvbyte
)
-if (WIN32 OR APPLE OR "${CMAKE_SYSTEM_PROCESSOR}" MATCHES "x86_64")
+if (WIN32 OR
+ (APPLE AND NOT "${CMAKE_SYSTEM_PROCESSOR}" MATCHES "arm64") OR
+ "${CMAKE_SYSTEM_PROCESSOR}" MATCHES "x86_64")
if(NOT MSVC)
target_compile_options(vbz PRIVATE -mssse3)
endif()
diff --git a/vbz/perf/test_data_generator.h b/vbz/perf/test_data_generator.h
index 4b13d81..1bb593b 100644
--- a/vbz/perf/test_data_generator.h
+++ b/vbz/perf/test_data_generator.h
@@ -2,7 +2,7 @@
#include "../test/test_data.h"
-#include <gsl/gsl>
+#include <gsl/gsl-lite.hpp>
#include <numeric>
#include <random>
diff --git a/vbz/test/CMakeLists.txt b/vbz/test/CMakeLists.txt
index 5c8a3df..0e1b48c 100644
--- a/vbz/test/CMakeLists.txt
+++ b/vbz/test/CMakeLists.txt
@@ -9,13 +9,16 @@ add_sanitizers(vbz_test)
set_property(TARGET vbz_test PROPERTY CXX_STANDARD 11)
+find_package( Threads )
+
target_link_libraries(vbz_test
PUBLIC
vbz
+ ${CMAKE_THREAD_LIBS_INIT}
)
add_test(
NAME vbz_test
COMMAND vbz_test
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
-) \ No newline at end of file
+)
diff --git a/vbz/test/test_utils.h b/vbz/test/test_utils.h
index 596c1b0..138ffe9 100644
--- a/vbz/test/test_utils.h
+++ b/vbz/test/test_utils.h
@@ -1,6 +1,6 @@
#pragma once
-#include <gsl/gsl>
+#include <gsl/gsl-lite.hpp>
#include <iostream>
diff --git a/vbz/v0/vbz_streamvbyte.cpp b/vbz/v0/vbz_streamvbyte.cpp
index 9ffeb01..609075e 100644
--- a/vbz/v0/vbz_streamvbyte.cpp
+++ b/vbz/v0/vbz_streamvbyte.cpp
@@ -2,7 +2,7 @@
#include "vbz_streamvbyte_impl.h"
#include "vbz.h"
-#include <gsl/gsl>
+#include <gsl/gsl-lite.hpp>
vbz_size_t vbz_max_streamvbyte_compressed_size_v0(
std::size_t integer_size,
diff --git a/vbz/v0/vbz_streamvbyte_impl.h b/vbz/v0/vbz_streamvbyte_impl.h
index 015ad13..357cb61 100644
--- a/vbz/v0/vbz_streamvbyte_impl.h
+++ b/vbz/v0/vbz_streamvbyte_impl.h
@@ -5,7 +5,9 @@
#include "streamvbyte.h"
#include "streamvbyte_zigzag.h"
-#include <gsl/gsl>
+#include <gsl/gsl-lite.hpp>
+
+#include <vector>
/// \brief Generic implementation, safe for all integer types, and platforms.
template <typename T, bool UseZigZag>
@@ -53,14 +55,14 @@ struct StreamVByteWorkerV0
if (!UseZigZag)
{
- cast(gsl::make_span(intermediate_buffer), gsl::make_span(output));
+ cast(gsl::make_span(intermediate_buffer), output);
return vbz_size_t(output.size() * sizeof(T));
}
std::vector<std::int32_t> output_buffer(output.size());
zigzag_delta_decode(intermediate_buffer.data(), output_buffer.data(), output_buffer.size(), 0);
- cast(gsl::make_span(output_buffer), gsl::make_span(output));
+ cast(gsl::make_span(output_buffer), output);
return vbz_size_t(output.size() * sizeof(T));
}
diff --git a/vbz/v1/vbz_streamvbyte.cpp b/vbz/v1/vbz_streamvbyte.cpp
index 9fc3414..d2d9a67 100644
--- a/vbz/v1/vbz_streamvbyte.cpp
+++ b/vbz/v1/vbz_streamvbyte.cpp
@@ -3,7 +3,7 @@
#include "../v0/vbz_streamvbyte_impl.h" // for 4 byte case
#include "vbz.h"
-#include <gsl/gsl>
+#include <gsl/gsl-lite.hpp>
vbz_size_t vbz_max_streamvbyte_compressed_size_v1(
std::size_t integer_size,
diff --git a/vbz/v1/vbz_streamvbyte_impl.h b/vbz/v1/vbz_streamvbyte_impl.h
index be306f9..b3bce88 100644
--- a/vbz/v1/vbz_streamvbyte_impl.h
+++ b/vbz/v1/vbz_streamvbyte_impl.h
@@ -5,9 +5,10 @@
#include "streamvbyte.h"
#include "streamvbyte_zigzag.h"
-#include <gsl/gsl>
+#include <gsl/gsl-lite.hpp>
#include <cassert>
+#include <vector>
#ifdef _MSC_VER
# define VBZ_RESTRICT __restrict
@@ -224,14 +225,14 @@ struct StreamVByteWorkerV1
if (!UseZigZag)
{
- cast(gsl::make_span(intermediate_buffer), gsl::make_span(output));
+ cast(gsl::make_span(intermediate_buffer), output);
return vbz_size_t(output.size() * sizeof(T));
}
std::vector<std::int32_t> output_buffer(output.size());
zigzag_delta_decode(intermediate_buffer.data(), output_buffer.data(), output_buffer.size(), 0);
- cast(gsl::make_span(output_buffer), gsl::make_span(output));
+ cast(gsl::make_span(output_buffer), output);
return vbz_size_t(output.size() * sizeof(T));
}
diff --git a/vbz/vbz.cpp b/vbz/vbz.cpp
index 56dbe8b..8ae0b74 100644
--- a/vbz/vbz.cpp
+++ b/vbz/vbz.cpp
@@ -1,7 +1,7 @@
#include "v0/vbz_streamvbyte.h"
#include "v1/vbz_streamvbyte.h"
-#include <gsl/gsl>
+#include <gsl/gsl-lite.hpp>
#include <zstd.h>
#include <cassert>
diff --git a/vbz_plugin/CMakeLists.txt b/vbz_plugin/CMakeLists.txt
index 1b0603a..e4612f0 100644
--- a/vbz_plugin/CMakeLists.txt
+++ b/vbz_plugin/CMakeLists.txt
@@ -1,5 +1,5 @@
-add_library(vbz_hdf_plugin SHARED
+add_library(vbz_hdf_plugin
vbz_plugin_user_utils.h
vbz_plugin.cpp
vbz_plugin.h
@@ -10,6 +10,16 @@ generate_export_header(vbz_hdf_plugin EXPORT_FILE_NAME vbz_plugin/vbz_hdf_plugin
set_property(TARGET vbz_hdf_plugin PROPERTY CXX_STANDARD 11)
+if(WIN32 AND HDF5_USE_STATIC_LIBRARIES)
+ # See vbz_plugin.cpp -- if also building with Python on Windows then the runtime
+ # used is determined by that Python version, so we only support dynamic builds.
+ if(ENABLE_PYTHON)
+ message(FATAL_ERROR "Cannot enable HDF5_USE_STATIC_LIBRARIES as well as ENABLE_PYTHON")
+ else()
+ add_definitions(-DHDF5_USE_STATIC_LIBRARIES)
+ endif()
+endif()
+
target_include_directories(
vbz_hdf_plugin
PUBLIC
diff --git a/vbz_plugin/vbz_plugin.cpp b/vbz_plugin/vbz_plugin.cpp
index 4e39dd1..75e1612 100644
--- a/vbz_plugin/vbz_plugin.cpp
+++ b/vbz_plugin/vbz_plugin.cpp
@@ -2,7 +2,7 @@
#include "vbz_plugin.h"
#include "vbz.h"
-#include <gsl/gsl>
+#include <gsl/gsl-lite.hpp>
#include <hdf5/hdf5_plugin_types.h>
#include <array>
@@ -32,7 +32,7 @@ int checksum(gsl::span<char const> input)
}
#endif
-#ifdef _WIN32
+#if defined(_WIN32) && !defined(HDF5_USE_STATIC_LIBRARIES)
HMODULE get_hdf_module()
{
static HMODULE module = nullptr;
@@ -64,7 +64,7 @@ HMODULE get_hdf_module()
//
void* h5_malloc(std::size_t size)
{
-#ifdef _WIN32
+#if defined(_WIN32) && !defined(HDF5_USE_STATIC_LIBRARIES)
static auto module = get_hdf_module();
static auto malloc_memory = (void*(*)(size_t, bool))GetProcAddress(module, "H5allocate_memory");
@@ -76,7 +76,7 @@ void* h5_malloc(std::size_t size)
void h5_free(void* memory)
{
-#ifdef _WIN32
+#if defined(_WIN32) && !defined(HDF5_USE_STATIC_LIBRARIES)
static auto module = get_hdf_module();
static auto free_hdf5 = (int(*)(void *))GetProcAddress(module, "H5free_memory");