diff --git a/.gitignore b/.gitignore index e595d4fa1a..40f38d44c4 100644 --- a/.gitignore +++ b/.gitignore @@ -31,4 +31,6 @@ benchmark-dir bazel-* build-fuzzers debug-build +build/ +.cache .vscode diff --git a/CMakePresets.json b/CMakePresets.json index 00f3a6d3af..dd98914500 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -20,6 +20,27 @@ "CATCH_BUILD_SURROGATES": "ON", "CATCH_ENABLE_CONFIGURE_TESTS": "ON" } + }, + { + "name": "basic-tests-shared", + "displayName": "Basic development build with BUILD_SHARED_LIBS=ON", + "description": "Enables development build with basic tests that are cheap to build and run", + "cacheVariables": { + "CATCH_DEVELOPMENT_BUILD": "ON", + "BUILD_SHARED_LIBS": "ON" + } + }, + { + "name": "all-tests-shared", + "inherits": "basic-tests-shared", + "displayName": "Full development build with BUILD_SHARED_LIBS=ON", + "description": "Enables development build with examples and ALL tests", + "cacheVariables": { + "CATCH_BUILD_EXAMPLES": "ON", + "CATCH_BUILD_EXTRA_TESTS": "ON", + "CATCH_BUILD_SURROGATES": "ON", + "CATCH_ENABLE_CONFIGURE_TESTS": "ON" + } } ] } diff --git a/extras/catch_amalgamated.cpp b/extras/catch_amalgamated.cpp index 58a1c7d599..1534007d43 100644 --- a/extras/catch_amalgamated.cpp +++ b/extras/catch_amalgamated.cpp @@ -6,7 +6,7 @@ // SPDX-License-Identifier: BSL-1.0 // Catch v3.0.0-preview.5 -// Generated: 2022-04-20 23:45:15.004945 +// Generated: 2022-04-26 23:43:38.004914 // ---------------------------------------------------------- // This file is an amalgamation of multiple different files. // You probably shouldn't edit it directly. @@ -635,6 +635,7 @@ namespace Catch { bool Config::showInvisibles() const { return m_data.showInvisibles; } Verbosity Config::verbosity() const { return m_data.verbosity; } + bool Config::skipBenchmarks() const { return m_data.skipBenchmarks; } bool Config::benchmarkNoAnalysis() const { return m_data.benchmarkNoAnalysis; } unsigned int Config::benchmarkSamples() const { return m_data.benchmarkSamples; } double Config::benchmarkConfidenceInterval() const { return m_data.benchmarkConfidenceInterval; } @@ -2412,7 +2413,7 @@ namespace Catch { return Detail::InternalParseResult::runtimeError( "Expected argument following " + token.token); - auto result = valueRef->setValue(argToken.token); + const auto result = valueRef->setValue(argToken.token); if (!result) return Detail::InternalParseResult(result); if (result.value() == @@ -3125,6 +3126,9 @@ namespace Catch { | Opt( setWaitForKeypress, "never|start|exit|both" ) ["--wait-for-keypress"] ( "waits for a keypress before exiting" ) + | Opt( config.skipBenchmarks) + ["--skip-benchmarks"] + ( "disable running benchmarks") | Opt( config.benchmarkSamples, "samples" ) ["--benchmark-samples"] ( "number of samples to collect (default: 100)" ) diff --git a/extras/catch_amalgamated.hpp b/extras/catch_amalgamated.hpp index a5f8df0af7..f830198fb8 100644 --- a/extras/catch_amalgamated.hpp +++ b/extras/catch_amalgamated.hpp @@ -6,7 +6,7 @@ // SPDX-License-Identifier: BSL-1.0 // Catch v3.0.0-preview.5 -// Generated: 2022-04-20 23:45:13.582550 +// Generated: 2022-04-26 23:43:37.987745 // ---------------------------------------------------------- // This file is an amalgamation of multiple different files. // You probably shouldn't edit it directly. @@ -57,50 +57,303 @@ #ifndef CATCH_BENCHMARK_HPP_INCLUDED #define CATCH_BENCHMARK_HPP_INCLUDED +#include -#ifndef CATCH_INTERFACES_CONFIG_HPP_INCLUDED -#define CATCH_INTERFACES_CONFIG_HPP_INCLUDED +// Adapted from donated nonius code. +#ifndef CATCH_CHRONOMETER_HPP_INCLUDED +#define CATCH_CHRONOMETER_HPP_INCLUDED -#ifndef CATCH_NONCOPYABLE_HPP_INCLUDED -#define CATCH_NONCOPYABLE_HPP_INCLUDED + +// Adapted from donated nonius code. + +#ifndef CATCH_CLOCK_HPP_INCLUDED +#define CATCH_CLOCK_HPP_INCLUDED + + + +#ifndef CATCH_DLL_PUBLIC_HPP_INCLUDED +#define CATCH_DLL_PUBLIC_HPP_INCLUDED + +#if defined _WIN32 || defined __CYGWIN__ +# ifdef BUILDING_DLL +# ifdef __GNUC__ +# define CATCH_DLL_PUBLIC __attribute__( ( dllexport ) ) +# else +# define CATCH_DLL_PUBLIC \ + __declspec( dllexport ) // Note: actually gcc seems to also + // supports this syntax. +# endif +# else +# ifdef __GNUC__ +# define CATCH_DLL_PUBLIC __attribute__( ( dllimport ) ) +# else +# define CATCH_DLL_PUBLIC \ + __declspec( dllimport ) // Note: actually gcc seems to also + // supports this syntax. +# endif +# endif +# define DLL_LOCAL +#else +# if __GNUC__ >= 4 +# define CATCH_DLL_PUBLIC __attribute__( ( visibility( "default" ) ) ) +# define DLL_LOCAL __attribute__( ( visibility( "hidden" ) ) ) +# else +# define CATCH_DLL_PUBLIC +# define DLL_LOCAL +# endif +#endif + +#endif // CATCH_DLL_PUBLIC_INCLUDED +#include +#include namespace Catch { - namespace Detail { + namespace Benchmark { + template + using ClockDuration = typename Clock::duration; + template + using FloatDuration = std::chrono::duration; - //! Deriving classes become noncopyable and nonmovable - class NonCopyable { - NonCopyable( NonCopyable const& ) = delete; - NonCopyable( NonCopyable&& ) = delete; - NonCopyable& operator=( NonCopyable const& ) = delete; - NonCopyable& operator=( NonCopyable&& ) = delete; + template + using TimePoint = typename Clock::time_point; - protected: - NonCopyable() noexcept = default; + using default_clock = std::chrono::steady_clock; + + template struct CATCH_DLL_PUBLIC now { + TimePoint operator()() const { + return Clock::now(); + } }; - } // namespace Detail + using fp_seconds = std::chrono::duration>; + } // namespace Benchmark } // namespace Catch -#endif // CATCH_NONCOPYABLE_HPP_INCLUDED +#endif // CATCH_CLOCK_HPP_INCLUDED + + +// Adapted from donated nonius code. + +#ifndef CATCH_OPTIMIZER_HPP_INCLUDED +#define CATCH_OPTIMIZER_HPP_INCLUDED + +#if defined(_MSC_VER) +# include // atomic_thread_fence +#endif + + + +#ifndef CATCH_MOVE_AND_FORWARD_HPP_INCLUDED +#define CATCH_MOVE_AND_FORWARD_HPP_INCLUDED + +#include + +//! Replacement for std::move with better compile time performance +#define CATCH_MOVE(...) static_cast&&>(__VA_ARGS__) + +//! Replacement for std::forward with better compile time performance +#define CATCH_FORWARD(...) static_cast(__VA_ARGS__) + +#endif // CATCH_MOVE_AND_FORWARD_HPP_INCLUDED +#include + +namespace Catch { + namespace Benchmark { +#if defined(__GNUC__) || defined(__clang__) + template + 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 + inline void keep_memory(T* p) { + // thanks @milleniumbug + *reinterpret_cast(p) = *reinterpret_cast(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 + inline void deoptimize_value(T&& x) { + keep_memory(&x); + } + + template + inline auto invoke_deoptimized(Fn&& fn, Args&&... args) -> std::enable_if_t::value> { + deoptimize_value(CATCH_FORWARD(fn) (CATCH_FORWARD(args)...)); + } + + template + inline auto invoke_deoptimized(Fn&& fn, Args&&... args) -> std::enable_if_t::value> { + CATCH_FORWARD(fn) (CATCH_FORWARD(args)...); + } + } // namespace Benchmark +} // namespace Catch + +#endif // CATCH_OPTIMIZER_HPP_INCLUDED + + +// Adapted from donated nonius code. + +#ifndef CATCH_COMPLETE_INVOKE_HPP_INCLUDED +#define CATCH_COMPLETE_INVOKE_HPP_INCLUDED + + + +#ifndef CATCH_TEST_FAILURE_EXCEPTION_HPP_INCLUDED +#define CATCH_TEST_FAILURE_EXCEPTION_HPP_INCLUDED + + +namespace Catch { + + //! Used to signal that an assertion macro failed + struct CATCH_DLL_PUBLIC TestFailureException {}; + +} // namespace Catch + +#endif // CATCH_TEST_FAILURE_EXCEPTION_HPP_INCLUDED + + +#ifndef CATCH_META_HPP_INCLUDED +#define CATCH_META_HPP_INCLUDED + +#include + +namespace Catch { + template + struct CATCH_DLL_PUBLIC always_false : std::false_type {}; + + template struct CATCH_DLL_PUBLIC true_given : std::true_type {}; + struct CATCH_DLL_PUBLIC is_callable_tester { + template + true_given()(std::declval()...))> static test(int); + template + std::false_type static test(...); + }; + + template + struct is_callable; + + template + struct is_callable : decltype(is_callable_tester::test(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 + using FunctionReturnType = std::remove_reference_t>>; +#else + template + using FunctionReturnType = std::remove_reference_t>>; +#endif + +} // namespace Catch + +namespace mpl_{ + struct na; +} + +#endif // CATCH_META_HPP_INCLUDED + + +#ifndef CATCH_INTERFACES_CAPTURE_HPP_INCLUDED +#define CATCH_INTERFACES_CAPTURE_HPP_INCLUDED + + + +#ifndef CATCH_RESULT_TYPE_HPP_INCLUDED +#define CATCH_RESULT_TYPE_HPP_INCLUDED + + +namespace Catch { + + // ResultWas::OfType enum + struct CATCH_DLL_PUBLIC ResultWas { + enum OfType { + Unknown = -1, + Ok = 0, + Info = 1, + Warning = 2, + + FailureBit = 0x10, + + ExpressionFailed = FailureBit | 1, + ExplicitFailure = FailureBit | 2, + + Exception = 0x100 | FailureBit, + + ThrewException = Exception | 1, + DidntThrowException = Exception | 2, + + FatalErrorCondition = 0x200 | FailureBit + + }; + }; + + bool isOk( ResultWas::OfType resultType ); + bool isJustInfo( int flags ); + + + // ResultDisposition::Flags enum + struct CATCH_DLL_PUBLIC ResultDisposition { + enum Flags { + Normal = 0x01, + + ContinueOnFailure = + 0x02, // Failures fail test, but execution continues + FalseTest = 0x04, // Prefix expression with ! + SuppressFail = + 0x08 // Failures are reported but do not fail the test + }; + }; + + CATCH_DLL_PUBLIC ResultDisposition::Flags + operator|( ResultDisposition::Flags lhs, ResultDisposition::Flags rhs ); + + bool shouldContinueOnFailure( int flags ); + inline bool isFalseTest( int flags ) { return ( flags & ResultDisposition::FalseTest ) != 0; } + bool shouldSuppressFailure( int flags ); + +} // end namespace Catch + +#endif // CATCH_RESULT_TYPE_HPP_INCLUDED #ifndef CATCH_STRINGREF_HPP_INCLUDED #define CATCH_STRINGREF_HPP_INCLUDED +#include #include -#include #include -#include +#include namespace Catch { /// 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. - class StringRef { + class CATCH_DLL_PUBLIC StringRef { public: using size_type = std::size_t; using const_iterator = const char*; @@ -171,10 +424,12 @@ namespace Catch { constexpr const_iterator begin() const { return m_start; } constexpr const_iterator end() const { return m_start + m_size; } - - friend std::string& operator += (std::string& lhs, StringRef sr); - friend std::ostream& operator << (std::ostream& os, StringRef sr); - friend std::string operator+(StringRef lhs, StringRef rhs); + CATCH_DLL_PUBLIC friend std::string& operator+=( std::string& lhs, + StringRef sr ); + CATCH_DLL_PUBLIC friend std::ostream& operator<<( std::ostream& os, + StringRef sr ); + CATCH_DLL_PUBLIC friend std::string operator+( StringRef lhs, + StringRef rhs ); /** * Provides a three-way comparison with rhs @@ -182,10 +437,9 @@ namespace Catch { * Returns negative number if lhs < rhs, 0 if lhs == rhs, and a positive * number if lhs > rhs */ - int compare( StringRef rhs ) const; + CATCH_DLL_PUBLIC int compare( StringRef rhs ) const; }; - constexpr auto operator ""_sr( char const* rawChars, std::size_t size ) noexcept -> StringRef { return StringRef( rawChars, size ); } @@ -196,2369 +450,2149 @@ constexpr auto operator ""_catch_sr( char const* rawChars, std::size_t size ) no } #endif // CATCH_STRINGREF_HPP_INCLUDED - #include -#include #include -#include namespace Catch { - enum class Verbosity { - Quiet = 0, - Normal, - High - }; + class AssertionResult; + struct AssertionInfo; + struct SectionInfo; + struct SectionEndInfo; + struct MessageInfo; + struct MessageBuilder; + struct Counts; + struct AssertionReaction; + struct SourceLineInfo; - struct WarnAbout { enum What { - Nothing = 0x00, - //! A test case or leaf section did not run any assertions - NoAssertions = 0x01, - //! A command line test spec matched no test cases - UnmatchedTestSpec = 0x02, - }; }; + class ITransientExpression; + class IGeneratorTracker; - enum class ShowDurations { - DefaultForReporter, - Always, - Never - }; - enum class TestRunOrder { - Declared, - LexicographicallySorted, - Randomized - }; - enum class ColourMode : std::uint8_t { - //! Let Catch2 pick implementation based on platform detection - PlatformDefault, - //! Use ANSI colour code escapes - ANSI, - //! Use Win32 console colour API - Win32, - //! Don't use any colour - None - }; - struct WaitForKeypress { enum When { - Never, - BeforeStart = 1, - BeforeExit = 2, - BeforeStartAndExit = BeforeStart | BeforeExit - }; }; - - class TestSpec; - class IStream; + struct BenchmarkInfo; + template > + struct BenchmarkStats; - class IConfig : public Detail::NonCopyable { + class CATCH_DLL_PUBLIC IResultCapture { public: - virtual ~IConfig(); - - virtual bool allowThrows() const = 0; - virtual StringRef name() const = 0; - virtual bool includeSuccessfulResults() const = 0; - virtual bool shouldDebugBreak() const = 0; - virtual bool warnAboutMissingAssertions() const = 0; - virtual bool warnAboutUnmatchedTestSpecs() const = 0; - virtual bool zeroTestsCountAsSuccess() const = 0; - virtual int abortAfter() const = 0; - virtual bool showInvisibles() const = 0; - virtual ShowDurations showDurations() const = 0; - virtual double minDuration() const = 0; - virtual TestSpec const& testSpec() const = 0; - virtual bool hasTestFilters() const = 0; - virtual std::vector const& getTestsOrTags() const = 0; - virtual TestRunOrder runOrder() const = 0; - virtual uint32_t rngSeed() const = 0; - virtual unsigned int shardCount() const = 0; - virtual unsigned int shardIndex() const = 0; - virtual ColourMode defaultColourMode() const = 0; - virtual std::vector const& getSectionsToRun() const = 0; - virtual Verbosity verbosity() const = 0; - - virtual bool benchmarkNoAnalysis() const = 0; - virtual unsigned int benchmarkSamples() const = 0; - virtual double benchmarkConfidenceInterval() const = 0; - virtual unsigned int benchmarkResamples() const = 0; - virtual std::chrono::milliseconds benchmarkWarmupTime() const = 0; - }; -} + virtual ~IResultCapture(); -#endif // CATCH_INTERFACES_CONFIG_HPP_INCLUDED + virtual bool sectionStarted( SectionInfo const& sectionInfo, + Counts& assertions ) = 0; + virtual void sectionEnded( SectionEndInfo const& endInfo ) = 0; + virtual void sectionEndedEarly( SectionEndInfo const& endInfo ) = 0; + virtual auto acquireGeneratorTracker( StringRef generatorName, SourceLineInfo const& lineInfo ) -> IGeneratorTracker& = 0; -#ifndef CATCH_COMPILER_CAPABILITIES_HPP_INCLUDED -#define CATCH_COMPILER_CAPABILITIES_HPP_INCLUDED + virtual void benchmarkPreparing( StringRef name ) = 0; + virtual void benchmarkStarting( BenchmarkInfo const& info ) = 0; + virtual void benchmarkEnded( BenchmarkStats<> const& stats ) = 0; + virtual void benchmarkFailed( StringRef error ) = 0; -// Detect a number of compiler features - by compiler -// The following features are defined: -// -// CATCH_CONFIG_WINDOWS_SEH : is Windows SEH supported? -// CATCH_CONFIG_POSIX_SIGNALS : are POSIX signals supported? -// CATCH_CONFIG_DISABLE_EXCEPTIONS : Are exceptions enabled? -// **************** -// Note to maintainers: if new toggles are added please document them -// in configuration.md, too -// **************** + virtual void pushScopedMessage( MessageInfo const& message ) = 0; + virtual void popScopedMessage( MessageInfo const& message ) = 0; -// In general each macro has a _NO_ form -// (e.g. CATCH_CONFIG_NO_POSIX_SIGNALS) which disables the feature. -// Many features, at point of detection, define an _INTERNAL_ macro, so they -// can be combined, en-mass, with the _NO_ forms later. + virtual void emplaceUnscopedMessage( MessageBuilder const& builder ) = 0; + virtual void handleFatalErrorCondition( StringRef message ) = 0; + virtual void handleExpr + ( AssertionInfo const& info, + ITransientExpression const& expr, + AssertionReaction& reaction ) = 0; + virtual void handleMessage + ( AssertionInfo const& info, + ResultWas::OfType resultType, + StringRef message, + AssertionReaction& reaction ) = 0; + virtual void handleUnexpectedExceptionNotThrown + ( AssertionInfo const& info, + AssertionReaction& reaction ) = 0; + virtual void handleUnexpectedInflightException + ( AssertionInfo const& info, + std::string const& message, + AssertionReaction& reaction ) = 0; + virtual void handleIncomplete + ( AssertionInfo const& info ) = 0; + virtual void handleNonExpr + ( AssertionInfo const &info, + ResultWas::OfType resultType, + AssertionReaction &reaction ) = 0; -#ifndef CATCH_PLATFORM_HPP_INCLUDED -#define CATCH_PLATFORM_HPP_INCLUDED -// See e.g.: -// https://opensource.apple.com/source/CarbonHeaders/CarbonHeaders-18.1/TargetConditionals.h.auto.html -#ifdef __APPLE__ -# include -# 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 + virtual bool lastAssertionPassed() = 0; + virtual void assertionPassed() = 0; -#elif defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER) || defined(__MINGW32__) -# define CATCH_PLATFORM_WINDOWS -#endif + // Deprecated, do not use: + virtual std::string getCurrentTestName() const = 0; + virtual const AssertionResult* getLastResult() const = 0; + virtual void exceptionEarlyReported() = 0; + }; -#endif // CATCH_PLATFORM_HPP_INCLUDED + CATCH_DLL_PUBLIC IResultCapture& getResultCapture(); +} -#ifdef __cplusplus +#endif // CATCH_INTERFACES_CAPTURE_HPP_INCLUDED -# if (__cplusplus >= 201402L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 201402L) -# define CATCH_CPP14_OR_GREATER -# endif -# if (__cplusplus >= 201703L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) -# define CATCH_CPP17_OR_GREATER -# endif +#ifndef CATCH_INTERFACES_REGISTRY_HUB_HPP_INCLUDED +#define CATCH_INTERFACES_REGISTRY_HUB_HPP_INCLUDED -#endif -// 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" ) -// This only works on GCC 9+. so we have to also add a global suppression of Wparentheses -// for older versions of GCC. -# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \ - _Pragma( "GCC diagnostic ignored \"-Wparentheses\"" ) +#ifndef CATCH_UNIQUE_PTR_HPP_INCLUDED +#define CATCH_UNIQUE_PTR_HPP_INCLUDED -# define CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \ - _Pragma( "GCC diagnostic ignored \"-Wunused-variable\"" ) +#include +#include -# define CATCH_INTERNAL_IGNORE_BUT_WARN(...) (void)__builtin_constant_p(__VA_ARGS__) +namespace Catch { +namespace Detail { + /** + * A reimplementation of `std::unique_ptr` for improved compilation performance + * + * Does not support arrays nor custom deleters. + */ + template class CATCH_DLL_PUBLIC unique_ptr { + T* m_ptr; + public: + constexpr unique_ptr(std::nullptr_t = nullptr): + m_ptr{} + {} + explicit constexpr unique_ptr(T* ptr): + m_ptr(ptr) + {} -#endif + template ::value>> + unique_ptr(unique_ptr&& from): + m_ptr(from.release()) + {} -#if defined(__clang__) && !defined(_MSC_VER) + template ::value>> + unique_ptr& operator=(unique_ptr&& from) { + reset(from.release()); -# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION _Pragma( "clang diagnostic push" ) -# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION _Pragma( "clang diagnostic pop" ) + return *this; + } -// 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") -// ``` -// -// Similarly, NVHPC's implementation of `__builtin_constant_p` has a bug which -// results in calls to the immediately evaluated lambda expressions to be -// reported as unevaluated lambdas. -// https://developer.nvidia.com/nvidia_bug/3321845. -// -// Therefore, `CATCH_INTERNAL_IGNORE_BUT_WARN` is not implemented. -# if !defined(__ibmxl__) && !defined(__CUDACC__) && !defined( __NVCOMPILER ) -# define CATCH_INTERNAL_IGNORE_BUT_WARN(...) (void)__builtin_constant_p(__VA_ARGS__) /* NOLINT(cppcoreguidelines-pro-type-vararg, hicpp-vararg) */ -# endif + unique_ptr(unique_ptr const&) = delete; + unique_ptr& operator=(unique_ptr const&) = delete; + unique_ptr(unique_ptr&& rhs) noexcept: + m_ptr(rhs.m_ptr) { + rhs.m_ptr = nullptr; + } + unique_ptr& operator=(unique_ptr&& rhs) noexcept { + reset(rhs.release()); -# define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ - _Pragma( "clang diagnostic ignored \"-Wexit-time-destructors\"" ) \ - _Pragma( "clang diagnostic ignored \"-Wglobal-constructors\"") + return *this; + } -# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \ - _Pragma( "clang diagnostic ignored \"-Wparentheses\"" ) + ~unique_ptr() { + delete m_ptr; + } -# define CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \ - _Pragma( "clang diagnostic ignored \"-Wunused-variable\"" ) + T& operator*() { + assert(m_ptr); + return *m_ptr; + } + T const& operator*() const { + assert(m_ptr); + return *m_ptr; + } + T* operator->() noexcept { + assert(m_ptr); + return m_ptr; + } + T const* operator->() const noexcept { + assert(m_ptr); + return m_ptr; + } -# define CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS \ - _Pragma( "clang diagnostic ignored \"-Wgnu-zero-variadic-macro-arguments\"" ) + T* get() { return m_ptr; } + T const* get() const { return m_ptr; } -# define CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \ - _Pragma( "clang diagnostic ignored \"-Wunused-template\"" ) + void reset(T* ptr = nullptr) { + delete m_ptr; + m_ptr = ptr; + } -#endif // __clang__ + T* release() { + auto temp = m_ptr; + m_ptr = nullptr; + return temp; + } + explicit operator bool() const { + return m_ptr; + } -//////////////////////////////////////////////////////////////////////////////// -// Assume that non-Windows platforms support posix signals by default -#if !defined(CATCH_PLATFORM_WINDOWS) - #define CATCH_INTERNAL_CONFIG_POSIX_SIGNALS -#endif + friend void swap(unique_ptr& lhs, unique_ptr& rhs) { + auto temp = lhs.m_ptr; + lhs.m_ptr = rhs.m_ptr; + rhs.m_ptr = temp; + } + }; -//////////////////////////////////////////////////////////////////////////////// -// We know some environments not to support full POSIX signals -#if defined(__CYGWIN__) || defined(__QNX__) || defined(__EMSCRIPTEN__) || defined(__DJGPP__) - #define CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS -#endif + //! Specialization to cause compile-time error for arrays + template + class unique_ptr; -#ifdef __OS400__ -# define CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS -#endif + template + unique_ptr make_unique(Args&&... args) { + return unique_ptr(new T(CATCH_FORWARD(args)...)); + } -//////////////////////////////////////////////////////////////////////////////// -// Android somehow still does not support std::to_string -#if defined(__ANDROID__) -# define CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING -#endif -//////////////////////////////////////////////////////////////////////////////// -// Not all Windows environments support SEH properly -#if defined(__MINGW32__) -# define CATCH_INTERNAL_CONFIG_NO_WINDOWS_SEH -#endif +} // end namespace Detail +} // end namespace Catch -//////////////////////////////////////////////////////////////////////////////// -// PS4 -#if defined(__ORBIS__) -# define CATCH_INTERNAL_CONFIG_NO_NEW_CAPTURE -#endif +#endif // CATCH_UNIQUE_PTR_HPP_INCLUDED +#include -//////////////////////////////////////////////////////////////////////////////// -// Cygwin -#ifdef __CYGWIN__ +namespace Catch { -// Required for some versions of Cygwin to declare gettimeofday -// see: http://stackoverflow.com/questions/36901803/gettimeofday-not-declared-in-this-scope-cygwin -# define _BSD_SOURCE -// 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)) + class TestCaseHandle; + struct TestCaseInfo; + class ITestCaseRegistry; + class IExceptionTranslatorRegistry; + class IExceptionTranslator; + class IReporterRegistry; + class IReporterFactory; + class ITagAliasRegistry; + class ITestInvoker; + class IMutableEnumValuesRegistry; + struct SourceLineInfo; -# define CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING + class StartupExceptionRegistry; + class EventListenerFactory; -# endif -#endif // __CYGWIN__ + using IReporterFactoryPtr = Detail::unique_ptr; -//////////////////////////////////////////////////////////////////////////////// -// Visual C++ -#if defined(_MSC_VER) + class CATCH_DLL_PUBLIC IRegistryHub { + public: + virtual ~IRegistryHub(); // = default -# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION __pragma( warning(push) ) -# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION __pragma( warning(pop) ) + virtual IReporterRegistry const& getReporterRegistry() const = 0; + virtual ITestCaseRegistry const& getTestCaseRegistry() const = 0; + virtual ITagAliasRegistry const& getTagAliasRegistry() const = 0; + virtual IExceptionTranslatorRegistry const& getExceptionTranslatorRegistry() const = 0; -// Universal Windows platform does not support SEH -// Or console colours (or console at all...) -# if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP) -# define CATCH_INTERNAL_CONFIG_NO_COLOUR_WIN32 -# else -# define CATCH_INTERNAL_CONFIG_WINDOWS_SEH -# endif -// 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(__clang__) // Handle Clang masquerading for msvc -# if !defined(_MSVC_TRADITIONAL) || (defined(_MSVC_TRADITIONAL) && _MSVC_TRADITIONAL) -# define CATCH_INTERNAL_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR -# endif // MSVC_TRADITIONAL -# endif // __clang__ + virtual StartupExceptionRegistry const& getStartupExceptionRegistry() const = 0; + }; -#endif // _MSC_VER + class CATCH_DLL_PUBLIC IMutableRegistryHub { + public: + virtual ~IMutableRegistryHub(); // = default + virtual void registerReporter( std::string const& name, IReporterFactoryPtr factory ) = 0; + virtual void registerListener( Detail::unique_ptr factory ) = 0; + virtual void registerTest(Detail::unique_ptr&& testInfo, Detail::unique_ptr&& invoker) = 0; + virtual void registerTranslator( Detail::unique_ptr&& 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; + }; -#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 + CATCH_DLL_PUBLIC IRegistryHub const& getRegistryHub(); + CATCH_DLL_PUBLIC IMutableRegistryHub& getMutableRegistryHub(); + CATCH_DLL_PUBLIC void cleanUp(); + CATCH_DLL_PUBLIC std::string translateActiveException(); +} -//////////////////////////////////////////////////////////////////////////////// -// Check if we are compiled with -fno-exceptions or equivalent -#if defined(__EXCEPTIONS) || defined(__cpp_exceptions) || defined(_CPPUNWIND) -# define CATCH_INTERNAL_CONFIG_EXCEPTIONS_ENABLED -#endif +#endif // CATCH_INTERFACES_REGISTRY_HUB_HPP_INCLUDED +#include -//////////////////////////////////////////////////////////////////////////////// -// Embarcadero C++Build -#if defined(__BORLANDC__) - #define CATCH_INTERNAL_CONFIG_POLYFILL_ISNAN -#endif +namespace Catch { + namespace Benchmark { + namespace Detail { + template + struct CompleteType { using type = T; }; + template <> + struct CompleteType { struct type {}; }; -//////////////////////////////////////////////////////////////////////////////// + template + using CompleteType_t = typename CompleteType::type; -// 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_INTERNAL_CONFIG_NO_COLOUR_WIN32 -#endif + template + struct CompleteInvoker { + template + static Result invoke(Fun&& fun, Args&&... args) { + return CATCH_FORWARD(fun)(CATCH_FORWARD(args)...); + } + }; + template <> + struct CompleteInvoker { + template + static CompleteType_t invoke(Fun&& fun, Args&&... args) { + CATCH_FORWARD(fun)(CATCH_FORWARD(args)...); + return {}; + } + }; -#if !defined(_GLIBCXX_USE_C99_MATH_TR1) -#define CATCH_INTERNAL_CONFIG_GLOBAL_NEXTAFTER -#endif + // invoke and not return void :( + template + CompleteType_t> complete_invoke(Fun&& fun, Args&&... args) { + return CompleteInvoker>::invoke(CATCH_FORWARD(fun), CATCH_FORWARD(args)...); + } -// Various stdlib support checks that require __has_include -#if defined(__has_include) - // Check if string_view is available and usable - #if __has_include() && defined(CATCH_CPP17_OR_GREATER) - # define CATCH_INTERNAL_CONFIG_CPP17_STRING_VIEW - #endif + } // namespace Detail - // Check if optional is available and usable - # if __has_include() && defined(CATCH_CPP17_OR_GREATER) - # define CATCH_INTERNAL_CONFIG_CPP17_OPTIONAL - # endif // __has_include() && defined(CATCH_CPP17_OR_GREATER) + template + Detail::CompleteType_t> user_code(Fun&& fun) { + return Detail::complete_invoke(CATCH_FORWARD(fun)); + } + } // namespace Benchmark +} // namespace Catch - // Check if byte is available and usable - # if __has_include() && defined(CATCH_CPP17_OR_GREATER) - # include - # if defined(__cpp_lib_byte) && (__cpp_lib_byte > 0) - # define CATCH_INTERNAL_CONFIG_CPP17_BYTE - # endif - # endif // __has_include() && defined(CATCH_CPP17_OR_GREATER) +#endif // CATCH_COMPLETE_INVOKE_HPP_INCLUDED - // Check if variant is available and usable - # if __has_include() && 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 - # 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() && defined(CATCH_CPP17_OR_GREATER) -#endif // defined(__has_include) +namespace Catch { + namespace Benchmark { + namespace Detail { + struct CATCH_DLL_PUBLIC ChronometerConcept { + virtual void start() = 0; + virtual void finish() = 0; + virtual ~ChronometerConcept(); // = default; + ChronometerConcept() = default; + ChronometerConcept(ChronometerConcept const&) = default; + ChronometerConcept& operator=(ChronometerConcept const&) = default; + }; + template + struct CATCH_DLL_PUBLIC ChronometerModel final + : public ChronometerConcept { + void start() override { started = Clock::now(); } + void finish() override { finished = Clock::now(); } -#if defined(CATCH_INTERNAL_CONFIG_WINDOWS_SEH) && !defined(CATCH_CONFIG_NO_WINDOWS_SEH) && !defined(CATCH_CONFIG_WINDOWS_SEH) && !defined(CATCH_INTERNAL_CONFIG_NO_WINDOWS_SEH) -# define CATCH_CONFIG_WINDOWS_SEH -#endif -// This is set by default, because we assume that unix compilers are posix-signal-compatible by default. -#if defined(CATCH_INTERNAL_CONFIG_POSIX_SIGNALS) && !defined(CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS) && !defined(CATCH_CONFIG_NO_POSIX_SIGNALS) && !defined(CATCH_CONFIG_POSIX_SIGNALS) -# define CATCH_CONFIG_POSIX_SIGNALS -#endif + ClockDuration elapsed() const { return finished - started; } -#if !defined(CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING) && !defined(CATCH_CONFIG_NO_CPP11_TO_STRING) && !defined(CATCH_CONFIG_CPP11_TO_STRING) -# define CATCH_CONFIG_CPP11_TO_STRING -#endif + TimePoint started; + TimePoint finished; + }; + } // namespace Detail -#if defined(CATCH_INTERNAL_CONFIG_CPP17_OPTIONAL) && !defined(CATCH_CONFIG_NO_CPP17_OPTIONAL) && !defined(CATCH_CONFIG_CPP17_OPTIONAL) -# define CATCH_CONFIG_CPP17_OPTIONAL -#endif + struct CATCH_DLL_PUBLIC Chronometer { + public: + template + void measure(Fun&& fun) { measure(CATCH_FORWARD(fun), is_callable()); } -#if defined(CATCH_INTERNAL_CONFIG_CPP17_STRING_VIEW) && !defined(CATCH_CONFIG_NO_CPP17_STRING_VIEW) && !defined(CATCH_CONFIG_CPP17_STRING_VIEW) -# define CATCH_CONFIG_CPP17_STRING_VIEW -#endif + int runs() const { return repeats; } -#if defined(CATCH_INTERNAL_CONFIG_CPP17_VARIANT) && !defined(CATCH_CONFIG_NO_CPP17_VARIANT) && !defined(CATCH_CONFIG_CPP17_VARIANT) -# define CATCH_CONFIG_CPP17_VARIANT -#endif + Chronometer(Detail::ChronometerConcept& meter, int repeats_) + : impl(&meter) + , repeats(repeats_) {} -#if defined(CATCH_INTERNAL_CONFIG_CPP17_BYTE) && !defined(CATCH_CONFIG_NO_CPP17_BYTE) && !defined(CATCH_CONFIG_CPP17_BYTE) -# define CATCH_CONFIG_CPP17_BYTE -#endif + private: + template + void measure(Fun&& fun, std::false_type) { + measure([&fun](int) { return fun(); }, std::true_type()); + } + template + void measure(Fun&& fun, std::true_type) { + Detail::optimizer_barrier(); + impl->start(); + for (int i = 0; i < repeats; ++i) invoke_deoptimized(fun, i); + impl->finish(); + Detail::optimizer_barrier(); + } -#if defined(CATCH_CONFIG_EXPERIMENTAL_REDIRECT) -# define CATCH_INTERNAL_CONFIG_NEW_CAPTURE -#endif + Detail::ChronometerConcept* impl; + int repeats; + }; + } // namespace Benchmark +} // namespace Catch -#if defined(CATCH_INTERNAL_CONFIG_NEW_CAPTURE) && !defined(CATCH_INTERNAL_CONFIG_NO_NEW_CAPTURE) && !defined(CATCH_CONFIG_NO_NEW_CAPTURE) && !defined(CATCH_CONFIG_NEW_CAPTURE) -# define CATCH_CONFIG_NEW_CAPTURE -#endif +#endif // CATCH_CHRONOMETER_HPP_INCLUDED -#if !defined( CATCH_INTERNAL_CONFIG_EXCEPTIONS_ENABLED ) && \ - !defined( CATCH_CONFIG_DISABLE_EXCEPTIONS ) && \ - !defined( CATCH_CONFIG_NO_DISABLE_EXCEPTIONS ) -# define CATCH_CONFIG_DISABLE_EXCEPTIONS -#endif -#if defined(CATCH_INTERNAL_CONFIG_POLYFILL_ISNAN) && !defined(CATCH_CONFIG_NO_POLYFILL_ISNAN) && !defined(CATCH_CONFIG_POLYFILL_ISNAN) -# define CATCH_CONFIG_POLYFILL_ISNAN -#endif +// Adapted from donated nonius code. -#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 +#ifndef CATCH_ENVIRONMENT_HPP_INCLUDED +#define CATCH_ENVIRONMENT_HPP_INCLUDED -#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 -#endif -#if !defined(CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS) -# define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS -#endif -#if !defined(CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS) -# define CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS -#endif -#if !defined(CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS) -# define CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS -#endif +// Adapted from donated nonius code. -// 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 +#ifndef CATCH_OUTLIER_CLASSIFICATION_HPP_INCLUDED +#define CATCH_OUTLIER_CLASSIFICATION_HPP_INCLUDED -#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 +namespace Catch { + namespace Benchmark { + struct CATCH_DLL_PUBLIC 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 -#if defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) -#define CATCH_TRY if ((true)) -#define CATCH_CATCH_ALL if ((false)) -#define CATCH_CATCH_ANON(type) if ((false)) -#else -#define CATCH_TRY try -#define CATCH_CATCH_ALL catch (...) -#define CATCH_CATCH_ANON(type) catch (type) -#endif + int total() const { + return low_severe + low_mild + high_mild + high_severe; + } + }; + } // namespace Benchmark +} // namespace Catch -#if defined(CATCH_INTERNAL_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR) && !defined(CATCH_CONFIG_NO_TRADITIONAL_MSVC_PREPROCESSOR) && !defined(CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR) -#define CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR -#endif +#endif // CATCH_OUTLIERS_CLASSIFICATION_HPP_INCLUDED -#if defined( CATCH_PLATFORM_WINDOWS ) && \ - !defined( CATCH_CONFIG_COLOUR_WIN32 ) && \ - !defined( CATCH_CONFIG_NO_COLOUR_WIN32 ) && \ - !defined( CATCH_INTERNAL_CONFIG_NO_COLOUR_WIN32 ) -# define CATCH_CONFIG_COLOUR_WIN32 -#endif +namespace Catch { + namespace Benchmark { + template + struct CATCH_DLL_PUBLIC EnvironmentEstimate { + Duration mean; + OutlierClassification outliers; + template + operator EnvironmentEstimate() const { + return { mean, outliers }; + } + }; + template struct CATCH_DLL_PUBLIC Environment { + using clock_type = Clock; + EnvironmentEstimate> clock_resolution; + EnvironmentEstimate> clock_cost; + }; + } // namespace Benchmark +} // namespace Catch -#endif // CATCH_COMPILER_CAPABILITIES_HPP_INCLUDED +#endif // CATCH_ENVIRONMENT_HPP_INCLUDED -#ifndef CATCH_CONTEXT_HPP_INCLUDED -#define CATCH_CONTEXT_HPP_INCLUDED +// Adapted from donated nonius code. -namespace Catch { +#ifndef CATCH_EXECUTION_PLAN_HPP_INCLUDED +#define CATCH_EXECUTION_PLAN_HPP_INCLUDED - class IResultCapture; - class IConfig; +#include - class IContext { - public: - virtual ~IContext(); // = default - virtual IResultCapture* getResultCapture() = 0; - virtual IConfig const* getConfig() const = 0; - }; +// Adapted from donated nonius code. - class IMutableContext : public IContext { - public: - virtual ~IMutableContext(); // = default - virtual void setResultCapture( IResultCapture* resultCapture ) = 0; - virtual void setConfig( IConfig const* config ) = 0; +#ifndef CATCH_BENCHMARK_FUNCTION_HPP_INCLUDED +#define CATCH_BENCHMARK_FUNCTION_HPP_INCLUDED - private: - static IMutableContext *currentContext; - friend IMutableContext& getCurrentMutableContext(); - friend void cleanUpContext(); - static void createContext(); - }; +#include - inline IMutableContext& getCurrentMutableContext() - { - if( !IMutableContext::currentContext ) - IMutableContext::createContext(); - // NOLINTNEXTLINE(clang-analyzer-core.uninitialized.UndefReturn) - return *IMutableContext::currentContext; - } +namespace Catch { + namespace Benchmark { + namespace Detail { + template + struct is_related + : std::is_same, std::decay_t> {}; - inline IContext& getCurrentContext() - { - return getCurrentMutableContext(); - } + /// 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 CATCH_DLL_PUBLIC BenchmarkFunction { + private: + struct callable { + virtual void call(Chronometer meter) const = 0; + virtual Catch::Detail::unique_ptr clone() const = 0; + virtual ~callable(); // = default; - void cleanUpContext(); + callable() = default; + callable(callable const&) = default; + callable& operator=(callable const&) = default; + }; + template + struct model : public callable { + model(Fun&& fun_) : fun(CATCH_MOVE(fun_)) {} + model(Fun const& fun_) : fun(fun_) {} - class SimplePcg32; - SimplePcg32& rng(); -} + Catch::Detail::unique_ptr clone() const override { + return Catch::Detail::make_unique>( *this ); + } -#endif // CATCH_CONTEXT_HPP_INCLUDED + void call(Chronometer meter) const override { + call(meter, is_callable()); + } + void call(Chronometer meter, std::true_type) const { + fun(meter); + } + void call(Chronometer meter, std::false_type) const { + meter.measure(fun); + } + Fun fun; + }; -#ifndef CATCH_INTERFACES_REPORTER_HPP_INCLUDED -#define CATCH_INTERFACES_REPORTER_HPP_INCLUDED + struct do_nothing { void operator()() const {} }; + template + BenchmarkFunction(model* c) : f(c) {} + public: + BenchmarkFunction() + : f(new model{ {} }) {} -#ifndef CATCH_SECTION_INFO_HPP_INCLUDED -#define CATCH_SECTION_INFO_HPP_INCLUDED + template ::value, int> = 0> + BenchmarkFunction(Fun&& fun) + : f(new model>(CATCH_FORWARD(fun))) {} + BenchmarkFunction( BenchmarkFunction&& that ) noexcept: + f( CATCH_MOVE( that.f ) ) {} + BenchmarkFunction(BenchmarkFunction const& that) + : f(that.f->clone()) {} -#ifndef CATCH_MOVE_AND_FORWARD_HPP_INCLUDED -#define CATCH_MOVE_AND_FORWARD_HPP_INCLUDED + BenchmarkFunction& + operator=( BenchmarkFunction&& that ) noexcept { + f = CATCH_MOVE( that.f ); + return *this; + } -#include + BenchmarkFunction& operator=(BenchmarkFunction const& that) { + f = that.f->clone(); + return *this; + } -//! Replacement for std::move with better compile time performance -#define CATCH_MOVE(...) static_cast&&>(__VA_ARGS__) + void operator()(Chronometer meter) const { f->call(meter); } -//! Replacement for std::forward with better compile time performance -#define CATCH_FORWARD(...) static_cast(__VA_ARGS__) + private: + Catch::Detail::unique_ptr f; + }; + } // namespace Detail + } // namespace Benchmark +} // namespace Catch -#endif // CATCH_MOVE_AND_FORWARD_HPP_INCLUDED +#endif // CATCH_BENCHMARK_FUNCTION_HPP_INCLUDED -#ifndef CATCH_SOURCE_LINE_INFO_HPP_INCLUDED -#define CATCH_SOURCE_LINE_INFO_HPP_INCLUDED +// Adapted from donated nonius code. -#include -#include +#ifndef CATCH_REPEAT_HPP_INCLUDED +#define CATCH_REPEAT_HPP_INCLUDED -namespace Catch { +#include - struct SourceLineInfo { +namespace Catch { + namespace Benchmark { + namespace Detail { + template + struct repeater { + void operator()(int k) const { + for (int i = 0; i < k; ++i) { + fun(); + } + } + Fun fun; + }; + template + repeater> repeat(Fun&& fun) { + return { CATCH_FORWARD(fun) }; + } + } // namespace Detail + } // namespace Benchmark +} // namespace Catch - SourceLineInfo() = delete; - constexpr SourceLineInfo( char const* _file, std::size_t _line ) noexcept: - file( _file ), - line( _line ) - {} +#endif // CATCH_REPEAT_HPP_INCLUDED - bool operator == ( SourceLineInfo const& other ) const noexcept; - bool operator < ( SourceLineInfo const& other ) const noexcept; - char const* file; - std::size_t line; +// Adapted from donated nonius code. - friend std::ostream& operator << (std::ostream& os, SourceLineInfo const& info); - }; -} +#ifndef CATCH_RUN_FOR_AT_LEAST_HPP_INCLUDED +#define CATCH_RUN_FOR_AT_LEAST_HPP_INCLUDED -#define CATCH_INTERNAL_LINEINFO \ - ::Catch::SourceLineInfo( __FILE__, static_cast( __LINE__ ) ) -#endif // CATCH_SOURCE_LINE_INFO_HPP_INCLUDED +// Adapted from donated nonius code. -#ifndef CATCH_TOTALS_HPP_INCLUDED -#define CATCH_TOTALS_HPP_INCLUDED +#ifndef CATCH_MEASURE_HPP_INCLUDED +#define CATCH_MEASURE_HPP_INCLUDED -#include -namespace Catch { - struct Counts { - Counts operator - ( Counts const& other ) const; - Counts& operator += ( Counts const& other ); +// Adapted from donated nonius code. - std::uint64_t total() const; - bool allPassed() const; - bool allOk() const; +#ifndef CATCH_TIMING_HPP_INCLUDED +#define CATCH_TIMING_HPP_INCLUDED - std::uint64_t passed = 0; - std::uint64_t failed = 0; - std::uint64_t failedButOk = 0; - }; - struct Totals { +#include - Totals operator - ( Totals const& other ) const; - Totals& operator += ( Totals const& other ); +namespace Catch { + namespace Benchmark { + template + struct Timing { + Duration elapsed; + Result result; + int iterations; + }; + template + using TimingOf = Timing, Detail::CompleteType_t>>; + } // namespace Benchmark +} // namespace Catch - Totals delta( Totals const& prevTotals ) const; +#endif // CATCH_TIMING_HPP_INCLUDED - Counts assertions; - Counts testCases; - }; -} +namespace Catch { + namespace Benchmark { + namespace Detail { + template + TimingOf measure(Fun&& fun, Args&&... args) { + auto start = Clock::now(); + auto&& r = Detail::complete_invoke(fun, CATCH_FORWARD(args)...); + auto end = Clock::now(); + auto delta = end - start; + return { delta, CATCH_FORWARD(r), 1 }; + } + } // namespace Detail + } // namespace Benchmark +} // namespace Catch -#endif // CATCH_TOTALS_HPP_INCLUDED +#endif // CATCH_MEASURE_HPP_INCLUDED -#include +#include namespace Catch { + namespace Benchmark { + namespace Detail { + template + TimingOf measure_one(Fun&& fun, int iters, std::false_type) { + return Detail::measure(fun, iters); + } + template + TimingOf measure_one(Fun&& fun, int iters, std::true_type) { + Detail::ChronometerModel meter; + auto&& result = Detail::complete_invoke(fun, Chronometer(meter, iters)); - struct SectionInfo { - // The last argument is ignored, so that people can write - // SECTION("ShortName", "Proper description that is long") and - // still use the `-c` flag comfortably. - SectionInfo( SourceLineInfo const& _lineInfo, std::string _name, - const char* const = nullptr ): - name(CATCH_MOVE(_name)), - lineInfo(_lineInfo) - {} - - std::string name; - SourceLineInfo lineInfo; - }; + return { meter.elapsed(), CATCH_MOVE(result), iters }; + } - struct SectionEndInfo { - SectionInfo sectionInfo; - Counts prevAssertions; - double durationInSeconds; - }; + template + using run_for_at_least_argument_t = std::conditional_t::value, Chronometer, int>; -} // end namespace Catch + [[noreturn]] CATCH_DLL_PUBLIC void throw_optimized_away_error(); -#endif // CATCH_SECTION_INFO_HPP_INCLUDED + template + TimingOf> + run_for_at_least(ClockDuration how_long, + const int initial_iterations, + Fun&& fun) { + auto iters = initial_iterations; + while (iters < (1 << 30)) { + auto&& Timing = measure_one(fun, iters, is_callable()); + if (Timing.elapsed >= how_long) { + return { Timing.elapsed, CATCH_MOVE(Timing.result), iters }; + } + iters *= 2; + } + throw_optimized_away_error(); + } + } // namespace Detail + } // namespace Benchmark +} // namespace Catch -#ifndef CATCH_ASSERTION_RESULT_HPP_INCLUDED -#define CATCH_ASSERTION_RESULT_HPP_INCLUDED +#endif // CATCH_RUN_FOR_AT_LEAST_HPP_INCLUDED +#ifndef CATCH_INTERFACES_CONFIG_HPP_INCLUDED +#define CATCH_INTERFACES_CONFIG_HPP_INCLUDED -#ifndef CATCH_ASSERTION_INFO_HPP_INCLUDED -#define CATCH_ASSERTION_INFO_HPP_INCLUDED +#ifndef CATCH_NONCOPYABLE_HPP_INCLUDED +#define CATCH_NONCOPYABLE_HPP_INCLUDED -#ifndef CATCH_RESULT_TYPE_HPP_INCLUDED -#define CATCH_RESULT_TYPE_HPP_INCLUDED namespace Catch { + namespace Detail { - // ResultWas::OfType enum - struct ResultWas { enum OfType { - Unknown = -1, - Ok = 0, - Info = 1, - Warning = 2, - - FailureBit = 0x10, - - ExpressionFailed = FailureBit | 1, - ExplicitFailure = FailureBit | 2, - - Exception = 0x100 | FailureBit, - - ThrewException = Exception | 1, - DidntThrowException = Exception | 2, - - FatalErrorCondition = 0x200 | FailureBit - - }; }; - - bool isOk( ResultWas::OfType resultType ); - bool isJustInfo( int flags ); - - - // ResultDisposition::Flags enum - struct ResultDisposition { enum Flags { - Normal = 0x01, - - ContinueOnFailure = 0x02, // Failures fail test, but execution continues - FalseTest = 0x04, // Prefix expression with ! - SuppressFail = 0x08 // Failures are reported but do not fail the test - }; }; - - ResultDisposition::Flags operator | ( ResultDisposition::Flags lhs, ResultDisposition::Flags rhs ); + //! Deriving classes become noncopyable and nonmovable + class CATCH_DLL_PUBLIC NonCopyable { + NonCopyable( NonCopyable const& ) = delete; + NonCopyable( NonCopyable&& ) = delete; + NonCopyable& operator=( NonCopyable const& ) = delete; + NonCopyable& operator=( NonCopyable&& ) = delete; - bool shouldContinueOnFailure( int flags ); - inline bool isFalseTest( int flags ) { return ( flags & ResultDisposition::FalseTest ) != 0; } - bool shouldSuppressFailure( int flags ); + protected: + NonCopyable() noexcept = default; + }; -} // end namespace Catch + } // namespace Detail +} // namespace Catch -#endif // CATCH_RESULT_TYPE_HPP_INCLUDED +#endif // CATCH_NONCOPYABLE_HPP_INCLUDED +#include +#include +#include +#include namespace Catch { - struct AssertionInfo { - // AssertionInfo() = delete; + enum class CATCH_DLL_PUBLIC Verbosity { Quiet = 0, Normal, High }; - StringRef macroName; - SourceLineInfo lineInfo; - StringRef capturedExpression; - ResultDisposition::Flags resultDisposition; + struct CATCH_DLL_PUBLIC WarnAbout { + enum What { + Nothing = 0x00, + //! A test case or leaf section did not run any assertions + NoAssertions = 0x01, + //! A command line test spec matched no test cases + UnmatchedTestSpec = 0x02, + }; }; -} // end namespace Catch - -#endif // CATCH_ASSERTION_INFO_HPP_INCLUDED - - -#ifndef CATCH_LAZY_EXPR_HPP_INCLUDED -#define CATCH_LAZY_EXPR_HPP_INCLUDED + enum class ShowDurations { + DefaultForReporter, + Always, + Never + }; + enum class TestRunOrder { + Declared, + LexicographicallySorted, + Randomized + }; + enum class ColourMode : std::uint8_t { + //! Let Catch2 pick implementation based on platform detection + PlatformDefault, + //! Use ANSI colour code escapes + ANSI, + //! Use Win32 console colour API + Win32, + //! Don't use any colour + None + }; + struct WaitForKeypress { enum When { + Never, + BeforeStart = 1, + BeforeExit = 2, + BeforeStartAndExit = BeforeStart | BeforeExit + }; }; -#include + class TestSpec; + class IStream; -namespace Catch { + class CATCH_DLL_PUBLIC IConfig : public Detail::NonCopyable { + public: + virtual ~IConfig(); - class ITransientExpression; - - class LazyExpression { - friend class AssertionHandler; - friend struct AssertionStats; - friend class RunContext; - - ITransientExpression const* m_transientExpression = nullptr; - bool m_isNegated; - public: - LazyExpression( bool isNegated ): - m_isNegated(isNegated) - {} - LazyExpression(LazyExpression const& other) = default; - LazyExpression& operator = ( LazyExpression const& ) = delete; - - explicit operator bool() const { - return m_transientExpression != nullptr; - } + virtual bool allowThrows() const = 0; + virtual StringRef name() const = 0; + virtual bool includeSuccessfulResults() const = 0; + virtual bool shouldDebugBreak() const = 0; + virtual bool warnAboutMissingAssertions() const = 0; + virtual bool warnAboutUnmatchedTestSpecs() const = 0; + virtual bool zeroTestsCountAsSuccess() const = 0; + virtual int abortAfter() const = 0; + virtual bool showInvisibles() const = 0; + virtual ShowDurations showDurations() const = 0; + virtual double minDuration() const = 0; + virtual TestSpec const& testSpec() const = 0; + virtual bool hasTestFilters() const = 0; + virtual std::vector const& getTestsOrTags() const = 0; + virtual TestRunOrder runOrder() const = 0; + virtual uint32_t rngSeed() const = 0; + virtual unsigned int shardCount() const = 0; + virtual unsigned int shardIndex() const = 0; + virtual ColourMode defaultColourMode() const = 0; + virtual std::vector const& getSectionsToRun() const = 0; + virtual Verbosity verbosity() const = 0; - friend auto operator << ( std::ostream& os, LazyExpression const& lazyExpr ) -> std::ostream&; + virtual bool skipBenchmarks() const = 0; + virtual bool benchmarkNoAnalysis() const = 0; + virtual unsigned int benchmarkSamples() const = 0; + virtual double benchmarkConfidenceInterval() const = 0; + virtual unsigned int benchmarkResamples() const = 0; + virtual std::chrono::milliseconds benchmarkWarmupTime() const = 0; }; +} -} // namespace Catch - -#endif // CATCH_LAZY_EXPR_HPP_INCLUDED - -#include +#endif // CATCH_INTERFACES_CONFIG_HPP_INCLUDED +#include namespace Catch { + namespace Benchmark { + template struct CATCH_DLL_PUBLIC ExecutionPlan { + int iterations_per_sample; + Duration estimated_duration; + Detail::BenchmarkFunction benchmark; + Duration warmup_time; + int warmup_iterations; - struct AssertionResultData - { - AssertionResultData() = delete; + template + operator ExecutionPlan() const { + return { iterations_per_sample, estimated_duration, benchmark, warmup_time, warmup_iterations }; + } - AssertionResultData( ResultWas::OfType _resultType, LazyExpression const& _lazyExpression ); + template + std::vector> run(const IConfig &cfg, Environment> env) const { + // warmup a bit + Detail::run_for_at_least(std::chrono::duration_cast>(warmup_time), warmup_iterations, Detail::repeat(now{})); - std::string message; - mutable std::string reconstructedExpression; - LazyExpression lazyExpression; - ResultWas::OfType resultType; + std::vector> times; + times.reserve(cfg.benchmarkSamples()); + std::generate_n(std::back_inserter(times), cfg.benchmarkSamples(), [this, env] { + Detail::ChronometerModel model; + this->benchmark(Chronometer(model, iterations_per_sample)); + auto sample_time = model.elapsed() - env.clock_cost.mean; + if (sample_time < FloatDuration::zero()) sample_time = FloatDuration::zero(); + return sample_time / iterations_per_sample; + }); + return times; + } + }; + } // namespace Benchmark +} // namespace Catch - std::string reconstructExpression() const; - }; +#endif // CATCH_EXECUTION_PLAN_HPP_INCLUDED - class AssertionResult { - public: - AssertionResult() = delete; - AssertionResult( AssertionInfo const& info, AssertionResultData const& data ); - bool isOk() const; - bool succeeded() const; - ResultWas::OfType getResultType() const; - bool hasExpression() const; - bool hasMessage() const; - std::string getExpression() const; - std::string getExpressionInMacro() const; - bool hasExpandedExpression() const; - std::string getExpandedExpression() const; - StringRef getMessage() const; - SourceLineInfo getSourceInfo() const; - StringRef getTestMacroName() const; +// Adapted from donated nonius code. - //protected: - AssertionInfo m_info; - AssertionResultData m_resultData; - }; +#ifndef CATCH_ANALYSE_HPP_INCLUDED +#define CATCH_ANALYSE_HPP_INCLUDED -} // end namespace Catch -#endif // CATCH_ASSERTION_RESULT_HPP_INCLUDED +// Adapted from donated nonius code. -#ifndef CATCH_MESSAGE_INFO_HPP_INCLUDED -#define CATCH_MESSAGE_INFO_HPP_INCLUDED +#ifndef CATCH_SAMPLE_ANALYSIS_HPP_INCLUDED +#define CATCH_SAMPLE_ANALYSIS_HPP_INCLUDED +#include -#ifndef CATCH_INTERFACES_CAPTURE_HPP_INCLUDED -#define CATCH_INTERFACES_CAPTURE_HPP_INCLUDED +// Adapted from donated nonius code. -#include -#include +#ifndef CATCH_ESTIMATE_HPP_INCLUDED +#define CATCH_ESTIMATE_HPP_INCLUDED namespace Catch { + namespace Benchmark { + template struct CATCH_DLL_PUBLIC Estimate { + Duration point; + Duration lower_bound; + Duration upper_bound; + double confidence_interval; - class AssertionResult; - struct AssertionInfo; - struct SectionInfo; - struct SectionEndInfo; - struct MessageInfo; - struct MessageBuilder; - struct Counts; - struct AssertionReaction; - struct SourceLineInfo; + template + operator Estimate() const { + return { point, lower_bound, upper_bound, confidence_interval }; + } + }; + } // namespace Benchmark +} // namespace Catch - class ITransientExpression; - class IGeneratorTracker; +#endif // CATCH_ESTIMATE_HPP_INCLUDED +#include +#include - struct BenchmarkInfo; - template > - struct BenchmarkStats; +namespace Catch { + namespace Benchmark { + template struct CATCH_DLL_PUBLIC SampleAnalysis { + std::vector samples; + Estimate mean; + Estimate standard_deviation; + OutlierClassification outliers; + double outlier_variance; - class IResultCapture { - public: - virtual ~IResultCapture(); + template + operator SampleAnalysis() const { + std::vector samples2; + samples2.reserve(samples.size()); + std::transform(samples.begin(), samples.end(), std::back_inserter(samples2), [](Duration d) { return Duration2(d); }); + return { + CATCH_MOVE(samples2), + mean, + standard_deviation, + outliers, + outlier_variance, + }; + } + }; + } // namespace Benchmark +} // namespace Catch - virtual bool sectionStarted( SectionInfo const& sectionInfo, - Counts& assertions ) = 0; - virtual void sectionEnded( SectionEndInfo const& endInfo ) = 0; - virtual void sectionEndedEarly( SectionEndInfo const& endInfo ) = 0; +#endif // CATCH_SAMPLE_ANALYSIS_HPP_INCLUDED - virtual auto acquireGeneratorTracker( StringRef generatorName, SourceLineInfo const& lineInfo ) -> IGeneratorTracker& = 0; - virtual void benchmarkPreparing( StringRef name ) = 0; - virtual void benchmarkStarting( BenchmarkInfo const& info ) = 0; - virtual void benchmarkEnded( BenchmarkStats<> const& stats ) = 0; - virtual void benchmarkFailed( StringRef error ) = 0; +// Adapted from donated nonius code. - virtual void pushScopedMessage( MessageInfo const& message ) = 0; - virtual void popScopedMessage( MessageInfo const& message ) = 0; +#ifndef CATCH_STATS_HPP_INCLUDED +#define CATCH_STATS_HPP_INCLUDED - virtual void emplaceUnscopedMessage( MessageBuilder const& builder ) = 0; +#include +#include +#include +#include +#include - virtual void handleFatalErrorCondition( StringRef message ) = 0; +namespace Catch { + namespace Benchmark { + namespace Detail { + using sample = std::vector; - virtual void handleExpr - ( AssertionInfo const& info, - ITransientExpression const& expr, - AssertionReaction& reaction ) = 0; - virtual void handleMessage - ( AssertionInfo const& info, - ResultWas::OfType resultType, - StringRef message, - AssertionReaction& reaction ) = 0; - virtual void handleUnexpectedExceptionNotThrown - ( AssertionInfo const& info, - AssertionReaction& reaction ) = 0; - virtual void handleUnexpectedInflightException - ( AssertionInfo const& info, - std::string const& message, - AssertionReaction& reaction ) = 0; - virtual void handleIncomplete - ( AssertionInfo const& info ) = 0; - virtual void handleNonExpr - ( AssertionInfo const &info, - ResultWas::OfType resultType, - AssertionReaction &reaction ) = 0; + CATCH_DLL_PUBLIC double + weighted_average_quantile( int k, + int q, + std::vector::iterator first, + std::vector::iterator last ); + template + OutlierClassification classify_outliers(Iterator first, Iterator last) { + std::vector 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.); - virtual bool lastAssertionPassed() = 0; - virtual void assertionPassed() = 0; + 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; + } - // Deprecated, do not use: - virtual std::string getCurrentTestName() const = 0; - virtual const AssertionResult* getLastResult() const = 0; - virtual void exceptionEarlyReported() = 0; - }; - - IResultCapture& getResultCapture(); -} + template + double mean(Iterator first, Iterator last) { + auto count = last - first; + double sum = std::accumulate(first, last, 0.); + return sum / count; + } -#endif // CATCH_INTERFACES_CAPTURE_HPP_INCLUDED + template + sample jackknife(Estimator&& estimator, Iterator first, Iterator last) { + auto n = static_cast(last - first); + auto second = first; + ++second; + sample results; + results.reserve(n); -#include + for (auto it = first; it != last; ++it) { + std::iter_swap(it, first); + results.push_back(estimator(second, last)); + } -namespace Catch { + return results; + } - struct MessageInfo { - MessageInfo( StringRef _macroName, - SourceLineInfo const& _lineInfo, - ResultWas::OfType _type ); + inline double normal_cdf(double x) { + return std::erfc(-x / std::sqrt(2.0)) / 2.0; + } - StringRef macroName; - std::string message; - SourceLineInfo lineInfo; - ResultWas::OfType type; - unsigned int sequence; + CATCH_DLL_PUBLIC double erfc_inv( double x ); - bool operator == (MessageInfo const& other) const { - return sequence == other.sequence; - } - bool operator < (MessageInfo const& other) const { - return sequence < other.sequence; - } - private: - static unsigned int globalCount; - }; + CATCH_DLL_PUBLIC double normal_quantile( double p ); -} // end namespace Catch + template + Estimate bootstrap(double confidence_level, Iterator first, Iterator last, sample const& resample, Estimator&& estimator) { + auto n_samples = last - first; -#endif // CATCH_MESSAGE_INFO_HPP_INCLUDED + 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 sqcb, double x) -> std::pair { + auto d = jack_mean - x; + auto d2 = d * d; + auto d3 = d2 * d; + return { sqcb.first + d2, sqcb.second + d3 }; + }); -#ifndef CATCH_UNIQUE_PTR_HPP_INCLUDED -#define CATCH_UNIQUE_PTR_HPP_INCLUDED + double accel = sum_cubes / (6 * std::pow(sum_squares, 1.5)); + int n = static_cast(resample.size()); + double prob_n = std::count_if(resample.begin(), resample.end(), [point](double x) { return x < point; }) / static_cast(n); + // degenerate case with uniform samples + if (prob_n == 0) return { point, point, point, confidence_level }; -#include -#include + 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 = static_cast((std::max)(cumn(a1), 0)); + auto hi = static_cast((std::min)(cumn(a2), n - 1)); -namespace Catch { -namespace Detail { - /** - * A reimplementation of `std::unique_ptr` for improved compilation performance - * - * Does not support arrays nor custom deleters. - */ - template - class unique_ptr { - T* m_ptr; - public: - constexpr unique_ptr(std::nullptr_t = nullptr): - m_ptr{} - {} - explicit constexpr unique_ptr(T* ptr): - m_ptr(ptr) - {} + return { point, resample[lo], resample[hi], confidence_level }; + } - template ::value>> - unique_ptr(unique_ptr&& from): - m_ptr(from.release()) - {} + double outlier_variance(Estimate mean, Estimate stddev, int n); - template ::value>> - unique_ptr& operator=(unique_ptr&& from) { - reset(from.release()); + struct bootstrap_analysis { + Estimate mean; + Estimate standard_deviation; + double outlier_variance; + }; - return *this; - } + CATCH_DLL_PUBLIC bootstrap_analysis + analyse_samples( double confidence_level, + unsigned int n_resamples, + std::vector::iterator first, + std::vector::iterator last ); + } // namespace Detail + } // namespace Benchmark +} // namespace Catch - unique_ptr(unique_ptr const&) = delete; - unique_ptr& operator=(unique_ptr const&) = delete; +#endif // CATCH_STATS_HPP_INCLUDED - unique_ptr(unique_ptr&& rhs) noexcept: - m_ptr(rhs.m_ptr) { - rhs.m_ptr = nullptr; - } - unique_ptr& operator=(unique_ptr&& rhs) noexcept { - reset(rhs.release()); +#include +#include +#include - return *this; - } +namespace Catch { + namespace Benchmark { + namespace Detail { + template + SampleAnalysis analyse(const IConfig &cfg, Environment, Iterator first, Iterator last) { + if (!cfg.benchmarkNoAnalysis()) { + std::vector samples; + samples.reserve(static_cast(last - first)); + std::transform(first, last, std::back_inserter(samples), [](Duration d) { return d.count(); }); - ~unique_ptr() { - delete m_ptr; - } + 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()); - T& operator*() { - assert(m_ptr); - return *m_ptr; - } - T const& operator*() const { - assert(m_ptr); - return *m_ptr; - } - T* operator->() noexcept { - assert(m_ptr); - return m_ptr; - } - T const* operator->() const noexcept { - assert(m_ptr); - return m_ptr; - } + auto wrap_estimate = [](Estimate e) { + return Estimate { + Duration(e.point), + Duration(e.lower_bound), + Duration(e.upper_bound), + e.confidence_interval, + }; + }; + std::vector samples2; + samples2.reserve(samples.size()); + std::transform(samples.begin(), samples.end(), std::back_inserter(samples2), [](double d) { return Duration(d); }); + return { + CATCH_MOVE(samples2), + wrap_estimate(analysis.mean), + wrap_estimate(analysis.standard_deviation), + outliers, + analysis.outlier_variance, + }; + } else { + std::vector samples; + samples.reserve(static_cast(last - first)); - T* get() { return m_ptr; } - T const* get() const { return m_ptr; } + 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; - void reset(T* ptr = nullptr) { - delete m_ptr; - m_ptr = ptr; - } + return { + CATCH_MOVE(samples), + Estimate{mean, mean, mean, 0.0}, + Estimate{Duration(0), Duration(0), Duration(0), 0.0}, + OutlierClassification{}, + 0.0 + }; + } + } + } // namespace Detail + } // namespace Benchmark +} // namespace Catch - T* release() { - auto temp = m_ptr; - m_ptr = nullptr; - return temp; - } +#endif // CATCH_ANALYSE_HPP_INCLUDED - explicit operator bool() const { - return m_ptr; - } - friend void swap(unique_ptr& lhs, unique_ptr& rhs) { - auto temp = lhs.m_ptr; - lhs.m_ptr = rhs.m_ptr; - rhs.m_ptr = temp; - } - }; +// Adapted from donated nonius code. - //! Specialization to cause compile-time error for arrays - template - class unique_ptr; +#ifndef CATCH_ESTIMATE_CLOCK_HPP_INCLUDED +#define CATCH_ESTIMATE_CLOCK_HPP_INCLUDED - template - unique_ptr make_unique(Args&&... args) { - return unique_ptr(new T(CATCH_FORWARD(args)...)); - } +#include +#include +#include +#include -} // end namespace Detail -} // end namespace Catch +namespace Catch { + namespace Benchmark { + namespace Detail { + template + std::vector resolution(int k) { + std::vector> times; + times.reserve(static_cast(k + 1)); + std::generate_n(std::back_inserter(times), k + 1, now{}); -#endif // CATCH_UNIQUE_PTR_HPP_INCLUDED + std::vector deltas; + deltas.reserve(static_cast(k)); + std::transform(std::next(times.begin()), times.end(), times.begin(), + std::back_inserter(deltas), + [](TimePoint a, TimePoint b) { return static_cast((a - b).count()); }); + return deltas; + } -// Adapted from donated nonius code. + 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; -#ifndef CATCH_ESTIMATE_HPP_INCLUDED -#define CATCH_ESTIMATE_HPP_INCLUDED + template + int warmup() { + return run_for_at_least(std::chrono::duration_cast>(warmup_time), warmup_seed, &resolution) + .iterations; + } + template + EnvironmentEstimate> estimate_clock_resolution(int iterations) { + auto r = run_for_at_least(std::chrono::duration_cast>(clock_resolution_estimation_time), iterations, &resolution) + .result; + return { + FloatDuration(mean(r.begin(), r.end())), + classify_outliers(r.begin(), r.end()), + }; + } + template + EnvironmentEstimate> estimate_clock_cost(FloatDuration resolution) { + auto time_limit = (std::min)( + resolution * clock_cost_estimation_tick_limit, + FloatDuration(clock_cost_estimation_time_limit)); + auto time_clock = [](int k) { + return Detail::measure([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(std::chrono::duration_cast>(clock_cost_estimation_time), iters, time_clock); + std::vector times; + int nsamples = static_cast(std::ceil(time_limit / r.elapsed)); + times.reserve(static_cast(nsamples)); + std::generate_n(std::back_inserter(times), nsamples, [time_clock, &r] { + return static_cast((time_clock(r.iterations) / r.iterations).count()); + }); + return { + FloatDuration(mean(times.begin(), times.end())), + classify_outliers(times.begin(), times.end()), + }; + } -namespace Catch { - namespace Benchmark { - template - struct Estimate { - Duration point; - Duration lower_bound; - Duration upper_bound; - double confidence_interval; + template + Environment> measure_environment() { +#if defined(__clang__) +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wexit-time-destructors" +#endif + static Catch::Detail::unique_ptr>> env; +#if defined(__clang__) +# pragma clang diagnostic pop +#endif + if (env) { + return *env; + } - template - operator Estimate() const { - return { point, lower_bound, upper_bound, confidence_interval }; + auto iters = Detail::warmup(); + auto resolution = Detail::estimate_clock_resolution(iters); + auto cost = Detail::estimate_clock_cost(resolution.mean); + + env = Catch::Detail::make_unique>>( Environment>{resolution, cost} ); + return *env; } - }; + } // namespace Detail } // namespace Benchmark } // namespace Catch -#endif // CATCH_ESTIMATE_HPP_INCLUDED +#endif // CATCH_ESTIMATE_CLOCK_HPP_INCLUDED -// Adapted from donated nonius code. +#ifndef CATCH_INTERFACES_REPORTER_HPP_INCLUDED +#define CATCH_INTERFACES_REPORTER_HPP_INCLUDED -#ifndef CATCH_OUTLIER_CLASSIFICATION_HPP_INCLUDED -#define CATCH_OUTLIER_CLASSIFICATION_HPP_INCLUDED -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 +#ifndef CATCH_ASSERTION_RESULT_HPP_INCLUDED +#define CATCH_ASSERTION_RESULT_HPP_INCLUDED -#endif // CATCH_OUTLIERS_CLASSIFICATION_HPP_INCLUDED -#include -#include -#include +#ifndef CATCH_ASSERTION_INFO_HPP_INCLUDED +#define CATCH_ASSERTION_INFO_HPP_INCLUDED + + + +#ifndef CATCH_SOURCE_LINE_INFO_HPP_INCLUDED +#define CATCH_SOURCE_LINE_INFO_HPP_INCLUDED + +#include #include namespace Catch { - struct ReporterDescription; - struct TagInfo; - struct TestCaseInfo; - class TestCaseHandle; - class IConfig; - class IStream; - enum class ColourMode : std::uint8_t; - - struct ReporterConfig { - ReporterConfig( IConfig const* _fullConfig, - Detail::unique_ptr _stream, - ColourMode colourMode, - std::map customOptions ); + struct CATCH_DLL_PUBLIC SourceLineInfo { - ReporterConfig( ReporterConfig&& ) = default; - ReporterConfig& operator=( ReporterConfig&& ) = default; - ~ReporterConfig(); // = default + SourceLineInfo() = delete; + constexpr SourceLineInfo( char const* _file, std::size_t _line ) noexcept: + file( _file ), + line( _line ) + {} - Detail::unique_ptr takeStream() &&; - IConfig const* fullConfig() const; - ColourMode colourMode() const; - std::map const& customOptions() const; + bool operator == ( SourceLineInfo const& other ) const noexcept; + bool operator < ( SourceLineInfo const& other ) const noexcept; - private: - Detail::unique_ptr m_stream; - IConfig const* m_fullConfig; - ColourMode m_colourMode; - std::map m_customOptions; - }; + char const* file; + std::size_t line; - struct TestRunInfo { - constexpr TestRunInfo(StringRef _name) : name(_name) {} - StringRef name; + CATCH_DLL_PUBLIC friend std::ostream& + operator<<( std::ostream& os, SourceLineInfo const& info ); }; +} - struct AssertionStats { - AssertionStats( AssertionResult const& _assertionResult, - std::vector const& _infoMessages, - Totals const& _totals ); +#define CATCH_INTERNAL_LINEINFO \ + ::Catch::SourceLineInfo( __FILE__, static_cast( __LINE__ ) ) - AssertionStats( AssertionStats const& ) = default; - AssertionStats( AssertionStats && ) = default; - AssertionStats& operator = ( AssertionStats const& ) = delete; - AssertionStats& operator = ( AssertionStats && ) = delete; +#endif // CATCH_SOURCE_LINE_INFO_HPP_INCLUDED - AssertionResult assertionResult; - std::vector infoMessages; - Totals totals; - }; +namespace Catch { - struct SectionStats { - SectionStats( SectionInfo const& _sectionInfo, - Counts const& _assertions, - double _durationInSeconds, - bool _missingAssertions ); + struct CATCH_DLL_PUBLIC AssertionInfo { + // AssertionInfo() = delete; - SectionInfo sectionInfo; - Counts assertions; - double durationInSeconds; - bool missingAssertions; + StringRef macroName; + SourceLineInfo lineInfo; + StringRef capturedExpression; + ResultDisposition::Flags resultDisposition; }; - struct TestCaseStats { - TestCaseStats( TestCaseInfo const& _testInfo, - Totals const& _totals, - std::string const& _stdOut, - std::string const& _stdErr, - bool _aborting ); +} // end namespace Catch - TestCaseInfo const * testInfo; - Totals totals; - std::string stdOut; - std::string stdErr; - bool aborting; - }; +#endif // CATCH_ASSERTION_INFO_HPP_INCLUDED - struct TestRunStats { - TestRunStats( TestRunInfo const& _runInfo, - Totals const& _totals, - bool _aborting ); - TestRunInfo runInfo; - Totals totals; - bool aborting; - }; +#ifndef CATCH_LAZY_EXPR_HPP_INCLUDED +#define CATCH_LAZY_EXPR_HPP_INCLUDED +#include - struct BenchmarkInfo { - std::string name; - double estimatedDuration; - int iterations; - unsigned int samples; - unsigned int resamples; - double clockResolution; - double clockCost; - }; +namespace Catch { - template - struct BenchmarkStats { - BenchmarkInfo info; + class ITransientExpression; - std::vector samples; - Benchmark::Estimate mean; - Benchmark::Estimate standardDeviation; - Benchmark::OutlierClassification outliers; - double outlierVariance; + class CATCH_DLL_PUBLIC LazyExpression { + friend class AssertionHandler; + friend struct AssertionStats; + friend class RunContext; - template - operator BenchmarkStats() const { - std::vector samples2; - samples2.reserve(samples.size()); - for (auto const& sample : samples) { - samples2.push_back(Duration2(sample)); - } - return { - info, - CATCH_MOVE(samples2), - mean, - standardDeviation, - outliers, - outlierVariance, - }; + ITransientExpression const* m_transientExpression = nullptr; + bool m_isNegated; + public: + LazyExpression( bool isNegated ): + m_isNegated(isNegated) + {} + LazyExpression(LazyExpression const& other) = default; + LazyExpression& operator = ( LazyExpression const& ) = delete; + + explicit operator bool() const { + return m_transientExpression != nullptr; } + + CATCH_DLL_PUBLIC friend auto + operator<<( std::ostream& os, LazyExpression const& lazyExpr ) + -> std::ostream&; }; - //! By setting up its preferences, a reporter can modify Catch2's behaviour - //! in some regards, e.g. it can request Catch2 to capture writes to - //! stdout/stderr during test execution, and pass them to the reporter. - struct ReporterPreferences { - //! Catch2 should redirect writes to stdout and pass them to the - //! reporter - bool shouldRedirectStdOut = false; - //! Catch2 should call `Reporter::assertionEnded` even for passing - //! assertions - bool shouldReportAllAssertions = false; - }; - - /** - * The common base for all reporters and event listeners - * - * Implementing classes must also implement: - * - * //! User-friendly description of the reporter/listener type - * static std::string getDescription() - * - * Generally shouldn't be derived from by users of Catch2 directly, - * instead they should derive from one of the utility bases that - * derive from this class. - */ - class IEventListener { - protected: - //! Derived classes can set up their preferences here - ReporterPreferences m_preferences; - //! The test run's config as filled in from CLI and defaults - IConfig const* m_config; - - public: - IEventListener( IConfig const* config ): m_config( config ) {} - - virtual ~IEventListener(); // = default; - - // Implementing class must also provide the following static methods: - // static std::string getDescription(); - - ReporterPreferences const& getPreferences() const { - return m_preferences; - } - - //! Called when no test cases match provided test spec - virtual void noMatchingTestCases( StringRef unmatchedSpec ) = 0; - //! Called for all invalid test specs from the cli - virtual void reportInvalidTestSpec( StringRef invalidArgument ) = 0; - - /** - * Called once in a testing run before tests are started - * - * Not called if tests won't be run (e.g. only listing will happen) - */ - virtual void testRunStarting( TestRunInfo const& testRunInfo ) = 0; +} // namespace Catch - //! Called _once_ for each TEST_CASE, no matter how many times it is entered - virtual void testCaseStarting( TestCaseInfo const& testInfo ) = 0; - //! Called _every time_ a TEST_CASE is entered, including repeats (due to sections) - virtual void testCasePartialStarting( TestCaseInfo const& testInfo, uint64_t partNumber ) = 0; - //! Called when a `SECTION` is being entered. Not called for skipped sections - virtual void sectionStarting( SectionInfo const& sectionInfo ) = 0; +#endif // CATCH_LAZY_EXPR_HPP_INCLUDED +#include - //! Called when user-code is being probed before the actual benchmark runs - virtual void benchmarkPreparing( StringRef benchmarkName ) = 0; - //! Called after probe but before the user-code is being benchmarked - virtual void benchmarkStarting( BenchmarkInfo const& benchmarkInfo ) = 0; - //! Called with the benchmark results if benchmark successfully finishes - virtual void benchmarkEnded( BenchmarkStats<> const& benchmarkStats ) = 0; - //! Called if running the benchmarks fails for any reason - virtual void benchmarkFailed( StringRef benchmarkName ) = 0; +namespace Catch { - //! Called before assertion success/failure is evaluated - virtual void assertionStarting( AssertionInfo const& assertionInfo ) = 0; + struct CATCH_DLL_PUBLIC AssertionResultData { + AssertionResultData() = delete; - //! Called after assertion was fully evaluated - virtual void assertionEnded( AssertionStats const& assertionStats ) = 0; + AssertionResultData( ResultWas::OfType _resultType, LazyExpression const& _lazyExpression ); - //! Called after a `SECTION` has finished running - virtual void sectionEnded( SectionStats const& sectionStats ) = 0; - //! Called _every time_ a TEST_CASE is entered, including repeats (due to sections) - virtual void testCasePartialEnded(TestCaseStats const& testCaseStats, uint64_t partNumber ) = 0; - //! Called _once_ for each TEST_CASE, no matter how many times it is entered - virtual void testCaseEnded( TestCaseStats const& testCaseStats ) = 0; - /** - * Called once after all tests in a testing run are finished - * - * Not called if tests weren't run (e.g. only listings happened) - */ - virtual void testRunEnded( TestRunStats const& testRunStats ) = 0; + std::string message; + mutable std::string reconstructedExpression; + LazyExpression lazyExpression; + ResultWas::OfType resultType; - //! Called with test cases that are skipped due to the test run aborting - virtual void skipTest( TestCaseInfo const& testInfo ) = 0; + std::string reconstructExpression() const; + }; - //! Called if a fatal error (signal/structured exception) occured - virtual void fatalErrorEncountered( StringRef error ) = 0; + class CATCH_DLL_PUBLIC AssertionResult { + public: + AssertionResult() = delete; + AssertionResult( AssertionInfo const& info, AssertionResultData const& data ); - //! Writes out information about provided reporters using reporter-specific format - virtual void listReporters(std::vector const& descriptions) = 0; - //! Writes out information about provided tests using reporter-specific format - virtual void listTests(std::vector const& tests) = 0; - //! Writes out information about the provided tags using reporter-specific format - virtual void listTags(std::vector const& tags) = 0; + bool isOk() const; + bool succeeded() const; + ResultWas::OfType getResultType() const; + bool hasExpression() const; + bool hasMessage() const; + std::string getExpression() const; + std::string getExpressionInMacro() const; + bool hasExpandedExpression() const; + std::string getExpandedExpression() const; + StringRef getMessage() const; + SourceLineInfo getSourceInfo() const; + StringRef getTestMacroName() const; + //protected: + AssertionInfo m_info; + AssertionResultData m_resultData; }; - using IEventListenerPtr = Detail::unique_ptr; } // end namespace Catch -#endif // CATCH_INTERFACES_REPORTER_HPP_INCLUDED +#endif // CATCH_ASSERTION_RESULT_HPP_INCLUDED -#ifndef CATCH_UNIQUE_NAME_HPP_INCLUDED -#define CATCH_UNIQUE_NAME_HPP_INCLUDED +#ifndef CATCH_SECTION_INFO_HPP_INCLUDED +#define CATCH_SECTION_INFO_HPP_INCLUDED +#ifndef CATCH_TOTALS_HPP_INCLUDED +#define CATCH_TOTALS_HPP_INCLUDED -/** \file - * Wrapper for the CONFIG configuration option - * - * When generating internal unique names, there are two options. Either - * we mix in the current line number, or mix in an incrementing number. - * We prefer the latter, using `__COUNTER__`, but users might want to - * use the former. - */ +#include -#ifndef CATCH_CONFIG_COUNTER_HPP_INCLUDED -#define CATCH_CONFIG_COUNTER_HPP_INCLUDED +namespace Catch { -#if ( !defined(__JETBRAINS_IDE__) || __JETBRAINS_IDE__ >= 20170300L ) - #define CATCH_INTERNAL_CONFIG_COUNTER -#endif + struct CATCH_DLL_PUBLIC Counts { + Counts operator - ( Counts const& other ) const; + Counts& operator += ( Counts const& other ); -#if defined( CATCH_INTERNAL_CONFIG_COUNTER ) && \ - !defined( CATCH_CONFIG_NO_COUNTER ) && \ - !defined( CATCH_CONFIG_COUNTER ) -# define CATCH_CONFIG_COUNTER -#endif + std::uint64_t total() const; + bool allPassed() const; + bool allOk() const; + std::uint64_t passed = 0; + std::uint64_t failed = 0; + std::uint64_t failedButOk = 0; + }; -#endif // CATCH_CONFIG_COUNTER_HPP_INCLUDED -#define INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) name##line -#define INTERNAL_CATCH_UNIQUE_NAME_LINE( name, line ) INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) -#ifdef CATCH_CONFIG_COUNTER -# define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __COUNTER__ ) -#else -# define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __LINE__ ) -#endif + struct CATCH_DLL_PUBLIC Totals { -#endif // CATCH_UNIQUE_NAME_HPP_INCLUDED + Totals operator - ( Totals const& other ) const; + Totals& operator += ( Totals const& other ); + Totals delta( Totals const& prevTotals ) const; -// Adapted from donated nonius code. + Counts assertions; + Counts testCases; + }; +} -#ifndef CATCH_CHRONOMETER_HPP_INCLUDED -#define CATCH_CHRONOMETER_HPP_INCLUDED +#endif // CATCH_TOTALS_HPP_INCLUDED +#include +namespace Catch { + struct CATCH_DLL_PUBLIC SectionInfo { + // The last argument is ignored, so that people can write + // SECTION("ShortName", "Proper description that is long") and + // still use the `-c` flag comfortably. + SectionInfo( SourceLineInfo const& _lineInfo, std::string _name, + const char* const = nullptr ): + name(CATCH_MOVE(_name)), + lineInfo(_lineInfo) + {} -// Adapted from donated nonius code. + std::string name; + SourceLineInfo lineInfo; + }; -#ifndef CATCH_CLOCK_HPP_INCLUDED -#define CATCH_CLOCK_HPP_INCLUDED + struct CATCH_DLL_PUBLIC SectionEndInfo { + SectionInfo sectionInfo; + Counts prevAssertions; + double durationInSeconds; + }; -#include -#include +} // end namespace Catch -namespace Catch { - namespace Benchmark { - template - using ClockDuration = typename Clock::duration; - template - using FloatDuration = std::chrono::duration; +#endif // CATCH_SECTION_INFO_HPP_INCLUDED - template - using TimePoint = typename Clock::time_point; - using default_clock = std::chrono::steady_clock; +#ifndef CATCH_MESSAGE_INFO_HPP_INCLUDED +#define CATCH_MESSAGE_INFO_HPP_INCLUDED - template - struct now { - TimePoint operator()() const { - return Clock::now(); - } - }; +#include - using fp_seconds = std::chrono::duration>; - } // namespace Benchmark -} // namespace Catch +namespace Catch { -#endif // CATCH_CLOCK_HPP_INCLUDED + struct CATCH_DLL_PUBLIC MessageInfo { + MessageInfo( StringRef _macroName, + SourceLineInfo const& _lineInfo, + ResultWas::OfType _type ); + StringRef macroName; + std::string message; + SourceLineInfo lineInfo; + ResultWas::OfType type; + unsigned int sequence; -// Adapted from donated nonius code. + bool operator == (MessageInfo const& other) const { + return sequence == other.sequence; + } + bool operator < (MessageInfo const& other) const { + return sequence < other.sequence; + } + private: + static unsigned int globalCount; + }; -#ifndef CATCH_OPTIMIZER_HPP_INCLUDED -#define CATCH_OPTIMIZER_HPP_INCLUDED +} // end namespace Catch -#if defined(_MSC_VER) -# include // atomic_thread_fence -#endif +#endif // CATCH_MESSAGE_INFO_HPP_INCLUDED +#include -#include +#include +#include +#include namespace Catch { - namespace Benchmark { -#if defined(__GNUC__) || defined(__clang__) - template - 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 - inline void keep_memory(T* p) { - // thanks @milleniumbug - *reinterpret_cast(p) = *reinterpret_cast(p); - } - // TODO equivalent keep_memory() -#pragma optimize("", on) + struct ReporterDescription; + struct TagInfo; + struct TestCaseInfo; + class TestCaseHandle; + class IConfig; + class IStream; + enum class ColourMode : std::uint8_t; - namespace Detail { - inline void optimizer_barrier() { - std::atomic_thread_fence(std::memory_order_seq_cst); - } - } // namespace Detail + struct CATCH_DLL_PUBLIC ReporterConfig { + ReporterConfig( IConfig const* _fullConfig, + Detail::unique_ptr _stream, + ColourMode colourMode, + std::map customOptions ); -#endif + ReporterConfig( ReporterConfig&& ) = default; + ReporterConfig& operator=( ReporterConfig&& ) = default; + ~ReporterConfig(); // = default - template - inline void deoptimize_value(T&& x) { - keep_memory(&x); - } + Detail::unique_ptr takeStream() &&; + IConfig const* fullConfig() const; + ColourMode colourMode() const; + std::map const& customOptions() const; - template - inline auto invoke_deoptimized(Fn&& fn, Args&&... args) -> std::enable_if_t::value> { - deoptimize_value(CATCH_FORWARD(fn) (CATCH_FORWARD(args)...)); - } + private: + Detail::unique_ptr m_stream; + IConfig const* m_fullConfig; + ColourMode m_colourMode; + std::map m_customOptions; + }; - template - inline auto invoke_deoptimized(Fn&& fn, Args&&... args) -> std::enable_if_t::value> { - CATCH_FORWARD(fn) (CATCH_FORWARD(args)...); - } - } // namespace Benchmark -} // namespace Catch + struct CATCH_DLL_PUBLIC TestRunInfo { + constexpr TestRunInfo(StringRef _name) : name(_name) {} + StringRef name; + }; -#endif // CATCH_OPTIMIZER_HPP_INCLUDED + struct CATCH_DLL_PUBLIC AssertionStats { + AssertionStats( AssertionResult const& _assertionResult, + std::vector const& _infoMessages, + Totals const& _totals ); + AssertionStats( AssertionStats const& ) = default; + AssertionStats( AssertionStats && ) = default; + AssertionStats& operator = ( AssertionStats const& ) = delete; + AssertionStats& operator = ( AssertionStats && ) = delete; -// Adapted from donated nonius code. + AssertionResult assertionResult; + std::vector infoMessages; + Totals totals; + }; -#ifndef CATCH_COMPLETE_INVOKE_HPP_INCLUDED -#define CATCH_COMPLETE_INVOKE_HPP_INCLUDED + struct CATCH_DLL_PUBLIC SectionStats { + SectionStats( SectionInfo const& _sectionInfo, + Counts const& _assertions, + double _durationInSeconds, + bool _missingAssertions ); + SectionInfo sectionInfo; + Counts assertions; + double durationInSeconds; + bool missingAssertions; + }; + struct CATCH_DLL_PUBLIC TestCaseStats { + TestCaseStats( TestCaseInfo const& _testInfo, + Totals const& _totals, + std::string const& _stdOut, + std::string const& _stdErr, + bool _aborting ); -#ifndef CATCH_TEST_FAILURE_EXCEPTION_HPP_INCLUDED -#define CATCH_TEST_FAILURE_EXCEPTION_HPP_INCLUDED + TestCaseInfo const * testInfo; + Totals totals; + std::string stdOut; + std::string stdErr; + bool aborting; + }; -namespace Catch { + struct CATCH_DLL_PUBLIC TestRunStats { + TestRunStats( TestRunInfo const& _runInfo, + Totals const& _totals, + bool _aborting ); - //! Used to signal that an assertion macro failed - struct TestFailureException{}; + TestRunInfo runInfo; + Totals totals; + bool aborting; + }; -} // namespace Catch + struct CATCH_DLL_PUBLIC BenchmarkInfo { + std::string name; + double estimatedDuration; + int iterations; + unsigned int samples; + unsigned int resamples; + double clockResolution; + double clockCost; + }; -#endif // CATCH_TEST_FAILURE_EXCEPTION_HPP_INCLUDED + template struct CATCH_DLL_PUBLIC BenchmarkStats { + BenchmarkInfo info; + std::vector samples; + Benchmark::Estimate mean; + Benchmark::Estimate standardDeviation; + Benchmark::OutlierClassification outliers; + double outlierVariance; -#ifndef CATCH_META_HPP_INCLUDED -#define CATCH_META_HPP_INCLUDED + template + operator BenchmarkStats() const { + std::vector samples2; + samples2.reserve(samples.size()); + for (auto const& sample : samples) { + samples2.push_back(Duration2(sample)); + } + return { + info, + CATCH_MOVE(samples2), + mean, + standardDeviation, + outliers, + outlierVariance, + }; + } + }; -#include + //! By setting up its preferences, a reporter can modify Catch2's behaviour + //! in some regards, e.g. it can request Catch2 to capture writes to + //! stdout/stderr during test execution, and pass them to the reporter. + struct CATCH_DLL_PUBLIC ReporterPreferences { + //! Catch2 should redirect writes to stdout and pass them to the + //! reporter + bool shouldRedirectStdOut = false; + //! Catch2 should call `Reporter::assertionEnded` even for passing + //! assertions + bool shouldReportAllAssertions = false; + }; -namespace Catch { - template - struct always_false : std::false_type {}; + /** + * The common base for all reporters and event listeners + * + * Implementing classes must also implement: + * + * //! User-friendly description of the reporter/listener type + * static std::string getDescription() + * + * Generally shouldn't be derived from by users of Catch2 directly, + * instead they should derive from one of the utility bases that + * derive from this class. + */ + class CATCH_DLL_PUBLIC IEventListener { + protected: + //! Derived classes can set up their preferences here + ReporterPreferences m_preferences; + //! The test run's config as filled in from CLI and defaults + IConfig const* m_config; - template struct true_given : std::true_type {}; - struct is_callable_tester { - template - true_given()(std::declval()...))> static test(int); - template - std::false_type static test(...); - }; + public: + IEventListener( IConfig const* config ): m_config( config ) {} - template - struct is_callable; + virtual ~IEventListener(); // = default; - template - struct is_callable : decltype(is_callable_tester::test(0)) {}; + // Implementing class must also provide the following static methods: + // static std::string getDescription(); + ReporterPreferences const& getPreferences() const { + return m_preferences; + } -#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 - using FunctionReturnType = std::remove_reference_t>>; -#else - template - using FunctionReturnType = std::remove_reference_t>>; -#endif + //! Called when no test cases match provided test spec + virtual void noMatchingTestCases( StringRef unmatchedSpec ) = 0; + //! Called for all invalid test specs from the cli + virtual void reportInvalidTestSpec( StringRef invalidArgument ) = 0; -} // namespace Catch + /** + * Called once in a testing run before tests are started + * + * Not called if tests won't be run (e.g. only listing will happen) + */ + virtual void testRunStarting( TestRunInfo const& testRunInfo ) = 0; -namespace mpl_{ - struct na; -} + //! Called _once_ for each TEST_CASE, no matter how many times it is entered + virtual void testCaseStarting( TestCaseInfo const& testInfo ) = 0; + //! Called _every time_ a TEST_CASE is entered, including repeats (due to sections) + virtual void testCasePartialStarting( TestCaseInfo const& testInfo, uint64_t partNumber ) = 0; + //! Called when a `SECTION` is being entered. Not called for skipped sections + virtual void sectionStarting( SectionInfo const& sectionInfo ) = 0; -#endif // CATCH_META_HPP_INCLUDED + //! Called when user-code is being probed before the actual benchmark runs + virtual void benchmarkPreparing( StringRef benchmarkName ) = 0; + //! Called after probe but before the user-code is being benchmarked + virtual void benchmarkStarting( BenchmarkInfo const& benchmarkInfo ) = 0; + //! Called with the benchmark results if benchmark successfully finishes + virtual void benchmarkEnded( BenchmarkStats<> const& benchmarkStats ) = 0; + //! Called if running the benchmarks fails for any reason + virtual void benchmarkFailed( StringRef benchmarkName ) = 0; + //! Called before assertion success/failure is evaluated + virtual void assertionStarting( AssertionInfo const& assertionInfo ) = 0; -#ifndef CATCH_INTERFACES_REGISTRY_HUB_HPP_INCLUDED -#define CATCH_INTERFACES_REGISTRY_HUB_HPP_INCLUDED + //! Called after assertion was fully evaluated + virtual void assertionEnded( AssertionStats const& assertionStats ) = 0; + //! Called after a `SECTION` has finished running + virtual void sectionEnded( SectionStats const& sectionStats ) = 0; + //! Called _every time_ a TEST_CASE is entered, including repeats (due to sections) + virtual void testCasePartialEnded(TestCaseStats const& testCaseStats, uint64_t partNumber ) = 0; + //! Called _once_ for each TEST_CASE, no matter how many times it is entered + virtual void testCaseEnded( TestCaseStats const& testCaseStats ) = 0; + /** + * Called once after all tests in a testing run are finished + * + * Not called if tests weren't run (e.g. only listings happened) + */ + virtual void testRunEnded( TestRunStats const& testRunStats ) = 0; -#include + //! Called with test cases that are skipped due to the test run aborting + virtual void skipTest( TestCaseInfo const& testInfo ) = 0; -namespace Catch { + //! Called if a fatal error (signal/structured exception) occured + virtual void fatalErrorEncountered( StringRef error ) = 0; - class TestCaseHandle; - struct TestCaseInfo; - class ITestCaseRegistry; - class IExceptionTranslatorRegistry; - class IExceptionTranslator; - class IReporterRegistry; - class IReporterFactory; - class ITagAliasRegistry; - class ITestInvoker; - class IMutableEnumValuesRegistry; - struct SourceLineInfo; - - class StartupExceptionRegistry; - class EventListenerFactory; + //! Writes out information about provided reporters using reporter-specific format + virtual void listReporters(std::vector const& descriptions) = 0; + //! Writes out information about provided tests using reporter-specific format + virtual void listTests(std::vector const& tests) = 0; + //! Writes out information about the provided tags using reporter-specific format + virtual void listTags(std::vector const& tags) = 0; + }; + using IEventListenerPtr = Detail::unique_ptr; - using IReporterFactoryPtr = Detail::unique_ptr; +} // end namespace Catch - class IRegistryHub { - public: - virtual ~IRegistryHub(); // = default +#endif // CATCH_INTERFACES_REPORTER_HPP_INCLUDED - virtual IReporterRegistry const& getReporterRegistry() const = 0; - virtual ITestCaseRegistry const& getTestCaseRegistry() const = 0; - virtual ITagAliasRegistry const& getTagAliasRegistry() const = 0; - virtual IExceptionTranslatorRegistry const& getExceptionTranslatorRegistry() const = 0; +#ifndef CATCH_COMPILER_CAPABILITIES_HPP_INCLUDED +#define CATCH_COMPILER_CAPABILITIES_HPP_INCLUDED - virtual StartupExceptionRegistry const& getStartupExceptionRegistry() const = 0; - }; +// Detect a number of compiler features - by compiler +// The following features are defined: +// +// CATCH_CONFIG_WINDOWS_SEH : is Windows SEH supported? +// CATCH_CONFIG_POSIX_SIGNALS : are POSIX signals supported? +// CATCH_CONFIG_DISABLE_EXCEPTIONS : Are exceptions enabled? +// **************** +// Note to maintainers: if new toggles are added please document them +// in configuration.md, too +// **************** - class IMutableRegistryHub { - public: - virtual ~IMutableRegistryHub(); // = default - virtual void registerReporter( std::string const& name, IReporterFactoryPtr factory ) = 0; - virtual void registerListener( Detail::unique_ptr factory ) = 0; - virtual void registerTest(Detail::unique_ptr&& testInfo, Detail::unique_ptr&& invoker) = 0; - virtual void registerTranslator( Detail::unique_ptr&& 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; - }; +// In general each macro has a _NO_ form +// (e.g. CATCH_CONFIG_NO_POSIX_SIGNALS) which disables the feature. +// Many features, at point of detection, define an _INTERNAL_ macro, so they +// can be combined, en-mass, with the _NO_ forms later. - IRegistryHub const& getRegistryHub(); - IMutableRegistryHub& getMutableRegistryHub(); - void cleanUp(); - std::string translateActiveException(); -} -#endif // CATCH_INTERFACES_REGISTRY_HUB_HPP_INCLUDED +#ifndef CATCH_PLATFORM_HPP_INCLUDED +#define CATCH_PLATFORM_HPP_INCLUDED -#include +// See e.g.: +// https://opensource.apple.com/source/CarbonHeaders/CarbonHeaders-18.1/TargetConditionals.h.auto.html +#ifdef __APPLE__ +# include +# 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 -namespace Catch { - namespace Benchmark { - namespace Detail { - template - struct CompleteType { using type = T; }; - template <> - struct CompleteType { struct type {}; }; +#elif defined(linux) || defined(__linux) || defined(__linux__) +# define CATCH_PLATFORM_LINUX - template - using CompleteType_t = typename CompleteType::type; +#elif defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER) || defined(__MINGW32__) +# define CATCH_PLATFORM_WINDOWS +#endif - template - struct CompleteInvoker { - template - static Result invoke(Fun&& fun, Args&&... args) { - return CATCH_FORWARD(fun)(CATCH_FORWARD(args)...); - } - }; - template <> - struct CompleteInvoker { - template - static CompleteType_t invoke(Fun&& fun, Args&&... args) { - CATCH_FORWARD(fun)(CATCH_FORWARD(args)...); - return {}; - } - }; +#endif // CATCH_PLATFORM_HPP_INCLUDED - // invoke and not return void :( - template - CompleteType_t> complete_invoke(Fun&& fun, Args&&... args) { - return CompleteInvoker>::invoke(CATCH_FORWARD(fun), CATCH_FORWARD(args)...); - } +#ifdef __cplusplus - } // namespace Detail +# if (__cplusplus >= 201402L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 201402L) +# define CATCH_CPP14_OR_GREATER +# endif - template - Detail::CompleteType_t> user_code(Fun&& fun) { - return Detail::complete_invoke(CATCH_FORWARD(fun)); - } - } // namespace Benchmark -} // namespace Catch +# if (__cplusplus >= 201703L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) +# define CATCH_CPP17_OR_GREATER +# endif -#endif // CATCH_COMPLETE_INVOKE_HPP_INCLUDED +#endif -namespace Catch { - namespace Benchmark { - namespace Detail { - struct ChronometerConcept { - virtual void start() = 0; - virtual void finish() = 0; - virtual ~ChronometerConcept(); // = default; +// 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" ) - ChronometerConcept() = default; - ChronometerConcept(ChronometerConcept const&) = default; - ChronometerConcept& operator=(ChronometerConcept const&) = default; - }; - template - struct ChronometerModel final : public ChronometerConcept { - void start() override { started = Clock::now(); } - void finish() override { finished = Clock::now(); } +// This only works on GCC 9+. so we have to also add a global suppression of Wparentheses +// for older versions of GCC. +# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \ + _Pragma( "GCC diagnostic ignored \"-Wparentheses\"" ) - ClockDuration elapsed() const { return finished - started; } +# define CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \ + _Pragma( "GCC diagnostic ignored \"-Wunused-variable\"" ) - TimePoint started; - TimePoint finished; - }; - } // namespace Detail +# define CATCH_INTERNAL_IGNORE_BUT_WARN(...) (void)__builtin_constant_p(__VA_ARGS__) - struct Chronometer { - public: - template - void measure(Fun&& fun) { measure(CATCH_FORWARD(fun), is_callable()); } +#endif - int runs() const { return repeats; } +#if defined(__clang__) && !defined(_MSC_VER) - Chronometer(Detail::ChronometerConcept& meter, int repeats_) - : impl(&meter) - , repeats(repeats_) {} +# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION _Pragma( "clang diagnostic push" ) +# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION _Pragma( "clang diagnostic pop" ) - private: - template - void measure(Fun&& fun, std::false_type) { - measure([&fun](int) { return fun(); }, std::true_type()); - } +// 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") +// ``` +// +// Similarly, NVHPC's implementation of `__builtin_constant_p` has a bug which +// results in calls to the immediately evaluated lambda expressions to be +// reported as unevaluated lambdas. +// https://developer.nvidia.com/nvidia_bug/3321845. +// +// Therefore, `CATCH_INTERNAL_IGNORE_BUT_WARN` is not implemented. +# if !defined(__ibmxl__) && !defined(__CUDACC__) && !defined( __NVCOMPILER ) +# define CATCH_INTERNAL_IGNORE_BUT_WARN(...) (void)__builtin_constant_p(__VA_ARGS__) /* NOLINT(cppcoreguidelines-pro-type-vararg, hicpp-vararg) */ +# endif - template - void measure(Fun&& fun, std::true_type) { - Detail::optimizer_barrier(); - impl->start(); - for (int i = 0; i < repeats; ++i) invoke_deoptimized(fun, i); - impl->finish(); - Detail::optimizer_barrier(); - } - Detail::ChronometerConcept* impl; - int repeats; - }; - } // namespace Benchmark -} // namespace Catch +# define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ + _Pragma( "clang diagnostic ignored \"-Wexit-time-destructors\"" ) \ + _Pragma( "clang diagnostic ignored \"-Wglobal-constructors\"") -#endif // CATCH_CHRONOMETER_HPP_INCLUDED +# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \ + _Pragma( "clang diagnostic ignored \"-Wparentheses\"" ) +# define CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \ + _Pragma( "clang diagnostic ignored \"-Wunused-variable\"" ) -// Adapted from donated nonius code. +# define CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS \ + _Pragma( "clang diagnostic ignored \"-Wgnu-zero-variadic-macro-arguments\"" ) -#ifndef CATCH_ENVIRONMENT_HPP_INCLUDED -#define CATCH_ENVIRONMENT_HPP_INCLUDED +# define CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \ + _Pragma( "clang diagnostic ignored \"-Wunused-template\"" ) +#endif // __clang__ -namespace Catch { - namespace Benchmark { - template - struct EnvironmentEstimate { - Duration mean; - OutlierClassification outliers; - template - operator EnvironmentEstimate() const { - return { mean, outliers }; - } - }; - template - struct Environment { - using clock_type = Clock; - EnvironmentEstimate> clock_resolution; - EnvironmentEstimate> clock_cost; - }; - } // namespace Benchmark -} // namespace Catch +//////////////////////////////////////////////////////////////////////////////// +// Assume that non-Windows platforms support posix signals by default +#if !defined(CATCH_PLATFORM_WINDOWS) + #define CATCH_INTERNAL_CONFIG_POSIX_SIGNALS +#endif -#endif // CATCH_ENVIRONMENT_HPP_INCLUDED +//////////////////////////////////////////////////////////////////////////////// +// We know some environments not to support full POSIX signals +#if defined(__CYGWIN__) || defined(__QNX__) || defined(__EMSCRIPTEN__) || defined(__DJGPP__) + #define CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS +#endif +#ifdef __OS400__ +# define CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS +#endif -// Adapted from donated nonius code. +//////////////////////////////////////////////////////////////////////////////// +// Android somehow still does not support std::to_string +#if defined(__ANDROID__) +# define CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING +#endif -#ifndef CATCH_EXECUTION_PLAN_HPP_INCLUDED -#define CATCH_EXECUTION_PLAN_HPP_INCLUDED - - - -// Adapted from donated nonius code. +//////////////////////////////////////////////////////////////////////////////// +// Not all Windows environments support SEH properly +#if defined(__MINGW32__) +# define CATCH_INTERNAL_CONFIG_NO_WINDOWS_SEH +#endif -#ifndef CATCH_BENCHMARK_FUNCTION_HPP_INCLUDED -#define CATCH_BENCHMARK_FUNCTION_HPP_INCLUDED +//////////////////////////////////////////////////////////////////////////////// +// PS4 +#if defined(__ORBIS__) +# define CATCH_INTERNAL_CONFIG_NO_NEW_CAPTURE +#endif +//////////////////////////////////////////////////////////////////////////////// +// Cygwin +#ifdef __CYGWIN__ -#include +// Required for some versions of Cygwin to declare gettimeofday +// see: http://stackoverflow.com/questions/36901803/gettimeofday-not-declared-in-this-scope-cygwin +# define _BSD_SOURCE +// 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)) -namespace Catch { - namespace Benchmark { - namespace Detail { - template - struct is_related - : std::is_same, std::decay_t> {}; +# define CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING - /// 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 Catch::Detail::unique_ptr clone() const = 0; - virtual ~callable(); // = default; +# endif +#endif // __CYGWIN__ - callable() = default; - callable(callable const&) = default; - callable& operator=(callable const&) = default; - }; - template - struct model : public callable { - model(Fun&& fun_) : fun(CATCH_MOVE(fun_)) {} - model(Fun const& fun_) : fun(fun_) {} +//////////////////////////////////////////////////////////////////////////////// +// Visual C++ +#if defined(_MSC_VER) - Catch::Detail::unique_ptr clone() const override { - return Catch::Detail::make_unique>( *this ); - } +# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION __pragma( warning(push) ) +# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION __pragma( warning(pop) ) - void call(Chronometer meter) const override { - call(meter, is_callable()); - } - void call(Chronometer meter, std::true_type) const { - fun(meter); - } - void call(Chronometer meter, std::false_type) const { - meter.measure(fun); - } +// Universal Windows platform does not support SEH +// Or console colours (or console at all...) +# if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP) +# define CATCH_INTERNAL_CONFIG_NO_COLOUR_WIN32 +# else +# define CATCH_INTERNAL_CONFIG_WINDOWS_SEH +# endif - Fun fun; - }; +// 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(__clang__) // Handle Clang masquerading for msvc +# if !defined(_MSVC_TRADITIONAL) || (defined(_MSVC_TRADITIONAL) && _MSVC_TRADITIONAL) +# define CATCH_INTERNAL_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR +# endif // MSVC_TRADITIONAL +# endif // __clang__ - struct do_nothing { void operator()() const {} }; +#endif // _MSC_VER - template - BenchmarkFunction(model* c) : f(c) {} +#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 - public: - BenchmarkFunction() - : f(new model{ {} }) {} +//////////////////////////////////////////////////////////////////////////////// +// Check if we are compiled with -fno-exceptions or equivalent +#if defined(__EXCEPTIONS) || defined(__cpp_exceptions) || defined(_CPPUNWIND) +# define CATCH_INTERNAL_CONFIG_EXCEPTIONS_ENABLED +#endif - template ::value, int> = 0> - BenchmarkFunction(Fun&& fun) - : f(new model>(CATCH_FORWARD(fun))) {} - BenchmarkFunction( BenchmarkFunction&& that ) noexcept: - f( CATCH_MOVE( that.f ) ) {} +//////////////////////////////////////////////////////////////////////////////// +// Embarcadero C++Build +#if defined(__BORLANDC__) + #define CATCH_INTERNAL_CONFIG_POLYFILL_ISNAN +#endif - BenchmarkFunction(BenchmarkFunction const& that) - : f(that.f->clone()) {} +//////////////////////////////////////////////////////////////////////////////// - BenchmarkFunction& - operator=( BenchmarkFunction&& that ) noexcept { - f = CATCH_MOVE( that.f ); - return *this; - } +// 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_INTERNAL_CONFIG_NO_COLOUR_WIN32 +#endif - BenchmarkFunction& operator=(BenchmarkFunction const& that) { - f = that.f->clone(); - return *this; - } +#if !defined(_GLIBCXX_USE_C99_MATH_TR1) +#define CATCH_INTERNAL_CONFIG_GLOBAL_NEXTAFTER +#endif - void operator()(Chronometer meter) const { f->call(meter); } +// Various stdlib support checks that require __has_include +#if defined(__has_include) + // Check if string_view is available and usable + #if __has_include() && defined(CATCH_CPP17_OR_GREATER) + # define CATCH_INTERNAL_CONFIG_CPP17_STRING_VIEW + #endif - private: - Catch::Detail::unique_ptr f; - }; - } // namespace Detail - } // namespace Benchmark -} // namespace Catch + // Check if optional is available and usable + # if __has_include() && defined(CATCH_CPP17_OR_GREATER) + # define CATCH_INTERNAL_CONFIG_CPP17_OPTIONAL + # endif // __has_include() && defined(CATCH_CPP17_OR_GREATER) -#endif // CATCH_BENCHMARK_FUNCTION_HPP_INCLUDED + // Check if byte is available and usable + # if __has_include() && defined(CATCH_CPP17_OR_GREATER) + # include + # if defined(__cpp_lib_byte) && (__cpp_lib_byte > 0) + # define CATCH_INTERNAL_CONFIG_CPP17_BYTE + # endif + # endif // __has_include() && defined(CATCH_CPP17_OR_GREATER) + // Check if variant is available and usable + # if __has_include() && 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 + # 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() && defined(CATCH_CPP17_OR_GREATER) +#endif // defined(__has_include) -// Adapted from donated nonius code. -#ifndef CATCH_REPEAT_HPP_INCLUDED -#define CATCH_REPEAT_HPP_INCLUDED +#if defined(CATCH_INTERNAL_CONFIG_WINDOWS_SEH) && !defined(CATCH_CONFIG_NO_WINDOWS_SEH) && !defined(CATCH_CONFIG_WINDOWS_SEH) && !defined(CATCH_INTERNAL_CONFIG_NO_WINDOWS_SEH) +# define CATCH_CONFIG_WINDOWS_SEH +#endif +// This is set by default, because we assume that unix compilers are posix-signal-compatible by default. +#if defined(CATCH_INTERNAL_CONFIG_POSIX_SIGNALS) && !defined(CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS) && !defined(CATCH_CONFIG_NO_POSIX_SIGNALS) && !defined(CATCH_CONFIG_POSIX_SIGNALS) +# define CATCH_CONFIG_POSIX_SIGNALS +#endif -#include +#if !defined(CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING) && !defined(CATCH_CONFIG_NO_CPP11_TO_STRING) && !defined(CATCH_CONFIG_CPP11_TO_STRING) +# define CATCH_CONFIG_CPP11_TO_STRING +#endif -namespace Catch { - namespace Benchmark { - namespace Detail { - template - struct repeater { - void operator()(int k) const { - for (int i = 0; i < k; ++i) { - fun(); - } - } - Fun fun; - }; - template - repeater> repeat(Fun&& fun) { - return { CATCH_FORWARD(fun) }; - } - } // namespace Detail - } // namespace Benchmark -} // namespace Catch +#if defined(CATCH_INTERNAL_CONFIG_CPP17_OPTIONAL) && !defined(CATCH_CONFIG_NO_CPP17_OPTIONAL) && !defined(CATCH_CONFIG_CPP17_OPTIONAL) +# define CATCH_CONFIG_CPP17_OPTIONAL +#endif -#endif // CATCH_REPEAT_HPP_INCLUDED +#if defined(CATCH_INTERNAL_CONFIG_CPP17_STRING_VIEW) && !defined(CATCH_CONFIG_NO_CPP17_STRING_VIEW) && !defined(CATCH_CONFIG_CPP17_STRING_VIEW) +# define CATCH_CONFIG_CPP17_STRING_VIEW +#endif +#if defined(CATCH_INTERNAL_CONFIG_CPP17_VARIANT) && !defined(CATCH_CONFIG_NO_CPP17_VARIANT) && !defined(CATCH_CONFIG_CPP17_VARIANT) +# define CATCH_CONFIG_CPP17_VARIANT +#endif -// Adapted from donated nonius code. +#if defined(CATCH_INTERNAL_CONFIG_CPP17_BYTE) && !defined(CATCH_CONFIG_NO_CPP17_BYTE) && !defined(CATCH_CONFIG_CPP17_BYTE) +# define CATCH_CONFIG_CPP17_BYTE +#endif -#ifndef CATCH_RUN_FOR_AT_LEAST_HPP_INCLUDED -#define CATCH_RUN_FOR_AT_LEAST_HPP_INCLUDED +#if defined(CATCH_CONFIG_EXPERIMENTAL_REDIRECT) +# define CATCH_INTERNAL_CONFIG_NEW_CAPTURE +#endif +#if defined(CATCH_INTERNAL_CONFIG_NEW_CAPTURE) && !defined(CATCH_INTERNAL_CONFIG_NO_NEW_CAPTURE) && !defined(CATCH_CONFIG_NO_NEW_CAPTURE) && !defined(CATCH_CONFIG_NEW_CAPTURE) +# define CATCH_CONFIG_NEW_CAPTURE +#endif -// Adapted from donated nonius code. +#if !defined( CATCH_INTERNAL_CONFIG_EXCEPTIONS_ENABLED ) && \ + !defined( CATCH_CONFIG_DISABLE_EXCEPTIONS ) && \ + !defined( CATCH_CONFIG_NO_DISABLE_EXCEPTIONS ) +# define CATCH_CONFIG_DISABLE_EXCEPTIONS +#endif -#ifndef CATCH_MEASURE_HPP_INCLUDED -#define CATCH_MEASURE_HPP_INCLUDED +#if defined(CATCH_INTERNAL_CONFIG_POLYFILL_ISNAN) && !defined(CATCH_CONFIG_NO_POLYFILL_ISNAN) && !defined(CATCH_CONFIG_POLYFILL_ISNAN) +# 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_GLOBAL_NEXTAFTER) && !defined(CATCH_CONFIG_NO_GLOBAL_NEXTAFTER) && !defined(CATCH_CONFIG_GLOBAL_NEXTAFTER) +# define CATCH_CONFIG_GLOBAL_NEXTAFTER +#endif -// Adapted from donated nonius code. -#ifndef CATCH_TIMING_HPP_INCLUDED -#define CATCH_TIMING_HPP_INCLUDED - - -#include - -namespace Catch { - namespace Benchmark { - template - struct Timing { - Duration elapsed; - Result result; - int iterations; - }; - template - using TimingOf = Timing, Detail::CompleteType_t>>; - } // namespace Benchmark -} // namespace Catch - -#endif // CATCH_TIMING_HPP_INCLUDED - -namespace Catch { - namespace Benchmark { - namespace Detail { - template - TimingOf measure(Fun&& fun, Args&&... args) { - auto start = Clock::now(); - auto&& r = Detail::complete_invoke(fun, CATCH_FORWARD(args)...); - auto end = Clock::now(); - auto delta = end - start; - return { delta, CATCH_FORWARD(r), 1 }; - } - } // namespace Detail - } // namespace Benchmark -} // namespace Catch - -#endif // CATCH_MEASURE_HPP_INCLUDED - -#include - -namespace Catch { - namespace Benchmark { - namespace Detail { - template - TimingOf measure_one(Fun&& fun, int iters, std::false_type) { - return Detail::measure(fun, iters); - } - template - TimingOf measure_one(Fun&& fun, int iters, std::true_type) { - Detail::ChronometerModel meter; - auto&& result = Detail::complete_invoke(fun, Chronometer(meter, iters)); - - return { meter.elapsed(), CATCH_MOVE(result), iters }; - } - - template - using run_for_at_least_argument_t = std::conditional_t::value, Chronometer, int>; - - - [[noreturn]] - void throw_optimized_away_error(); - - template - TimingOf> - run_for_at_least(ClockDuration how_long, - const int initial_iterations, - Fun&& fun) { - auto iters = initial_iterations; - while (iters < (1 << 30)) { - auto&& Timing = measure_one(fun, iters, is_callable()); - - if (Timing.elapsed >= how_long) { - return { Timing.elapsed, CATCH_MOVE(Timing.result), iters }; - } - iters *= 2; - } - throw_optimized_away_error(); - } - } // namespace Detail - } // namespace Benchmark -} // namespace Catch - -#endif // CATCH_RUN_FOR_AT_LEAST_HPP_INCLUDED - -#include -#include - -namespace Catch { - namespace Benchmark { - template - struct ExecutionPlan { - int iterations_per_sample; - Duration estimated_duration; - Detail::BenchmarkFunction benchmark; - Duration warmup_time; - int warmup_iterations; - - template - operator ExecutionPlan() const { - return { iterations_per_sample, estimated_duration, benchmark, warmup_time, warmup_iterations }; - } - - template - std::vector> run(const IConfig &cfg, Environment> env) const { - // warmup a bit - Detail::run_for_at_least(std::chrono::duration_cast>(warmup_time), warmup_iterations, Detail::repeat(now{})); - - std::vector> times; - times.reserve(cfg.benchmarkSamples()); - std::generate_n(std::back_inserter(times), cfg.benchmarkSamples(), [this, env] { - Detail::ChronometerModel model; - this->benchmark(Chronometer(model, iterations_per_sample)); - auto sample_time = model.elapsed() - env.clock_cost.mean; - if (sample_time < FloatDuration::zero()) sample_time = FloatDuration::zero(); - return sample_time / iterations_per_sample; - }); - return times; - } - }; - } // namespace Benchmark -} // namespace Catch - -#endif // CATCH_EXECUTION_PLAN_HPP_INCLUDED - - -// Adapted from donated nonius code. - -#ifndef CATCH_ESTIMATE_CLOCK_HPP_INCLUDED -#define CATCH_ESTIMATE_CLOCK_HPP_INCLUDED - - - -// Adapted from donated nonius code. - -#ifndef CATCH_STATS_HPP_INCLUDED -#define CATCH_STATS_HPP_INCLUDED - - -#include -#include -#include -#include -#include - -namespace Catch { - namespace Benchmark { - namespace Detail { - using sample = std::vector; - - double weighted_average_quantile(int k, int q, std::vector::iterator first, std::vector::iterator last); - - template - OutlierClassification classify_outliers(Iterator first, Iterator last) { - std::vector 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 - double mean(Iterator first, Iterator last) { - auto count = last - first; - double sum = std::accumulate(first, last, 0.); - return sum / count; - } - - template - sample jackknife(Estimator&& estimator, Iterator first, Iterator last) { - auto n = static_cast(last - first); - auto second = first; - ++second; - 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 - Estimate 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 sqcb, double x) -> std::pair { - 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(resample.size()); - double prob_n = std::count_if(resample.begin(), resample.end(), [point](double x) { return x < point; }) / static_cast(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 = static_cast((std::max)(cumn(a1), 0)); - auto hi = static_cast((std::min)(cumn(a2), n - 1)); - - return { point, resample[lo], resample[hi], confidence_level }; - } - - double outlier_variance(Estimate mean, Estimate stddev, int n); - - struct bootstrap_analysis { - Estimate mean; - Estimate standard_deviation; - double outlier_variance; - }; - - bootstrap_analysis analyse_samples(double confidence_level, unsigned int n_resamples, std::vector::iterator first, std::vector::iterator last); - } // namespace Detail - } // namespace Benchmark -} // namespace Catch - -#endif // CATCH_STATS_HPP_INCLUDED - -#include -#include -#include -#include - -namespace Catch { - namespace Benchmark { - namespace Detail { - template - std::vector resolution(int k) { - std::vector> times; - times.reserve(static_cast(k + 1)); - std::generate_n(std::back_inserter(times), k + 1, now{}); - - std::vector deltas; - deltas.reserve(static_cast(k)); - std::transform(std::next(times.begin()), times.end(), times.begin(), - std::back_inserter(deltas), - [](TimePoint a, TimePoint b) { return static_cast((a - b).count()); }); +// 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 +#endif +#if !defined(CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS) +# define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS +#endif +#if !defined(CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS) +# define CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS +#endif +#if !defined(CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS) +# define CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS +#endif - return deltas; - } +// 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 - 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; +#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 - template - int warmup() { - return run_for_at_least(std::chrono::duration_cast>(warmup_time), warmup_seed, &resolution) - .iterations; - } - template - EnvironmentEstimate> estimate_clock_resolution(int iterations) { - auto r = run_for_at_least(std::chrono::duration_cast>(clock_resolution_estimation_time), iterations, &resolution) - .result; - return { - FloatDuration(mean(r.begin(), r.end())), - classify_outliers(r.begin(), r.end()), - }; - } - template - EnvironmentEstimate> estimate_clock_cost(FloatDuration resolution) { - auto time_limit = (std::min)( - resolution * clock_cost_estimation_tick_limit, - FloatDuration(clock_cost_estimation_time_limit)); - auto time_clock = [](int k) { - return Detail::measure([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(std::chrono::duration_cast>(clock_cost_estimation_time), iters, time_clock); - std::vector times; - int nsamples = static_cast(std::ceil(time_limit / r.elapsed)); - times.reserve(static_cast(nsamples)); - std::generate_n(std::back_inserter(times), nsamples, [time_clock, &r] { - return static_cast((time_clock(r.iterations) / r.iterations).count()); - }); - return { - FloatDuration(mean(times.begin(), times.end())), - classify_outliers(times.begin(), times.end()), - }; - } +#if !defined(CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS) +# define CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS +#endif - template - Environment> measure_environment() { -#if defined(__clang__) -# pragma clang diagnostic push -# pragma clang diagnostic ignored "-Wexit-time-destructors" +#if defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) +#define CATCH_TRY if ((true)) +#define CATCH_CATCH_ALL if ((false)) +#define CATCH_CATCH_ANON(type) if ((false)) +#else +#define CATCH_TRY try +#define CATCH_CATCH_ALL catch (...) +#define CATCH_CATCH_ANON(type) catch (type) #endif - static Catch::Detail::unique_ptr>> env; -#if defined(__clang__) -# pragma clang diagnostic pop + +#if defined(CATCH_INTERNAL_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR) && !defined(CATCH_CONFIG_NO_TRADITIONAL_MSVC_PREPROCESSOR) && !defined(CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR) +#define CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR #endif - if (env) { - return *env; - } - auto iters = Detail::warmup(); - auto resolution = Detail::estimate_clock_resolution(iters); - auto cost = Detail::estimate_clock_cost(resolution.mean); +#if defined( CATCH_PLATFORM_WINDOWS ) && \ + !defined( CATCH_CONFIG_COLOUR_WIN32 ) && \ + !defined( CATCH_CONFIG_NO_COLOUR_WIN32 ) && \ + !defined( CATCH_INTERNAL_CONFIG_NO_COLOUR_WIN32 ) +# define CATCH_CONFIG_COLOUR_WIN32 +#endif - env = Catch::Detail::make_unique>>( Environment>{resolution, cost} ); - return *env; - } - } // namespace Detail - } // namespace Benchmark -} // namespace Catch -#endif // CATCH_ESTIMATE_CLOCK_HPP_INCLUDED +#endif // CATCH_COMPILER_CAPABILITIES_HPP_INCLUDED -// Adapted from donated nonius code. +#ifndef CATCH_CONTEXT_HPP_INCLUDED +#define CATCH_CONTEXT_HPP_INCLUDED -#ifndef CATCH_ANALYSE_HPP_INCLUDED -#define CATCH_ANALYSE_HPP_INCLUDED +namespace Catch { + class IResultCapture; + class IConfig; -// Adapted from donated nonius code. + class CATCH_DLL_PUBLIC IContext { + public: + virtual ~IContext(); // = default -#ifndef CATCH_SAMPLE_ANALYSIS_HPP_INCLUDED -#define CATCH_SAMPLE_ANALYSIS_HPP_INCLUDED + virtual IResultCapture* getResultCapture() = 0; + virtual IConfig const* getConfig() const = 0; + }; + class CATCH_DLL_PUBLIC IMutableContext : public IContext { + public: + virtual ~IMutableContext(); // = default + virtual void setResultCapture( IResultCapture* resultCapture ) = 0; + virtual void setConfig( IConfig const* config ) = 0; -#include -#include -#include + private: + static IMutableContext *currentContext; + friend IMutableContext& getCurrentMutableContext(); + friend void cleanUpContext(); + static void createContext(); + }; -namespace Catch { - namespace Benchmark { - template - struct SampleAnalysis { - std::vector samples; - Estimate mean; - Estimate standard_deviation; - OutlierClassification outliers; - double outlier_variance; + inline IMutableContext& getCurrentMutableContext() + { + if( !IMutableContext::currentContext ) + IMutableContext::createContext(); + // NOLINTNEXTLINE(clang-analyzer-core.uninitialized.UndefReturn) + return *IMutableContext::currentContext; + } - template - operator SampleAnalysis() const { - std::vector samples2; - samples2.reserve(samples.size()); - std::transform(samples.begin(), samples.end(), std::back_inserter(samples2), [](Duration d) { return Duration2(d); }); - return { - CATCH_MOVE(samples2), - mean, - standard_deviation, - outliers, - outlier_variance, - }; - } - }; - } // namespace Benchmark -} // namespace Catch + inline IContext& getCurrentContext() + { + return getCurrentMutableContext(); + } -#endif // CATCH_SAMPLE_ANALYSIS_HPP_INCLUDED + void cleanUpContext(); -#include -#include -#include + class CATCH_DLL_PUBLIC SimplePcg32; + CATCH_DLL_PUBLIC SimplePcg32& rng(); +} -namespace Catch { - namespace Benchmark { - namespace Detail { - template - SampleAnalysis analyse(const IConfig &cfg, Environment, Iterator first, Iterator last) { - if (!cfg.benchmarkNoAnalysis()) { - std::vector samples; - samples.reserve(static_cast(last - first)); - std::transform(first, last, std::back_inserter(samples), [](Duration d) { return d.count(); }); +#endif // CATCH_CONTEXT_HPP_INCLUDED - 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 e) { - return Estimate { - Duration(e.point), - Duration(e.lower_bound), - Duration(e.upper_bound), - e.confidence_interval, - }; - }; - std::vector samples2; - samples2.reserve(samples.size()); - std::transform(samples.begin(), samples.end(), std::back_inserter(samples2), [](double d) { return Duration(d); }); - return { - CATCH_MOVE(samples2), - wrap_estimate(analysis.mean), - wrap_estimate(analysis.standard_deviation), - outliers, - analysis.outlier_variance, - }; - } else { - std::vector samples; - samples.reserve(static_cast(last - first)); +#ifndef CATCH_UNIQUE_NAME_HPP_INCLUDED +#define CATCH_UNIQUE_NAME_HPP_INCLUDED - 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 { - CATCH_MOVE(samples), - Estimate{mean, mean, mean, 0.0}, - Estimate{Duration(0), Duration(0), Duration(0), 0.0}, - OutlierClassification{}, - 0.0 - }; - } - } - } // namespace Detail - } // namespace Benchmark -} // namespace Catch -#endif // CATCH_ANALYSE_HPP_INCLUDED -#include +/** \file + * Wrapper for the CONFIG configuration option + * + * When generating internal unique names, there are two options. Either + * we mix in the current line number, or mix in an incrementing number. + * We prefer the latter, using `__COUNTER__`, but users might want to + * use the former. + */ + +#ifndef CATCH_CONFIG_COUNTER_HPP_INCLUDED +#define CATCH_CONFIG_COUNTER_HPP_INCLUDED + +#if ( !defined(__JETBRAINS_IDE__) || __JETBRAINS_IDE__ >= 20170300L ) + #define CATCH_INTERNAL_CONFIG_COUNTER +#endif + +#if defined( CATCH_INTERNAL_CONFIG_COUNTER ) && \ + !defined( CATCH_CONFIG_NO_COUNTER ) && \ + !defined( CATCH_CONFIG_COUNTER ) +# define CATCH_CONFIG_COUNTER +#endif + + +#endif // CATCH_CONFIG_COUNTER_HPP_INCLUDED +#define INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) name##line +#define INTERNAL_CATCH_UNIQUE_NAME_LINE( name, line ) INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) +#ifdef CATCH_CONFIG_COUNTER +# define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __COUNTER__ ) +#else +# define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __LINE__ ) +#endif + +#endif // CATCH_UNIQUE_NAME_HPP_INCLUDED +#include #include #include #include -#include namespace Catch { namespace Benchmark { - struct Benchmark { + struct CATCH_DLL_PUBLIC Benchmark { Benchmark(std::string&& benchmarkName) : name(CATCH_MOVE(benchmarkName)) {} @@ -2619,8 +2653,11 @@ namespace Catch { // sets lambda to be used in fun *and* executes benchmark! template ::value, int> = 0> Benchmark & operator=(Fun func) { - fun = Detail::BenchmarkFunction(func); - run(); + auto const* cfg = getCurrentContext().getConfig(); + if (!cfg->skipBenchmarks()) { + fun = Detail::BenchmarkFunction(func); + run(); + } return *this; } @@ -2670,7 +2707,6 @@ namespace Catch { #ifndef CATCH_CONSTRUCTOR_HPP_INCLUDED #define CATCH_CONSTRUCTOR_HPP_INCLUDED - #include namespace Catch { @@ -2750,12 +2786,45 @@ namespace Catch { #define CATCH_TOSTRING_HPP_INCLUDED + +#ifndef CATCH_INTERFACES_ENUM_VALUES_REGISTRY_HPP_INCLUDED +#define CATCH_INTERFACES_ENUM_VALUES_REGISTRY_HPP_INCLUDED + #include -#include -#include -#include -#include +namespace Catch { + + namespace Detail { + struct CATCH_DLL_PUBLIC EnumInfo { + StringRef m_name; + std::vector> m_values; + + ~EnumInfo(); + + StringRef lookup( int value ) const; + }; + } // namespace Detail + + class CATCH_DLL_PUBLIC IMutableEnumValuesRegistry { + public: + virtual ~IMutableEnumValuesRegistry(); // = default; + + virtual Detail::EnumInfo const& registerEnum( StringRef enumName, StringRef allEnums, std::vector const& values ) = 0; + + template + Detail::EnumInfo const& registerEnum( StringRef enumName, StringRef allEnums, std::initializer_list values ) { + static_assert(sizeof(int) >= sizeof(E), "Cannot serialize enum to int"); + std::vector intValues; + intValues.reserve( values.size() ); + for( auto enumValue : values ) + intValues.push_back( static_cast( enumValue ) ); + return registerEnum( enumName, allEnums, intValues ); + } + }; + +} // Catch + +#endif // CATCH_INTERFACES_ENUM_VALUES_REGISTRY_HPP_INCLUDED @@ -2792,12 +2861,13 @@ namespace Catch { #include #include +#include #include #include namespace Catch { - class ReusableStringStream : Detail::NonCopyable { + class CATCH_DLL_PUBLIC ReusableStringStream : Detail::NonCopyable { std::size_t m_index; std::ostream* m_oss; public: @@ -2821,8 +2891,9 @@ namespace Catch { #pragma GCC diagnostic ignored "-Wnonnull-compare" #endif - template - auto operator << ( T const& value ) -> ReusableStringStream& { + template + CATCH_DLL_PUBLIC auto operator<<( T const& value ) + -> ReusableStringStream& { *m_oss << value; return *this; } @@ -2830,72 +2901,37 @@ namespace Catch { #if defined(__GNUC__) && !defined(__clang__) #pragma GCC diagnostic pop #endif - auto get() -> std::ostream& { return *m_oss; } - }; -} - -#endif // CATCH_REUSABLE_STRING_STREAM_HPP_INCLUDED - - -#ifndef CATCH_VOID_TYPE_HPP_INCLUDED -#define CATCH_VOID_TYPE_HPP_INCLUDED - - -namespace Catch { - namespace Detail { - - template - struct make_void { using type = void; }; - - template - using void_t = typename make_void::type; - - } // namespace Detail -} // namespace Catch - - -#endif // CATCH_VOID_TYPE_HPP_INCLUDED + auto get() -> std::ostream& { return *m_oss; } + }; +} +#endif // CATCH_REUSABLE_STRING_STREAM_HPP_INCLUDED -#ifndef CATCH_INTERFACES_ENUM_VALUES_REGISTRY_HPP_INCLUDED -#define CATCH_INTERFACES_ENUM_VALUES_REGISTRY_HPP_INCLUDED +#ifndef CATCH_VOID_TYPE_HPP_INCLUDED +#define CATCH_VOID_TYPE_HPP_INCLUDED -#include namespace Catch { - namespace Detail { - struct EnumInfo { - StringRef m_name; - std::vector> m_values; - ~EnumInfo(); - - StringRef lookup( int value ) const; + template struct CATCH_DLL_PUBLIC make_void { + using type = void; }; - } // namespace Detail - class IMutableEnumValuesRegistry { - public: - virtual ~IMutableEnumValuesRegistry(); // = default; - - virtual Detail::EnumInfo const& registerEnum( StringRef enumName, StringRef allEnums, std::vector const& values ) = 0; + template + using void_t = typename make_void::type; - template - Detail::EnumInfo const& registerEnum( StringRef enumName, StringRef allEnums, std::initializer_list values ) { - static_assert(sizeof(int) >= sizeof(E), "Cannot serialize enum to int"); - std::vector intValues; - intValues.reserve( values.size() ); - for( auto enumValue : values ) - intValues.push_back( static_cast( enumValue ) ); - return registerEnum( enumName, allEnums, intValues ); - } - }; + } // namespace Detail +} // namespace Catch -} // Catch -#endif // CATCH_INTERFACES_ENUM_VALUES_REGISTRY_HPP_INCLUDED +#endif // CATCH_VOID_TYPE_HPP_INCLUDED +#include +#include +#include +#include +#include #ifdef CATCH_CONFIG_CPP17_STRING_VIEW #include @@ -2907,8 +2943,9 @@ namespace Catch { #endif // We need a dummy global operator<< so we can bring it into Catch namespace later -struct Catch_global_namespace_dummy{}; -std::ostream& operator<<(std::ostream&, Catch_global_namespace_dummy); +struct CATCH_DLL_PUBLIC Catch_global_namespace_dummy {}; +CATCH_DLL_PUBLIC std::ostream& operator<<( std::ostream&, + Catch_global_namespace_dummy ); namespace Catch { // Bring in global namespace operator<< for ADL lookup in @@ -2921,21 +2958,22 @@ namespace Catch { constexpr StringRef unprintableString = "{?}"_sr; //! Encases `string in quotes, and optionally escapes invisibles - std::string convertIntoString( StringRef string, bool escapeInvisibles ); + CATCH_DLL_PUBLIC std::string convertIntoString( StringRef string, + bool escapeInvisibles ); //! Encases `string` in quotes, and escapes invisibles if user requested //! it via CLI - std::string convertIntoString( StringRef string ); + CATCH_DLL_PUBLIC std::string convertIntoString( StringRef string ); - std::string rawMemoryToString( const void *object, std::size_t size ); + CATCH_DLL_PUBLIC std::string rawMemoryToString( const void* object, + std::size_t size ); template std::string rawMemoryToString( const T& object ) { return rawMemoryToString( &object, sizeof(object) ); } - template - class IsStreamInsertable { + template class CATCH_DLL_PUBLIC IsStreamInsertable { template static auto test(int) -> decltype(std::declval() << std::declval(), std::true_type()); @@ -2987,8 +3025,7 @@ namespace Catch { // If we decide for C++14, change these to enable_if_ts - template - struct StringMaker { + template struct CATCH_DLL_PUBLIC StringMaker { template static std::enable_if_t<::Catch::Detail::IsStreamInsertable::value, std::string> @@ -3281,12 +3318,10 @@ namespace Catch { #include namespace Catch { namespace Detail { - template< - typename Tuple, - std::size_t N = 0, - bool = (N < std::tuple_size::value) - > - struct TupleElementPrinter { + template ::value )> + struct CATCH_DLL_PUBLIC TupleElementPrinter { static void print(const Tuple& tuple, std::ostream& os) { os << (N ? ", " : " ") << ::Catch::Detail::stringify(std::get(tuple)); @@ -3353,14 +3388,14 @@ namespace Catch { namespace Detail { template - struct is_range_impl : std::false_type {}; + struct CATCH_DLL_PUBLIC is_range_impl : std::false_type {}; template struct is_range_impl()))>> : std::true_type {}; } // namespace Detail template - struct is_range : Detail::is_range_impl {}; + struct CATCH_DLL_PUBLIC is_range : Detail::is_range_impl {}; #if defined(_MANAGED) // Managed types are never ranges template @@ -3416,15 +3451,13 @@ namespace Catch { namespace Catch { -template -struct ratio_string { - static std::string symbol() { - Catch::ReusableStringStream rss; - rss << '[' << Ratio::num << '/' - << Ratio::den << ']'; - return rss.str(); - } -}; + template struct CATCH_DLL_PUBLIC ratio_string { + static std::string symbol() { + Catch::ReusableStringStream rss; + rss << '[' << Ratio::num << '/' << Ratio::den << ']'; + return rss.str(); + } + }; template <> struct ratio_string { @@ -3540,12 +3573,11 @@ namespace Catch { \ #endif #endif // CATCH_TOSTRING_HPP_INCLUDED - #include namespace Catch { - class Approx { + class CATCH_DLL_PUBLIC Approx { private: bool equalityComparisonImpl(double other) const; // Sets and validates the new margin (margin >= 0) @@ -3645,8 +3677,8 @@ namespace Catch { }; namespace literals { - Approx operator ""_a(long double val); - Approx operator ""_a(unsigned long long val); + CATCH_DLL_PUBLIC Approx operator""_a( long double val ); + CATCH_DLL_PUBLIC Approx operator""_a( unsigned long long val ); } // end namespace literals template<> @@ -3682,19 +3714,19 @@ struct StringMaker { #ifndef CATCH_CASE_SENSITIVE_HPP_INCLUDED #define CATCH_CASE_SENSITIVE_HPP_INCLUDED + namespace Catch { - enum class CaseSensitive { Yes, No }; + enum class CATCH_DLL_PUBLIC CaseSensitive { Yes, No }; } // namespace Catch #endif // CATCH_CASE_SENSITIVE_HPP_INCLUDED - #include namespace Catch { - class WildcardPattern { + class CATCH_DLL_PUBLIC WildcardPattern { enum WildcardPosition { NoWildcard = 0, WildcardAtStart = 1, @@ -3716,7 +3748,6 @@ namespace Catch } #endif // CATCH_WILDCARD_PATTERN_HPP_INCLUDED - #include #include @@ -3726,9 +3757,9 @@ namespace Catch { struct TestCaseInfo; class TestCaseHandle; - class TestSpec { + class CATCH_DLL_PUBLIC TestSpec { - class Pattern { + class CATCH_DLL_PUBLIC Pattern { public: explicit Pattern( std::string const& name ); virtual ~Pattern(); @@ -3738,7 +3769,7 @@ namespace Catch { std::string const m_name; }; - class NamePattern : public Pattern { + class CATCH_DLL_PUBLIC NamePattern : public Pattern { public: explicit NamePattern( std::string const& name, std::string const& filterString ); bool matches( TestCaseInfo const& testCase ) const override; @@ -3746,7 +3777,7 @@ namespace Catch { WildcardPattern m_wildcardPattern; }; - class TagPattern : public Pattern { + class CATCH_DLL_PUBLIC TagPattern : public Pattern { public: explicit TagPattern( std::string const& tag, std::string const& filterString ); bool matches( TestCaseInfo const& testCase ) const override; @@ -3754,7 +3785,7 @@ namespace Catch { std::string m_tag; }; - struct Filter { + struct CATCH_DLL_PUBLIC Filter { std::vector> m_required; std::vector> m_forbidden; @@ -3763,7 +3794,7 @@ namespace Catch { }; public: - struct FilterMatch { + struct CATCH_DLL_PUBLIC FilterMatch { std::string name; std::vector tests; }; @@ -3797,8 +3828,7 @@ namespace Catch { namespace Catch { // An optional type - template - class Optional { + template class CATCH_DLL_PUBLIC Optional { public: Optional() : nullableValue( nullptr ) {} Optional( T const& _value ) @@ -3861,7 +3891,8 @@ namespace Catch { return some(); } - friend bool operator==(Optional const& a, Optional const& b) { + CATCH_DLL_PUBLIC friend bool operator==( Optional const& a, + Optional const& b ) { if (a.none() && b.none()) { return true; } else if (a.some() && b.some()) { @@ -3870,7 +3901,8 @@ namespace Catch { return false; } } - friend bool operator!=(Optional const& a, Optional const& b) { + CATCH_DLL_PUBLIC friend bool operator!=( Optional const& a, + Optional const& b ) { return !( a == b ); } @@ -3891,14 +3923,14 @@ namespace Catch { namespace Catch { - enum class GenerateFrom { + enum class CATCH_DLL_PUBLIC GenerateFrom { Time, RandomDevice, //! Currently equivalent to RandomDevice, but can change at any point Default }; - std::uint32_t generateRandomSeed(GenerateFrom from); + CATCH_DLL_PUBLIC std::uint32_t generateRandomSeed( GenerateFrom from ); } // end namespace Catch @@ -3913,7 +3945,6 @@ namespace Catch { #ifndef CATCH_CONSOLE_COLOUR_HPP_INCLUDED #define CATCH_CONSOLE_COLOUR_HPP_INCLUDED - #include #include @@ -3922,7 +3953,7 @@ namespace Catch { enum class ColourMode : std::uint8_t; class IStream; - struct Colour { + struct CATCH_DLL_PUBLIC Colour { enum Code { None = 0, @@ -3960,7 +3991,7 @@ namespace Catch { }; }; - class ColourImpl { + class CATCH_DLL_PUBLIC ColourImpl { protected: //! The associated stream of this ColourImpl instance IStream* m_stream; @@ -3969,7 +4000,7 @@ namespace Catch { //! RAII wrapper around writing specific colour of text using specific //! colour impl into a stream. - class ColourGuard { + class CATCH_DLL_PUBLIC ColourGuard { ColourImpl const* m_colourImpl; Colour::Code m_code; bool m_engaged = false; @@ -4033,7 +4064,7 @@ namespace Catch { }; //! Provides ColourImpl based on global config and target compilation platform - Detail::unique_ptr makeColourImpl( ColourMode colourSelection, + CATCH_DLL_PUBLIC Detail::unique_ptr makeColourImpl( ColourMode colourSelection, IStream* stream ); //! Checks if specific colour impl has been compiled into the binary @@ -4053,9 +4084,9 @@ namespace Catch { namespace Detail { //! Splits the reporter spec into reporter name and kv-pair options - std::vector splitReporterSpec( StringRef reporterSpec ); + CATCH_DLL_PUBLIC std::vector splitReporterSpec( StringRef reporterSpec ); - Optional stringToColourMode( StringRef colourMode ); + CATCH_DLL_PUBLIC Optional stringToColourMode( StringRef colourMode ); } /** @@ -4066,15 +4097,15 @@ namespace Catch { * compiled into the binary, and the output filename might not be * openable. */ - class ReporterSpec { + class CATCH_DLL_PUBLIC ReporterSpec { std::string m_name; Optional m_outputFileName; Optional m_colourMode; std::map m_customOptions; - friend bool operator==( ReporterSpec const& lhs, + CATCH_DLL_PUBLIC friend bool operator==( ReporterSpec const& lhs, ReporterSpec const& rhs ); - friend bool operator!=( ReporterSpec const& lhs, + CATCH_DLL_PUBLIC friend bool operator!=( ReporterSpec const& lhs, ReporterSpec const& rhs ) { return !( lhs == rhs ); } @@ -4109,7 +4140,7 @@ namespace Catch { * * empty key/value in an custom kv pair * * ... */ - Optional parseReporterSpec( StringRef reporterSpec ); + CATCH_DLL_PUBLIC Optional parseReporterSpec( StringRef reporterSpec ); } @@ -4129,20 +4160,20 @@ namespace Catch { * * Like `ReporterSpec`, the semantics are unchecked. */ - struct ProcessedReporterSpec { + struct CATCH_DLL_PUBLIC ProcessedReporterSpec { std::string name; std::string outputFilename; ColourMode colourMode; std::map customOptions; - friend bool operator==( ProcessedReporterSpec const& lhs, + CATCH_DLL_PUBLIC friend bool operator==( ProcessedReporterSpec const& lhs, ProcessedReporterSpec const& rhs ); - friend bool operator!=( ProcessedReporterSpec const& lhs, + CATCH_DLL_PUBLIC friend bool operator!=( ProcessedReporterSpec const& lhs, ProcessedReporterSpec const& rhs ) { return !( lhs == rhs ); } }; - struct ConfigData { + struct CATCH_DLL_PUBLIC ConfigData { bool listTests = false; bool listTags = false; @@ -4163,6 +4194,7 @@ namespace Catch { unsigned int shardCount = 1; unsigned int shardIndex = 0; + bool skipBenchmarks = false; bool benchmarkNoAnalysis = false; unsigned int benchmarkSamples = 100; double benchmarkConfidenceInterval = 0.95; @@ -4186,8 +4218,7 @@ namespace Catch { std::vector sectionsToRun; }; - - class Config : public IConfig { + class CATCH_DLL_PUBLIC Config : public IConfig { public: Config() = default; @@ -4228,6 +4259,7 @@ namespace Catch { int abortAfter() const override; bool showInvisibles() const override; Verbosity verbosity() const override; + bool skipBenchmarks() const override; bool benchmarkNoAnalysis() const override; unsigned int benchmarkSamples() const override; double benchmarkConfidenceInterval() const override; @@ -4260,7 +4292,7 @@ namespace Catch { // << +StreamEndStop // as well as // << stuff +StreamEndStop - struct StreamEndStop { + struct CATCH_DLL_PUBLIC StreamEndStop { StringRef operator+() const { return StringRef(); } template @@ -4272,7 +4304,6 @@ namespace Catch { } // namespace Catch #endif // CATCH_STREAM_END_STOP_HPP_INCLUDED - #include #include @@ -4280,7 +4311,7 @@ namespace Catch { struct SourceLineInfo; - struct MessageStream { + struct CATCH_DLL_PUBLIC MessageStream { template MessageStream& operator << ( T const& value ) { @@ -4291,7 +4322,7 @@ namespace Catch { ReusableStringStream m_stream; }; - struct MessageBuilder : MessageStream { + struct CATCH_DLL_PUBLIC MessageBuilder : MessageStream { MessageBuilder( StringRef macroName, SourceLineInfo const& lineInfo, ResultWas::OfType type ): @@ -4307,7 +4338,7 @@ namespace Catch { MessageInfo m_info; }; - class ScopedMessage { + class CATCH_DLL_PUBLIC ScopedMessage { public: explicit ScopedMessage( MessageBuilder const& builder ); ScopedMessage( ScopedMessage& duplicate ) = delete; @@ -4318,7 +4349,7 @@ namespace Catch { bool m_moved = false; }; - class Capturer { + class CATCH_DLL_PUBLIC Capturer { std::vector m_messages; IResultCapture& m_resultCapture = getResultCapture(); size_t m_captured = 0; @@ -4438,6 +4469,7 @@ namespace Catch { # endif #endif +#include #include #include @@ -4454,24 +4486,24 @@ namespace Catch { class Parser; // enum of result types from a parse - enum class ParseResultType { + enum class CATCH_DLL_PUBLIC ParseResultType { Matched, NoMatch, ShortCircuitAll, ShortCircuitSame }; - struct accept_many_t {}; + struct CATCH_DLL_PUBLIC accept_many_t {}; constexpr accept_many_t accept_many {}; namespace Detail { - struct fake_arg { + struct CATCH_DLL_PUBLIC fake_arg { template operator T(); }; template - struct is_unary_function : std::false_type {}; + struct CATCH_DLL_PUBLIC is_unary_function : std::false_type {}; template struct is_unary_function< @@ -4504,15 +4536,15 @@ namespace Catch { // Wraps a token coming from a token stream. These may not directly // correspond to strings as a single string may encode an option + // its argument if the : or = form is used - enum class TokenType { Option, Argument }; - struct Token { + enum class CATCH_DLL_PUBLIC TokenType { Option, Argument }; + struct CATCH_DLL_PUBLIC Token { TokenType type; std::string token; }; // Abstracts iterators into args as a stream of tokens, with option // arguments uniformly handled - class TokenStream { + class CATCH_DLL_PUBLIC TokenStream { using Iterator = std::vector::const_iterator; Iterator it; Iterator itEnd; @@ -4546,14 +4578,14 @@ namespace Catch { }; //! Denotes type of a parsing result - enum class ResultType { + enum class CATCH_DLL_PUBLIC ResultType { Ok, ///< No errors LogicError, ///< Error in user-specified arguments for ///< construction RuntimeError ///< Error in parsing inputs }; - class ResultBase { + class CATCH_DLL_PUBLIC ResultBase { protected: ResultBase( ResultType type ): m_type( type ) {} virtual ~ResultBase(); // = default; @@ -4569,7 +4601,8 @@ namespace Catch { ResultType m_type; }; - template class ResultValueBase : public ResultBase { + template + class CATCH_DLL_PUBLIC ResultValueBase : public ResultBase { public: auto value() const -> T const& { enforceOk(); @@ -4615,7 +4648,7 @@ namespace Catch { }; template - class BasicResult : public ResultValueBase { + class CATCH_DLL_PUBLIC BasicResult : public ResultValueBase { public: template explicit BasicResult( BasicResult const& other ): @@ -4670,7 +4703,7 @@ namespace Catch { using ResultBase::m_type; }; - class ParseState { + class CATCH_DLL_PUBLIC ParseState { public: ParseState( ParseResultType type, TokenStream const& remainingTokens ); @@ -4689,7 +4722,7 @@ namespace Catch { using ParserResult = BasicResult; using InternalParseResult = BasicResult; - struct HelpColumns { + struct CATCH_DLL_PUBLIC HelpColumns { std::string left; std::string right; }; @@ -4706,9 +4739,10 @@ namespace Catch { return ParserResult::ok( ParseResultType::Matched ); } } - ParserResult convertInto( std::string const& source, - std::string& target ); - ParserResult convertInto( std::string const& source, bool& target ); + CATCH_DLL_PUBLIC ParserResult + convertInto( std::string const& source, std::string& target ); + CATCH_DLL_PUBLIC ParserResult + convertInto( std::string const& source, bool& target ); #ifdef CLARA_CONFIG_OPTIONAL_TYPE template @@ -4723,21 +4757,22 @@ namespace Catch { } #endif // CLARA_CONFIG_OPTIONAL_TYPE - struct BoundRef : Catch::Detail::NonCopyable { + struct CATCH_DLL_PUBLIC BoundRef : Catch::Detail::NonCopyable { virtual ~BoundRef() = default; virtual bool isContainer() const; virtual bool isFlag() const; }; - struct BoundValueRefBase : BoundRef { + struct CATCH_DLL_PUBLIC BoundValueRefBase : BoundRef { virtual auto setValue( std::string const& arg ) -> ParserResult = 0; }; - struct BoundFlagRefBase : BoundRef { + struct CATCH_DLL_PUBLIC BoundFlagRefBase : BoundRef { virtual auto setFlag( bool flag ) -> ParserResult = 0; bool isFlag() const override; }; - template struct BoundValueRef : BoundValueRefBase { + template + struct CATCH_DLL_PUBLIC BoundValueRef : BoundValueRefBase { T& m_ref; explicit BoundValueRef( T& ref ): m_ref( ref ) {} @@ -4765,7 +4800,7 @@ namespace Catch { } }; - struct BoundFlagRef : BoundFlagRefBase { + struct CATCH_DLL_PUBLIC BoundFlagRef : BoundFlagRefBase { bool& m_ref; explicit BoundFlagRef( bool& ref ): m_ref( ref ) {} @@ -4773,7 +4808,8 @@ namespace Catch { ParserResult setFlag( bool flag ) override; }; - template struct LambdaInvoker { + template + struct CATCH_DLL_PUBLIC LambdaInvoker { static_assert( std::is_same::value, "Lambda must return void or clara::ParserResult" ); @@ -4804,7 +4840,8 @@ namespace Catch { L>::ReturnType>::invoke( lambda, temp ); } - template struct BoundLambda : BoundValueRefBase { + template + struct CATCH_DLL_PUBLIC BoundLambda : BoundValueRefBase { L m_lambda; static_assert( @@ -4819,12 +4856,14 @@ namespace Catch { } }; - template struct BoundManyLambda : BoundLambda { + template + struct CATCH_DLL_PUBLIC BoundManyLambda : BoundLambda { explicit BoundManyLambda( L const& lambda ): BoundLambda( lambda ) {} bool isContainer() const override { return true; } }; - template struct BoundFlagLambda : BoundFlagRefBase { + template + struct CATCH_DLL_PUBLIC BoundFlagLambda : BoundFlagRefBase { L m_lambda; static_assert( @@ -4844,9 +4883,9 @@ namespace Catch { } }; - enum class Optionality { Optional, Required }; + enum class CATCH_DLL_PUBLIC Optionality { Optional, Required }; - class ParserBase { + class CATCH_DLL_PUBLIC ParserBase { public: virtual ~ParserBase() = default; virtual auto validate() const -> Result { return Result::ok(); } @@ -4859,7 +4898,7 @@ namespace Catch { }; template - class ComposableParserImpl : public ParserBase { + class CATCH_DLL_PUBLIC ComposableParserImpl : public ParserBase { public: template auto operator|( T const& other ) const -> Parser; @@ -4867,7 +4906,8 @@ namespace Catch { // Common code and state for Args and Opts template - class ParserRefImpl : public ComposableParserImpl { + class CATCH_DLL_PUBLIC ParserRefImpl + : public ComposableParserImpl { protected: Optionality m_optionality = Optionality::Optional; std::shared_ptr m_ref; @@ -4932,7 +4972,7 @@ namespace Catch { // A parser for arguments - class Arg : public Detail::ParserRefImpl { + class CATCH_DLL_PUBLIC Arg : public Detail::ParserRefImpl { public: using ParserRefImpl::ParserRefImpl; using ParserBase::parse; @@ -4943,7 +4983,7 @@ namespace Catch { }; // A parser for options - class Opt : public Detail::ParserRefImpl { + class CATCH_DLL_PUBLIC Opt : public Detail::ParserRefImpl { protected: std::vector m_optNames; @@ -4990,7 +5030,8 @@ namespace Catch { }; // Specifies the name of the executable - class ExeName : public Detail::ComposableParserImpl { + class CATCH_DLL_PUBLIC ExeName + : public Detail::ComposableParserImpl { std::shared_ptr m_name; std::shared_ptr m_ref; @@ -5013,9 +5054,8 @@ namespace Catch { Detail::ParserResult set(std::string const& newName); }; - // A Combined parser - class Parser : Detail::ParserBase { + class CATCH_DLL_PUBLIC Parser : Detail::ParserBase { mutable ExeName m_exeName; std::vector m_options; std::vector m_args; @@ -5048,7 +5088,8 @@ namespace Catch { void writeToStream(std::ostream& os) const; - friend auto operator<<(std::ostream& os, Parser const& parser) + CATCH_DLL_PUBLIC friend auto operator<<( std::ostream& os, + Parser const& parser ) -> std::ostream& { parser.writeToStream(os); return os; @@ -5064,7 +5105,7 @@ namespace Catch { // Transport for raw args (copied from main args, or supplied via // init list for testing) - class Args { + class CATCH_DLL_PUBLIC Args { friend Detail::TokenStream; std::string m_exeName; std::vector m_args; @@ -5076,9 +5117,8 @@ namespace Catch { std::string const& exeName() const { return m_exeName; } }; - // Convenience wrapper for option parser that specifies the help option - struct Help : Opt { + struct CATCH_DLL_PUBLIC Help : Opt { Help(bool& showHelpFlag); }; @@ -5111,7 +5151,7 @@ namespace Catch { struct ConfigData; - Clara::Parser makeCommandLineParser( ConfigData& config ); + CATCH_DLL_PUBLIC Clara::Parser makeCommandLineParser( ConfigData& config ); } // end namespace Catch @@ -5119,7 +5159,7 @@ namespace Catch { namespace Catch { - class Session : Detail::NonCopyable { + class CATCH_DLL_PUBLIC Session : Detail::NonCopyable { public: Session(); @@ -5168,12 +5208,11 @@ namespace Catch { #ifndef CATCH_TAG_ALIAS_HPP_INCLUDED #define CATCH_TAG_ALIAS_HPP_INCLUDED - #include namespace Catch { - struct TagAlias { + struct CATCH_DLL_PUBLIC TagAlias { TagAlias(std::string const& _tag, SourceLineInfo _lineInfo): tag(_tag), lineInfo(_lineInfo) @@ -5194,7 +5233,7 @@ namespace Catch { namespace Catch { - struct RegistrarForTagAliases { + struct CATCH_DLL_PUBLIC RegistrarForTagAliases { RegistrarForTagAliases( char const* alias, char const* tag, SourceLineInfo const& lineInfo ); }; @@ -5241,7 +5280,6 @@ namespace Catch { #ifndef CATCH_DECOMPOSER_HPP_INCLUDED #define CATCH_DECOMPOSER_HPP_INCLUDED - #include #ifdef _MSC_VER @@ -5263,7 +5301,7 @@ namespace Catch { namespace Catch { - class ITransientExpression { + class CATCH_DLL_PUBLIC ITransientExpression { bool m_isBinaryExpression; bool m_result; @@ -5285,16 +5323,20 @@ namespace Catch { // complain if it's not here :-( virtual ~ITransientExpression(); // = default; - friend std::ostream& operator<<(std::ostream& out, ITransientExpression const& expr) { + CATCH_DLL_PUBLIC friend std::ostream& operator<<(std::ostream& out, ITransientExpression const& expr) { expr.streamReconstructedExpression(out); return out; } }; - void formatReconstructedExpression( std::ostream &os, std::string const& lhs, StringRef op, std::string const& rhs ); + CATCH_DLL_PUBLIC void + formatReconstructedExpression( std::ostream& os, + std::string const& lhs, + StringRef op, + std::string const& rhs ); - template - class BinaryExpr : public ITransientExpression { + template + class CATCH_DLL_PUBLIC BinaryExpr : public ITransientExpression { LhsT m_lhs; StringRef m_op; RhsT m_rhs; @@ -5369,8 +5411,8 @@ namespace Catch { } }; - template - class UnaryExpr : public ITransientExpression { + template + class CATCH_DLL_PUBLIC UnaryExpr : public ITransientExpression { LhsT m_lhs; void streamReconstructedExpression( std::ostream &os ) const override { @@ -5384,7 +5426,6 @@ namespace Catch { {} }; - // Specialised comparison functions to handle equality comparisons between ints and pointers (NULL deduces as an int) template auto compareEqual( LhsT const& lhs, RhsT const& rhs ) -> bool { return static_cast(lhs == rhs); } @@ -5408,9 +5449,7 @@ namespace Catch { template auto compareNotEqual( long lhs, T* const& rhs ) -> bool { return reinterpret_cast( lhs ) != rhs; } - - template - class ExprLhs { + template class CATCH_DLL_PUBLIC ExprLhs { LhsT m_lhs; public: explicit ExprLhs( LhsT lhs ) : m_lhs( lhs ) {} @@ -5472,7 +5511,7 @@ namespace Catch { } }; - struct Decomposer { + struct CATCH_DLL_PUBLIC Decomposer { template>::value, int> = 0> friend auto operator <= ( Decomposer &&, T && lhs ) -> ExprLhs { return ExprLhs{ lhs }; @@ -5503,12 +5542,12 @@ namespace Catch { class IResultCapture; - struct AssertionReaction { + struct CATCH_DLL_PUBLIC AssertionReaction { bool shouldDebugBreak = false; bool shouldThrow = false; }; - class AssertionHandler { + class CATCH_DLL_PUBLIC AssertionHandler { AssertionInfo m_assertionInfo; AssertionReaction m_reaction; bool m_completed = false; @@ -5548,7 +5587,9 @@ namespace Catch { auto allowThrows() const -> bool; }; - void handleExceptionMatchExpr( AssertionHandler& handler, std::string const& str, StringRef matcherString ); + CATCH_DLL_PUBLIC void handleExceptionMatchExpr( AssertionHandler& handler, + std::string const& str, + StringRef matcherString ); } // namespace Catch @@ -5699,7 +5740,7 @@ namespace Catch { namespace Catch { - class Timer { + class CATCH_DLL_PUBLIC Timer { uint64_t m_nanoseconds = 0; public: void start(); @@ -5715,7 +5756,7 @@ namespace Catch { namespace Catch { - class Section : Detail::NonCopyable { + class CATCH_DLL_PUBLIC Section : Detail::NonCopyable { public: Section( SectionInfo&& info ); ~Section(); @@ -5763,7 +5804,7 @@ namespace Catch { class TestSpec; struct TestCaseInfo; - class ITestInvoker { + class CATCH_DLL_PUBLIC ITestInvoker { public: virtual void invoke () const = 0; virtual ~ITestInvoker(); // = default @@ -5772,7 +5813,7 @@ namespace Catch { class TestCaseHandle; class IConfig; - class ITestCaseRegistry { + class CATCH_DLL_PUBLIC ITestCaseRegistry { public: virtual ~ITestCaseRegistry(); // = default // TODO: this exists only for adding filenames to test cases -- let's expose this in a saner way later @@ -5815,26 +5856,30 @@ namespace Catch { namespace Catch { -template -class TestInvokerAsMethod : public ITestInvoker { - void (C::*m_testAsMethod)(); -public: - TestInvokerAsMethod( void (C::*testAsMethod)() ) noexcept : m_testAsMethod( testAsMethod ) {} + template + class CATCH_DLL_PUBLIC TestInvokerAsMethod : public ITestInvoker { + void ( C::*m_testAsMethod )(); - void invoke() const override { - C obj; - (obj.*m_testAsMethod)(); - } -}; + public: + TestInvokerAsMethod( void ( C::*testAsMethod )() ) noexcept: + m_testAsMethod( testAsMethod ) {} -Detail::unique_ptr makeTestInvoker( void(*testAsFunction)() ); + void invoke() const override { + C obj; + ( obj.*m_testAsMethod )(); + } + }; -template -Detail::unique_ptr makeTestInvoker( void (C::*testAsMethod)() ) { - return Detail::make_unique>( testAsMethod ); + Detail::unique_ptr + CATCH_DLL_PUBLIC makeTestInvoker( void ( *testAsFunction )() ); + + template + Detail::unique_ptr + makeTestInvoker( void ( C::*testAsMethod )() ) { + return Detail::make_unique>( testAsMethod ); } -struct NameAndTags { +struct CATCH_DLL_PUBLIC NameAndTags { constexpr NameAndTags( StringRef name_ = StringRef(), StringRef tags_ = StringRef() ) noexcept: name( name_ ), tags( tags_ ) {} @@ -5842,7 +5887,7 @@ struct NameAndTags { StringRef tags; }; -struct AutoReg : Detail::NonCopyable { +struct CATCH_DLL_PUBLIC AutoReg : Detail::NonCopyable { AutoReg( Detail::unique_ptr invoker, SourceLineInfo const& lineInfo, StringRef classOrMethod, NameAndTags const& nameAndTags ) noexcept; }; @@ -5851,12 +5896,14 @@ struct AutoReg : Detail::NonCopyable { #if defined(CATCH_CONFIG_DISABLE) #define INTERNAL_CATCH_TESTCASE_NO_REGISTRATION( TestName, ... ) \ static inline void TestName() - #define INTERNAL_CATCH_TESTCASE_METHOD_NO_REGISTRATION( TestName, ClassName, ... ) \ - namespace{ \ - struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName) { \ - void test(); \ - }; \ - } \ +# define INTERNAL_CATCH_TESTCASE_METHOD_NO_REGISTRATION( \ + TestName, ClassName, ... ) \ + namespace { \ + struct CATCH_DLL_PUBLIC TestName \ + : INTERNAL_CATCH_REMOVE_PARENS( ClassName ) { \ + void test(); \ + }; \ + } \ void TestName::test() #endif @@ -5879,28 +5926,40 @@ struct AutoReg : Detail::NonCopyable { 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) { \ - void test(); \ - }; \ - Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( Catch::makeTestInvoker( &TestName::test ), CATCH_INTERNAL_LINEINFO, #ClassName, Catch::NameAndTags{ __VA_ARGS__ } ); /* NOLINT */ \ - } \ - CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \ - void TestName::test() - #define INTERNAL_CATCH_TEST_CASE_METHOD( ClassName, ... ) \ - INTERNAL_CATCH_TEST_CASE_METHOD2( INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEST_ ), ClassName, __VA_ARGS__ ) +#define INTERNAL_CATCH_TEST_CASE_METHOD2( TestName, ClassName, ... ) \ + CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ + CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ + namespace { \ + struct CATCH_DLL_PUBLIC TestName \ + : INTERNAL_CATCH_REMOVE_PARENS( ClassName ) { \ + void test(); \ + }; \ + Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( \ + Catch::makeTestInvoker( &TestName::test ), \ + CATCH_INTERNAL_LINEINFO, \ + #ClassName, \ + Catch::NameAndTags{ __VA_ARGS__ } ); /* NOLINT */ \ + } \ + CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \ + void TestName::test() +#define INTERNAL_CATCH_TEST_CASE_METHOD( ClassName, ... ) \ + INTERNAL_CATCH_TEST_CASE_METHOD2( \ + INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEST_ ), \ + ClassName, \ + __VA_ARGS__ ) - /////////////////////////////////////////////////////////////////////////////// - #define INTERNAL_CATCH_REGISTER_TESTCASE( Function, ... ) \ - do { \ - 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_STOP_WARNINGS_SUPPRESSION \ - } while(false) +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_REGISTER_TESTCASE( Function, ... ) \ + do { \ + 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_STOP_WARNINGS_SUPPRESSION \ + } while ( false ) #endif // CATCH_TEST_REGISTRY_HPP_INCLUDED @@ -6210,53 +6269,128 @@ struct AutoReg : Detail::NonCopyable { #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 struct TypeList {};\ - template\ - constexpr auto get_wrapper() noexcept -> TypeList { return {}; }\ - template class...> struct TemplateTypeList{};\ - template class...Cs>\ - constexpr auto get_wrapper() noexcept -> TemplateTypeList { return {}; }\ - template\ - struct append;\ - template\ - struct rewrap;\ - template class, typename...>\ - struct create;\ - template class, typename>\ - struct convert;\ - \ - template \ - struct append { using type = T; };\ - template< template class L1, typename...E1, template class L2, typename...E2, typename...Rest>\ - struct append, L2, Rest...> { using type = typename append, Rest...>::type; };\ - template< template class L1, typename...E1, typename...Rest>\ - struct append, TypeList, Rest...> { using type = L1; };\ - \ - template< template class Container, template class List, typename...elems>\ - struct rewrap, List> { using type = TypeList>; };\ - template< template class Container, template class List, class...Elems, typename...Elements>\ - struct rewrap, List, Elements...> { using type = typename append>, typename rewrap, Elements...>::type>::type; };\ - \ - template