summaryrefslogtreecommitdiffstatshomepage
path: root/3rdparty/bx
diff options
context:
space:
mode:
Diffstat (limited to '3rdparty/bx')
-rw-r--r--3rdparty/bx/.appveyor.yml3
-rw-r--r--3rdparty/bx/.editorconfig7
-rw-r--r--3rdparty/bx/.travis.yml29
-rw-r--r--3rdparty/bx/3rdparty/catch/catch.hpp11069
-rw-r--r--3rdparty/bx/3rdparty/catch/catch_amalgamated.cpp10360
-rw-r--r--3rdparty/bx/3rdparty/catch/catch_amalgamated.hpp12233
-rw-r--r--3rdparty/bx/LICENSE18
-rw-r--r--3rdparty/bx/README.md31
-rw-r--r--3rdparty/bx/include/bx/allocator.h28
-rw-r--r--3rdparty/bx/include/bx/bounds.h526
-rw-r--r--3rdparty/bx/include/bx/bx.h207
-rw-r--r--3rdparty/bx/include/bx/commandline.h4
-rw-r--r--3rdparty/bx/include/bx/config.h12
-rw-r--r--3rdparty/bx/include/bx/constants.h70
-rw-r--r--3rdparty/bx/include/bx/cpu.h4
-rw-r--r--3rdparty/bx/include/bx/debug.h8
-rw-r--r--3rdparty/bx/include/bx/easing.h4
-rw-r--r--3rdparty/bx/include/bx/endian.h12
-rw-r--r--3rdparty/bx/include/bx/error.h69
-rw-r--r--3rdparty/bx/include/bx/file.h75
-rw-r--r--3rdparty/bx/include/bx/filepath.h34
-rw-r--r--3rdparty/bx/include/bx/float4x4_t.h26
-rw-r--r--3rdparty/bx/include/bx/handlealloc.h6
-rw-r--r--3rdparty/bx/include/bx/hash.h98
-rw-r--r--3rdparty/bx/include/bx/inline/allocator.inl16
-rw-r--r--3rdparty/bx/include/bx/inline/bounds.inl257
-rw-r--r--3rdparty/bx/include/bx/inline/bx.inl117
-rw-r--r--3rdparty/bx/include/bx/inline/cpu.inl57
-rw-r--r--3rdparty/bx/include/bx/inline/easing.inl4
-rw-r--r--3rdparty/bx/include/bx/inline/endian.inl10
-rw-r--r--3rdparty/bx/include/bx/inline/error.inl71
-rw-r--r--3rdparty/bx/include/bx/inline/float4x4_t.inl93
-rw-r--r--3rdparty/bx/include/bx/inline/handlealloc.inl14
-rw-r--r--3rdparty/bx/include/bx/inline/hash.inl182
-rw-r--r--3rdparty/bx/include/bx/inline/math.inl928
-rw-r--r--3rdparty/bx/include/bx/inline/mpscqueue.inl4
-rw-r--r--3rdparty/bx/include/bx/inline/mutex.inl4
-rw-r--r--3rdparty/bx/include/bx/inline/os.inl18
-rw-r--r--3rdparty/bx/include/bx/inline/pixelformat.inl56
-rw-r--r--3rdparty/bx/include/bx/inline/readerwriter.inl44
-rw-r--r--3rdparty/bx/include/bx/inline/ringbuffer.inl8
-rw-r--r--3rdparty/bx/include/bx/inline/rng.inl10
-rw-r--r--3rdparty/bx/include/bx/inline/simd128_langext.inl12
-rw-r--r--3rdparty/bx/include/bx/inline/simd128_neon.inl64
-rw-r--r--3rdparty/bx/include/bx/inline/simd128_ref.inl53
-rw-r--r--3rdparty/bx/include/bx/inline/simd128_sse.inl40
-rw-r--r--3rdparty/bx/include/bx/inline/simd128_swizzle.inl2
-rw-r--r--3rdparty/bx/include/bx/inline/simd256_avx.inl4
-rw-r--r--3rdparty/bx/include/bx/inline/simd256_ref.inl4
-rw-r--r--3rdparty/bx/include/bx/inline/simd_ni.inl13
-rw-r--r--3rdparty/bx/include/bx/inline/sort.inl172
-rw-r--r--3rdparty/bx/include/bx/inline/spscqueue.inl9
-rw-r--r--3rdparty/bx/include/bx/inline/string.inl182
-rw-r--r--3rdparty/bx/include/bx/inline/typetraits.inl462
-rw-r--r--3rdparty/bx/include/bx/inline/uint32_t.inl235
-rw-r--r--3rdparty/bx/include/bx/macros.h98
-rw-r--r--3rdparty/bx/include/bx/maputil.h4
-rw-r--r--3rdparty/bx/include/bx/math.h522
-rw-r--r--3rdparty/bx/include/bx/mpscqueue.h8
-rw-r--r--3rdparty/bx/include/bx/mutex.h6
-rw-r--r--3rdparty/bx/include/bx/os.h14
-rw-r--r--3rdparty/bx/include/bx/pixelformat.h14
-rw-r--r--3rdparty/bx/include/bx/platform.h126
-rw-r--r--3rdparty/bx/include/bx/process.h4
-rw-r--r--3rdparty/bx/include/bx/readerwriter.h145
-rw-r--r--3rdparty/bx/include/bx/ringbuffer.h10
-rw-r--r--3rdparty/bx/include/bx/rng.h8
-rw-r--r--3rdparty/bx/include/bx/semaphore.h5
-rw-r--r--3rdparty/bx/include/bx/settings.h8
-rw-r--r--3rdparty/bx/include/bx/simd_t.h12
-rw-r--r--3rdparty/bx/include/bx/sort.h277
-rw-r--r--3rdparty/bx/include/bx/spscqueue.h12
-rw-r--r--3rdparty/bx/include/bx/string.h126
-rw-r--r--3rdparty/bx/include/bx/thread.h19
-rw-r--r--3rdparty/bx/include/bx/timer.h4
-rw-r--r--3rdparty/bx/include/bx/typetraits.h285
-rw-r--r--3rdparty/bx/include/bx/uint32_t.h90
-rw-r--r--3rdparty/bx/include/bx/url.h4
-rw-r--r--3rdparty/bx/include/compat/linux/sal.h1
-rw-r--r--3rdparty/bx/include/compat/mingw/salieri.h16
-rw-r--r--3rdparty/bx/include/compat/msvc/dirent.h1044
-rw-r--r--3rdparty/bx/makefile111
-rw-r--r--3rdparty/bx/scripts/bin2c.lua16
-rw-r--r--3rdparty/bx/scripts/bx.lua54
-rw-r--r--3rdparty/bx/scripts/genie.lua28
-rw-r--r--3rdparty/bx/scripts/lemon.lua4
-rw-r--r--3rdparty/bx/scripts/toolchain.lua468
-rw-r--r--3rdparty/bx/src/allocator.cpp11
-rw-r--r--3rdparty/bx/src/amalgamated.cpp5
-rw-r--r--3rdparty/bx/src/bounds.cpp2039
-rw-r--r--3rdparty/bx/src/bx.cpp94
-rw-r--r--3rdparty/bx/src/bx_p.h45
-rw-r--r--3rdparty/bx/src/commandline.cpp9
-rw-r--r--3rdparty/bx/src/crtnone.cpp26
-rw-r--r--3rdparty/bx/src/debug.cpp24
-rw-r--r--3rdparty/bx/src/dtoa.cpp13
-rw-r--r--3rdparty/bx/src/easing.cpp5
-rw-r--r--3rdparty/bx/src/file.cpp462
-rw-r--r--3rdparty/bx/src/filepath.cpp206
-rw-r--r--3rdparty/bx/src/hash.cpp125
-rw-r--r--3rdparty/bx/src/math.cpp392
-rw-r--r--3rdparty/bx/src/mutex.cpp43
-rw-r--r--3rdparty/bx/src/os.cpp76
-rw-r--r--3rdparty/bx/src/process.cpp39
-rw-r--r--3rdparty/bx/src/semaphore.cpp30
-rw-r--r--3rdparty/bx/src/settings.cpp5
-rw-r--r--3rdparty/bx/src/sort.cpp124
-rw-r--r--3rdparty/bx/src/string.cpp302
-rw-r--r--3rdparty/bx/src/thread.cpp156
-rw-r--r--3rdparty/bx/src/timer.cpp10
-rw-r--r--3rdparty/bx/src/url.cpp3
-rw-r--r--3rdparty/bx/tests/allocator_test.cpp78
-rw-r--r--3rdparty/bx/tests/atomic_test.cpp4
-rw-r--r--3rdparty/bx/tests/crt_test.cpp27
-rw-r--r--3rdparty/bx/tests/dbg.h4
-rw-r--r--3rdparty/bx/tests/easing_test.cpp6
-rw-r--r--3rdparty/bx/tests/filepath_test.cpp9
-rw-r--r--3rdparty/bx/tests/handle_bench.cpp4
-rw-r--r--3rdparty/bx/tests/handle_test.cpp4
-rw-r--r--3rdparty/bx/tests/hash_test.cpp111
-rw-r--r--3rdparty/bx/tests/macros_test.cpp45
-rw-r--r--3rdparty/bx/tests/main_test.cpp8
-rw-r--r--3rdparty/bx/tests/math_bench.cpp32
-rw-r--r--3rdparty/bx/tests/math_test.cpp225
-rw-r--r--3rdparty/bx/tests/nlalloc_test.cpp195
-rw-r--r--3rdparty/bx/tests/os_test.cpp18
-rw-r--r--3rdparty/bx/tests/queue_test.cpp4
-rw-r--r--3rdparty/bx/tests/readerwriter_test.cpp31
-rw-r--r--3rdparty/bx/tests/ringbuffer_test.cpp4
-rw-r--r--3rdparty/bx/tests/rng_test.cpp4
-rw-r--r--3rdparty/bx/tests/run_test.cpp17
-rw-r--r--3rdparty/bx/tests/settings_test.cpp12
-rw-r--r--3rdparty/bx/tests/simd_bench.cpp4
-rw-r--r--3rdparty/bx/tests/simd_test.cpp28
-rw-r--r--3rdparty/bx/tests/sort_test.cpp148
-rw-r--r--3rdparty/bx/tests/string_test.cpp119
-rw-r--r--3rdparty/bx/tests/test.h12
-rw-r--r--3rdparty/bx/tests/thread_test.cpp12
-rw-r--r--3rdparty/bx/tests/tokenizecmd_test.cpp4
-rw-r--r--3rdparty/bx/tests/typetraits_test.cpp688
-rw-r--r--3rdparty/bx/tests/uint32_test.cpp87
-rw-r--r--3rdparty/bx/tests/url_test.cpp4
-rw-r--r--3rdparty/bx/tests/vsnprintf_test.cpp151
-rwxr-xr-x[-rw-r--r--]3rdparty/bx/tools/bin/darwin/bin2cbin113544 -> 127496 bytes
-rwxr-xr-x3rdparty/bx/tools/bin/darwin/geniebin548784 -> 549032 bytes
-rwxr-xr-x[-rw-r--r--]3rdparty/bx/tools/bin/darwin/lemonbin95148 -> 95148 bytes
-rw-r--r--3rdparty/bx/tools/bin/darwin/lempar.c2
-rwxr-xr-x[-rw-r--r--]3rdparty/bx/tools/bin/darwin/ninjabin176588 -> 176588 bytes
-rwxr-xr-x[-rw-r--r--]3rdparty/bx/tools/bin/linux/bin2cbin68272 -> 96464 bytes
-rwxr-xr-x3rdparty/bx/tools/bin/linux/geniebin519776 -> 547720 bytes
-rwxr-xr-x[-rw-r--r--]3rdparty/bx/tools/bin/linux/lemonbin80952 -> 84728 bytes
-rw-r--r--3rdparty/bx/tools/bin/linux/lempar.c2
-rwxr-xr-x[-rw-r--r--]3rdparty/bx/tools/bin/linux/ninjabin175240 -> 175240 bytes
-rwxr-xr-x[-rw-r--r--]3rdparty/bx/tools/bin/windows/bin2c.exebin859136 -> 163328 bytes
-rw-r--r--3rdparty/bx/tools/bin/windows/genie.exebin525824 -> 551936 bytes
-rw-r--r--3rdparty/bx/tools/bin/windows/lemon.exebin99840 -> 104448 bytes
-rw-r--r--3rdparty/bx/tools/bin/windows/lempar.c2
-rwxr-xr-x[-rw-r--r--]3rdparty/bx/tools/bin/windows/ninja.exebin396800 -> 396800 bytes
-rw-r--r--3rdparty/bx/tools/bin2c/bin2c.cpp134
-rw-r--r--3rdparty/bx/tools/lemon/lemon.c6
-rw-r--r--3rdparty/bx/tools/lemon/lempar.c2
161 files changed, 33616 insertions, 14496 deletions
diff --git a/3rdparty/bx/.appveyor.yml b/3rdparty/bx/.appveyor.yml
index 001d04317b3..b0b107726f8 100644
--- a/3rdparty/bx/.appveyor.yml
+++ b/3rdparty/bx/.appveyor.yml
@@ -1,11 +1,12 @@
shallow_clone: true
os:
- - Visual Studio 2017
+ - Visual Studio 2019
environment:
matrix:
- TOOLSET: vs2017
+# - TOOLSET: vs2019
configuration:
- Debug
diff --git a/3rdparty/bx/.editorconfig b/3rdparty/bx/.editorconfig
index e9070240b79..3a55382bae2 100644
--- a/3rdparty/bx/.editorconfig
+++ b/3rdparty/bx/.editorconfig
@@ -1,9 +1,10 @@
root = true
[*]
-indent_style = tab
-indent_size = 4
-end_of_line = lf
+charset = utf-8
+indent_style = tab
+indent_size = 4
+end_of_line = lf
max_line_length = 100
insert_final_newline = true
trim_trailing_whitespace = true
diff --git a/3rdparty/bx/.travis.yml b/3rdparty/bx/.travis.yml
deleted file mode 100644
index 5f5538002bb..00000000000
--- a/3rdparty/bx/.travis.yml
+++ /dev/null
@@ -1,29 +0,0 @@
-language: cpp
-matrix:
- include:
- - compiler: gcc
- os: linux
- - compiler: clang
- os: osx
-
-addons:
- apt:
- sources:
- - ubuntu-toolchain-r-test
- packages:
- - gcc-5
- - g++-5
- - clang
-
-script:
- - if [ "$TRAVIS_OS_NAME" == "linux" ]; then make test CXX="g++-5" CC="gcc-5"; fi
- - if [ "$TRAVIS_OS_NAME" == "osx" ]; then make test; fi
-
-branches:
- only:
- - master
-
-notifications:
- email: false
-
-osx_image: xcode9.3
diff --git a/3rdparty/bx/3rdparty/catch/catch.hpp b/3rdparty/bx/3rdparty/catch/catch.hpp
deleted file mode 100644
index 2a09fd193a0..00000000000
--- a/3rdparty/bx/3rdparty/catch/catch.hpp
+++ /dev/null
@@ -1,11069 +0,0 @@
-/*
- * Catch v1.7.2
- * Generated: 2017-02-13 15:57:33.350226
- * ----------------------------------------------------------
- * This file has been merged from multiple headers. Please don't edit it directly
- * Copyright (c) 2012 Two Blue Cubes Ltd. All rights reserved.
- *
- * Distributed under the Boost Software License, Version 1.0. (See accompanying
- * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
- */
-#ifndef TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED
-#define TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED
-
-#define TWOBLUECUBES_CATCH_HPP_INCLUDED
-
-#ifdef __clang__
-# pragma clang system_header
-#elif defined __GNUC__
-# pragma GCC system_header
-#endif
-
-// #included from: internal/catch_suppress_warnings.h
-
-#ifdef __clang__
-# ifdef __ICC // icpc defines the __clang__ macro
-# pragma warning(push)
-# pragma warning(disable: 161 1682)
-# else // __ICC
-# pragma clang diagnostic ignored "-Wglobal-constructors"
-# pragma clang diagnostic ignored "-Wvariadic-macros"
-# pragma clang diagnostic ignored "-Wc99-extensions"
-# pragma clang diagnostic ignored "-Wunused-variable"
-# pragma clang diagnostic push
-# pragma clang diagnostic ignored "-Wpadded"
-# pragma clang diagnostic ignored "-Wc++98-compat"
-# pragma clang diagnostic ignored "-Wc++98-compat-pedantic"
-# pragma clang diagnostic ignored "-Wswitch-enum"
-# pragma clang diagnostic ignored "-Wcovered-switch-default"
-# endif
-#elif defined __GNUC__
-# pragma GCC diagnostic ignored "-Wvariadic-macros"
-# pragma GCC diagnostic ignored "-Wunused-variable"
-# pragma GCC diagnostic push
-# pragma GCC diagnostic ignored "-Wpadded"
-#endif
-#if defined(CATCH_CONFIG_MAIN) || defined(CATCH_CONFIG_RUNNER)
-# define CATCH_IMPL
-#endif
-
-#ifdef CATCH_IMPL
-# ifndef CLARA_CONFIG_MAIN
-# define CLARA_CONFIG_MAIN_NOT_DEFINED
-# define CLARA_CONFIG_MAIN
-# endif
-#endif
-
-// #included from: internal/catch_notimplemented_exception.h
-#define TWOBLUECUBES_CATCH_NOTIMPLEMENTED_EXCEPTION_H_INCLUDED
-
-// #included from: catch_common.h
-#define TWOBLUECUBES_CATCH_COMMON_H_INCLUDED
-
-// #included from: catch_compiler_capabilities.h
-#define TWOBLUECUBES_CATCH_COMPILER_CAPABILITIES_HPP_INCLUDED
-
-// Detect a number of compiler features - mostly C++11/14 conformance - by compiler
-// The following features are defined:
-//
-// CATCH_CONFIG_CPP11_NULLPTR : is nullptr supported?
-// CATCH_CONFIG_CPP11_NOEXCEPT : is noexcept supported?
-// CATCH_CONFIG_CPP11_GENERATED_METHODS : The delete and default keywords for compiler generated methods
-// CATCH_CONFIG_CPP11_IS_ENUM : std::is_enum is supported?
-// CATCH_CONFIG_CPP11_TUPLE : std::tuple is supported
-// CATCH_CONFIG_CPP11_LONG_LONG : is long long supported?
-// CATCH_CONFIG_CPP11_OVERRIDE : is override supported?
-// CATCH_CONFIG_CPP11_UNIQUE_PTR : is unique_ptr supported (otherwise use auto_ptr)
-// CATCH_CONFIG_CPP11_SHUFFLE : is std::shuffle supported?
-// CATCH_CONFIG_CPP11_TYPE_TRAITS : are type_traits and enable_if supported?
-
-// CATCH_CONFIG_CPP11_OR_GREATER : Is C++11 supported?
-
-// CATCH_CONFIG_VARIADIC_MACROS : are variadic macros supported?
-// CATCH_CONFIG_COUNTER : is the __COUNTER__ macro supported?
-// CATCH_CONFIG_WINDOWS_SEH : is Windows SEH supported?
-// ****************
-// Note to maintainers: if new toggles are added please document them
-// in configuration.md, too
-// ****************
-
-// In general each macro has a _NO_<feature name> form
-// (e.g. CATCH_CONFIG_CPP11_NO_NULLPTR) 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.
-
-// All the C++11 features can be disabled with CATCH_CONFIG_NO_CPP11
-
-#ifdef __cplusplus
-
-# if __cplusplus >= 201103L
-# define CATCH_CPP11_OR_GREATER
-# endif
-
-# if __cplusplus >= 201402L
-# define CATCH_CPP14_OR_GREATER
-# endif
-
-#endif
-
-#ifdef __clang__
-
-# if __has_feature(cxx_nullptr)
-# define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR
-# endif
-
-# if __has_feature(cxx_noexcept)
-# define CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT
-# endif
-
-# if defined(CATCH_CPP11_OR_GREATER)
-# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS _Pragma( "clang diagnostic ignored \"-Wparentheses\"" )
-# endif
-
-#endif // __clang__
-
-////////////////////////////////////////////////////////////////////////////////
-// Borland
-#ifdef __BORLANDC__
-
-#endif // __BORLANDC__
-
-////////////////////////////////////////////////////////////////////////////////
-// EDG
-#ifdef __EDG_VERSION__
-
-#endif // __EDG_VERSION__
-
-////////////////////////////////////////////////////////////////////////////////
-// Digital Mars
-#ifdef __DMC__
-
-#endif // __DMC__
-
-////////////////////////////////////////////////////////////////////////////////
-// GCC
-#ifdef __GNUC__
-
-# if __GNUC__ == 4 && __GNUC_MINOR__ >= 6 && defined(__GXX_EXPERIMENTAL_CXX0X__)
-# define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR
-# endif
-
-# if !defined(CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS) && defined(CATCH_CPP11_OR_GREATER)
-# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS _Pragma( "GCC diagnostic ignored \"-Wparentheses\"" )
-# endif
-
-// - otherwise more recent versions define __cplusplus >= 201103L
-// and will get picked up below
-
-#endif // __GNUC__
-
-////////////////////////////////////////////////////////////////////////////////
-// Visual C++
-#ifdef _MSC_VER
-
-#define CATCH_INTERNAL_CONFIG_WINDOWS_SEH
-
-#if (_MSC_VER >= 1600)
-# define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR
-# define CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR
-#endif
-
-#if (_MSC_VER >= 1900 ) // (VC++ 13 (VS2015))
-#define CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT
-#define CATCH_INTERNAL_CONFIG_CPP11_GENERATED_METHODS
-#define CATCH_INTERNAL_CONFIG_CPP11_SHUFFLE
-#define CATCH_INTERNAL_CONFIG_CPP11_TYPE_TRAITS
-#endif
-
-#endif // _MSC_VER
-
-////////////////////////////////////////////////////////////////////////////////
-
-// Use variadic macros if the compiler supports them
-#if ( defined _MSC_VER && _MSC_VER > 1400 && !defined __EDGE__) || \
- ( defined __WAVE__ && __WAVE_HAS_VARIADICS ) || \
- ( defined __GNUC__ && __GNUC__ >= 3 ) || \
- ( !defined __cplusplus && __STDC_VERSION__ >= 199901L || __cplusplus >= 201103L )
-
-#define CATCH_INTERNAL_CONFIG_VARIADIC_MACROS
-
-#endif
-
-// Use __COUNTER__ if the compiler supports it
-#if ( defined _MSC_VER && _MSC_VER >= 1300 ) || \
- ( defined __GNUC__ && __GNUC__ >= 4 && __GNUC_MINOR__ >= 3 ) || \
- ( defined __clang__ && __clang_major__ >= 3 )
-
-#define CATCH_INTERNAL_CONFIG_COUNTER
-
-#endif
-
-////////////////////////////////////////////////////////////////////////////////
-// C++ language feature support
-
-// catch all support for C++11
-#if defined(CATCH_CPP11_OR_GREATER)
-
-# if !defined(CATCH_INTERNAL_CONFIG_CPP11_NULLPTR)
-# define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR
-# endif
-
-# ifndef CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT
-# define CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT
-# endif
-
-# ifndef CATCH_INTERNAL_CONFIG_CPP11_GENERATED_METHODS
-# define CATCH_INTERNAL_CONFIG_CPP11_GENERATED_METHODS
-# endif
-
-# ifndef CATCH_INTERNAL_CONFIG_CPP11_IS_ENUM
-# define CATCH_INTERNAL_CONFIG_CPP11_IS_ENUM
-# endif
-
-# ifndef CATCH_INTERNAL_CONFIG_CPP11_TUPLE
-# define CATCH_INTERNAL_CONFIG_CPP11_TUPLE
-# endif
-
-# ifndef CATCH_INTERNAL_CONFIG_VARIADIC_MACROS
-# define CATCH_INTERNAL_CONFIG_VARIADIC_MACROS
-# endif
-
-# if !defined(CATCH_INTERNAL_CONFIG_CPP11_LONG_LONG)
-# define CATCH_INTERNAL_CONFIG_CPP11_LONG_LONG
-# endif
-
-# if !defined(CATCH_INTERNAL_CONFIG_CPP11_OVERRIDE)
-# define CATCH_INTERNAL_CONFIG_CPP11_OVERRIDE
-# endif
-# if !defined(CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR)
-# define CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR
-# endif
-# if !defined(CATCH_INTERNAL_CONFIG_CPP11_SHUFFLE)
-# define CATCH_INTERNAL_CONFIG_CPP11_SHUFFLE
-# endif
-# if !defined(CATCH_INTERNAL_CONFIG_CPP11_TYPE_TRAITS)
-# define CATCH_INTERNAL_CONFIG_CPP11_TYPE_TRAITS
-# endif
-
-#endif // __cplusplus >= 201103L
-
-// Now set the actual defines based on the above + anything the user has configured
-#if defined(CATCH_INTERNAL_CONFIG_CPP11_NULLPTR) && !defined(CATCH_CONFIG_CPP11_NO_NULLPTR) && !defined(CATCH_CONFIG_CPP11_NULLPTR) && !defined(CATCH_CONFIG_NO_CPP11)
-# define CATCH_CONFIG_CPP11_NULLPTR
-#endif
-#if defined(CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT) && !defined(CATCH_CONFIG_CPP11_NO_NOEXCEPT) && !defined(CATCH_CONFIG_CPP11_NOEXCEPT) && !defined(CATCH_CONFIG_NO_CPP11)
-# define CATCH_CONFIG_CPP11_NOEXCEPT
-#endif
-#if defined(CATCH_INTERNAL_CONFIG_CPP11_GENERATED_METHODS) && !defined(CATCH_CONFIG_CPP11_NO_GENERATED_METHODS) && !defined(CATCH_CONFIG_CPP11_GENERATED_METHODS) && !defined(CATCH_CONFIG_NO_CPP11)
-# define CATCH_CONFIG_CPP11_GENERATED_METHODS
-#endif
-#if defined(CATCH_INTERNAL_CONFIG_CPP11_IS_ENUM) && !defined(CATCH_CONFIG_CPP11_NO_IS_ENUM) && !defined(CATCH_CONFIG_CPP11_IS_ENUM) && !defined(CATCH_CONFIG_NO_CPP11)
-# define CATCH_CONFIG_CPP11_IS_ENUM
-#endif
-#if defined(CATCH_INTERNAL_CONFIG_CPP11_TUPLE) && !defined(CATCH_CONFIG_CPP11_NO_TUPLE) && !defined(CATCH_CONFIG_CPP11_TUPLE) && !defined(CATCH_CONFIG_NO_CPP11)
-# define CATCH_CONFIG_CPP11_TUPLE
-#endif
-#if defined(CATCH_INTERNAL_CONFIG_VARIADIC_MACROS) && !defined(CATCH_CONFIG_NO_VARIADIC_MACROS) && !defined(CATCH_CONFIG_VARIADIC_MACROS)
-# define CATCH_CONFIG_VARIADIC_MACROS
-#endif
-#if defined(CATCH_INTERNAL_CONFIG_CPP11_LONG_LONG) && !defined(CATCH_CONFIG_CPP11_NO_LONG_LONG) && !defined(CATCH_CONFIG_CPP11_LONG_LONG) && !defined(CATCH_CONFIG_NO_CPP11)
-# define CATCH_CONFIG_CPP11_LONG_LONG
-#endif
-#if defined(CATCH_INTERNAL_CONFIG_CPP11_OVERRIDE) && !defined(CATCH_CONFIG_CPP11_NO_OVERRIDE) && !defined(CATCH_CONFIG_CPP11_OVERRIDE) && !defined(CATCH_CONFIG_NO_CPP11)
-# define CATCH_CONFIG_CPP11_OVERRIDE
-#endif
-#if defined(CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR) && !defined(CATCH_CONFIG_CPP11_NO_UNIQUE_PTR) && !defined(CATCH_CONFIG_CPP11_UNIQUE_PTR) && !defined(CATCH_CONFIG_NO_CPP11)
-# define CATCH_CONFIG_CPP11_UNIQUE_PTR
-#endif
-// Use of __COUNTER__ is suppressed if __JETBRAINS_IDE__ is #defined (meaning we're being parsed by a JetBrains IDE for
-// analytics) because, at time of writing, __COUNTER__ is not properly handled by it.
-// This does not affect compilation
-#if defined(CATCH_INTERNAL_CONFIG_COUNTER) && !defined(CATCH_CONFIG_NO_COUNTER) && !defined(CATCH_CONFIG_COUNTER) && !defined(__JETBRAINS_IDE__)
-# define CATCH_CONFIG_COUNTER
-#endif
-#if defined(CATCH_INTERNAL_CONFIG_CPP11_SHUFFLE) && !defined(CATCH_CONFIG_CPP11_NO_SHUFFLE) && !defined(CATCH_CONFIG_CPP11_SHUFFLE) && !defined(CATCH_CONFIG_NO_CPP11)
-# define CATCH_CONFIG_CPP11_SHUFFLE
-#endif
-# if defined(CATCH_INTERNAL_CONFIG_CPP11_TYPE_TRAITS) && !defined(CATCH_CONFIG_CPP11_NO_TYPE_TRAITS) && !defined(CATCH_CONFIG_CPP11_TYPE_TRAITS) && !defined(CATCH_CONFIG_NO_CPP11)
-# define CATCH_CONFIG_CPP11_TYPE_TRAITS
-# endif
-#if defined(CATCH_INTERNAL_CONFIG_WINDOWS_SEH) && !defined(CATCH_CONFIG_NO_WINDOWS_SEH) && !defined(CATCH_CONFIG_WINDOWS_SEH)
-# define CATCH_CONFIG_WINDOWS_SEH
-#endif
-
-#if !defined(CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS)
-# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS
-#endif
-
-// noexcept support:
-#if defined(CATCH_CONFIG_CPP11_NOEXCEPT) && !defined(CATCH_NOEXCEPT)
-# define CATCH_NOEXCEPT noexcept
-# define CATCH_NOEXCEPT_IS(x) noexcept(x)
-#else
-# define CATCH_NOEXCEPT throw()
-# define CATCH_NOEXCEPT_IS(x)
-#endif
-
-// nullptr support
-#ifdef CATCH_CONFIG_CPP11_NULLPTR
-# define CATCH_NULL nullptr
-#else
-# define CATCH_NULL NULL
-#endif
-
-// override support
-#ifdef CATCH_CONFIG_CPP11_OVERRIDE
-# define CATCH_OVERRIDE override
-#else
-# define CATCH_OVERRIDE
-#endif
-
-// unique_ptr support
-#ifdef CATCH_CONFIG_CPP11_UNIQUE_PTR
-# define CATCH_AUTO_PTR( T ) std::unique_ptr<T>
-#else
-# define CATCH_AUTO_PTR( T ) std::auto_ptr<T>
-#endif
-
-#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
-
-#define INTERNAL_CATCH_STRINGIFY2( expr ) #expr
-#define INTERNAL_CATCH_STRINGIFY( expr ) INTERNAL_CATCH_STRINGIFY2( expr )
-
-#include <sstream>
-#include <algorithm>
-
-namespace Catch {
-
- struct IConfig;
-
- struct CaseSensitive { enum Choice {
- Yes,
- No
- }; };
-
- class NonCopyable {
-#ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS
- NonCopyable( NonCopyable const& ) = delete;
- NonCopyable( NonCopyable && ) = delete;
- NonCopyable& operator = ( NonCopyable const& ) = delete;
- NonCopyable& operator = ( NonCopyable && ) = delete;
-#else
- NonCopyable( NonCopyable const& info );
- NonCopyable& operator = ( NonCopyable const& );
-#endif
-
- protected:
- NonCopyable() {}
- virtual ~NonCopyable();
- };
-
- class SafeBool {
- public:
- typedef void (SafeBool::*type)() const;
-
- static type makeSafe( bool value ) {
- return value ? &SafeBool::trueValue : 0;
- }
- private:
- void trueValue() const {}
- };
-
- template<typename ContainerT>
- inline void deleteAll( ContainerT& container ) {
- typename ContainerT::const_iterator it = container.begin();
- typename ContainerT::const_iterator itEnd = container.end();
- for(; it != itEnd; ++it )
- delete *it;
- }
- template<typename AssociativeContainerT>
- inline void deleteAllValues( AssociativeContainerT& container ) {
- typename AssociativeContainerT::const_iterator it = container.begin();
- typename AssociativeContainerT::const_iterator itEnd = container.end();
- for(; it != itEnd; ++it )
- delete it->second;
- }
-
- bool startsWith( std::string const& s, std::string const& prefix );
- bool startsWith( std::string const& s, char prefix );
- bool endsWith( std::string const& s, std::string const& suffix );
- bool endsWith( std::string const& s, char suffix );
- bool contains( std::string const& s, std::string const& infix );
- void toLowerInPlace( std::string& s );
- std::string toLower( std::string const& s );
- std::string trim( std::string const& str );
- bool replaceInPlace( std::string& str, std::string const& replaceThis, std::string const& withThis );
-
- struct pluralise {
- pluralise( std::size_t count, std::string const& label );
-
- friend std::ostream& operator << ( std::ostream& os, pluralise const& pluraliser );
-
- std::size_t m_count;
- std::string m_label;
- };
-
- struct SourceLineInfo {
-
- SourceLineInfo();
- SourceLineInfo( char const* _file, std::size_t _line );
-# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS
- SourceLineInfo(SourceLineInfo const& other) = default;
- SourceLineInfo( SourceLineInfo && ) = default;
- SourceLineInfo& operator = ( SourceLineInfo const& ) = default;
- SourceLineInfo& operator = ( SourceLineInfo && ) = default;
-# endif
- bool empty() const;
- bool operator == ( SourceLineInfo const& other ) const;
- bool operator < ( SourceLineInfo const& other ) const;
-
- char const* file;
- std::size_t line;
- };
-
- std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info );
-
- // This is just here to avoid compiler warnings with macro constants and boolean literals
- inline bool isTrue( bool value ){ return value; }
- inline bool alwaysTrue() { return true; }
- inline bool alwaysFalse() { return false; }
-
- void throwLogicError( std::string const& message, SourceLineInfo const& locationInfo );
-
- void seedRng( IConfig const& config );
- unsigned int rngSeed();
-
- // Use this in variadic streaming macros to allow
- // >> +StreamEndStop
- // as well as
- // >> stuff +StreamEndStop
- struct StreamEndStop {
- std::string operator+() {
- return std::string();
- }
- };
- template<typename T>
- T const& operator + ( T const& value, StreamEndStop ) {
- return value;
- }
-}
-
-#define CATCH_INTERNAL_LINEINFO ::Catch::SourceLineInfo( __FILE__, static_cast<std::size_t>( __LINE__ ) )
-#define CATCH_INTERNAL_ERROR( msg ) ::Catch::throwLogicError( msg, CATCH_INTERNAL_LINEINFO );
-
-namespace Catch {
-
- class NotImplementedException : public std::exception
- {
- public:
- NotImplementedException( SourceLineInfo const& lineInfo );
- NotImplementedException( NotImplementedException const& ) {}
-
- virtual ~NotImplementedException() CATCH_NOEXCEPT {}
-
- virtual const char* what() const CATCH_NOEXCEPT;
-
- private:
- std::string m_what;
- SourceLineInfo m_lineInfo;
- };
-
-} // end namespace Catch
-
-///////////////////////////////////////////////////////////////////////////////
-#define CATCH_NOT_IMPLEMENTED throw Catch::NotImplementedException( CATCH_INTERNAL_LINEINFO )
-
-// #included from: internal/catch_context.h
-#define TWOBLUECUBES_CATCH_CONTEXT_H_INCLUDED
-
-// #included from: catch_interfaces_generators.h
-#define TWOBLUECUBES_CATCH_INTERFACES_GENERATORS_H_INCLUDED
-
-#include <string>
-
-namespace Catch {
-
- struct IGeneratorInfo {
- virtual ~IGeneratorInfo();
- virtual bool moveNext() = 0;
- virtual std::size_t getCurrentIndex() const = 0;
- };
-
- struct IGeneratorsForTest {
- virtual ~IGeneratorsForTest();
-
- virtual IGeneratorInfo& getGeneratorInfo( std::string const& fileInfo, std::size_t size ) = 0;
- virtual bool moveNext() = 0;
- };
-
- IGeneratorsForTest* createGeneratorsForTest();
-
-} // end namespace Catch
-
-// #included from: catch_ptr.hpp
-#define TWOBLUECUBES_CATCH_PTR_HPP_INCLUDED
-
-#ifdef __clang__
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wpadded"
-#endif
-
-namespace Catch {
-
- // An intrusive reference counting smart pointer.
- // T must implement addRef() and release() methods
- // typically implementing the IShared interface
- template<typename T>
- class Ptr {
- public:
- Ptr() : m_p( CATCH_NULL ){}
- Ptr( T* p ) : m_p( p ){
- if( m_p )
- m_p->addRef();
- }
- Ptr( Ptr const& other ) : m_p( other.m_p ){
- if( m_p )
- m_p->addRef();
- }
- ~Ptr(){
- if( m_p )
- m_p->release();
- }
- void reset() {
- if( m_p )
- m_p->release();
- m_p = CATCH_NULL;
- }
- Ptr& operator = ( T* p ){
- Ptr temp( p );
- swap( temp );
- return *this;
- }
- Ptr& operator = ( Ptr const& other ){
- Ptr temp( other );
- swap( temp );
- return *this;
- }
- void swap( Ptr& other ) { std::swap( m_p, other.m_p ); }
- T* get() const{ return m_p; }
- T& operator*() const { return *m_p; }
- T* operator->() const { return m_p; }
- bool operator !() const { return m_p == CATCH_NULL; }
- operator SafeBool::type() const { return SafeBool::makeSafe( m_p != CATCH_NULL ); }
-
- private:
- T* m_p;
- };
-
- struct IShared : NonCopyable {
- virtual ~IShared();
- virtual void addRef() const = 0;
- virtual void release() const = 0;
- };
-
- template<typename T = IShared>
- struct SharedImpl : T {
-
- SharedImpl() : m_rc( 0 ){}
-
- virtual void addRef() const {
- ++m_rc;
- }
- virtual void release() const {
- if( --m_rc == 0 )
- delete this;
- }
-
- mutable unsigned int m_rc;
- };
-
-} // end namespace Catch
-
-#ifdef __clang__
-#pragma clang diagnostic pop
-#endif
-
-namespace Catch {
-
- class TestCase;
- class Stream;
- struct IResultCapture;
- struct IRunner;
- struct IGeneratorsForTest;
- struct IConfig;
-
- struct IContext
- {
- virtual ~IContext();
-
- virtual IResultCapture* getResultCapture() = 0;
- virtual IRunner* getRunner() = 0;
- virtual size_t getGeneratorIndex( std::string const& fileInfo, size_t totalSize ) = 0;
- virtual bool advanceGeneratorsForCurrentTest() = 0;
- virtual Ptr<IConfig const> getConfig() const = 0;
- };
-
- struct IMutableContext : IContext
- {
- virtual ~IMutableContext();
- virtual void setResultCapture( IResultCapture* resultCapture ) = 0;
- virtual void setRunner( IRunner* runner ) = 0;
- virtual void setConfig( Ptr<IConfig const> const& config ) = 0;
- };
-
- IContext& getCurrentContext();
- IMutableContext& getCurrentMutableContext();
- void cleanUpContext();
- Stream createStream( std::string const& streamName );
-
-}
-
-// #included from: internal/catch_test_registry.hpp
-#define TWOBLUECUBES_CATCH_TEST_REGISTRY_HPP_INCLUDED
-
-// #included from: catch_interfaces_testcase.h
-#define TWOBLUECUBES_CATCH_INTERFACES_TESTCASE_H_INCLUDED
-
-#include <vector>
-
-namespace Catch {
-
- class TestSpec;
-
- struct ITestCase : IShared {
- virtual void invoke () const = 0;
- protected:
- virtual ~ITestCase();
- };
-
- class TestCase;
- struct IConfig;
-
- struct ITestCaseRegistry {
- virtual ~ITestCaseRegistry();
- virtual std::vector<TestCase> const& getAllTests() const = 0;
- virtual std::vector<TestCase> const& getAllTestsSorted( IConfig const& config ) const = 0;
- };
-
- bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config );
- std::vector<TestCase> filterTests( std::vector<TestCase> const& testCases, TestSpec const& testSpec, IConfig const& config );
- std::vector<TestCase> const& getAllTestCasesSorted( IConfig const& config );
-
-}
-
-namespace Catch {
-
-template<typename C>
-class MethodTestCase : public SharedImpl<ITestCase> {
-
-public:
- MethodTestCase( void (C::*method)() ) : m_method( method ) {}
-
- virtual void invoke() const {
- C obj;
- (obj.*m_method)();
- }
-
-private:
- virtual ~MethodTestCase() {}
-
- void (C::*m_method)();
-};
-
-typedef void(*TestFunction)();
-
-struct NameAndDesc {
- NameAndDesc( const char* _name = "", const char* _description= "" )
- : name( _name ), description( _description )
- {}
-
- const char* name;
- const char* description;
-};
-
-void registerTestCase
- ( ITestCase* testCase,
- char const* className,
- NameAndDesc const& nameAndDesc,
- SourceLineInfo const& lineInfo );
-
-struct AutoReg {
-
- AutoReg
- ( TestFunction function,
- SourceLineInfo const& lineInfo,
- NameAndDesc const& nameAndDesc );
-
- template<typename C>
- AutoReg
- ( void (C::*method)(),
- char const* className,
- NameAndDesc const& nameAndDesc,
- SourceLineInfo const& lineInfo ) {
-
- registerTestCase
- ( new MethodTestCase<C>( method ),
- className,
- nameAndDesc,
- lineInfo );
- }
-
- ~AutoReg();
-
-private:
- AutoReg( AutoReg const& );
- void operator= ( AutoReg const& );
-};
-
-void registerTestCaseFunction
- ( TestFunction function,
- SourceLineInfo const& lineInfo,
- NameAndDesc const& nameAndDesc );
-
-} // end namespace Catch
-
-#ifdef CATCH_CONFIG_VARIADIC_MACROS
- ///////////////////////////////////////////////////////////////////////////////
- #define INTERNAL_CATCH_TESTCASE2( TestName, ... ) \
- static void TestName(); \
- namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &TestName, CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( __VA_ARGS__ ) ); }\
- static void TestName()
- #define INTERNAL_CATCH_TESTCASE( ... ) \
- INTERNAL_CATCH_TESTCASE2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), __VA_ARGS__ )
-
- ///////////////////////////////////////////////////////////////////////////////
- #define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, ... ) \
- namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &QualifiedMethod, "&" #QualifiedMethod, Catch::NameAndDesc( __VA_ARGS__ ), CATCH_INTERNAL_LINEINFO ); }
-
- ///////////////////////////////////////////////////////////////////////////////
- #define INTERNAL_CATCH_TEST_CASE_METHOD2( TestName, ClassName, ... )\
- namespace{ \
- struct TestName : ClassName{ \
- void test(); \
- }; \
- Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( &TestName::test, #ClassName, Catch::NameAndDesc( __VA_ARGS__ ), CATCH_INTERNAL_LINEINFO ); \
- } \
- void TestName::test()
- #define INTERNAL_CATCH_TEST_CASE_METHOD( ClassName, ... ) \
- INTERNAL_CATCH_TEST_CASE_METHOD2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), ClassName, __VA_ARGS__ )
-
- ///////////////////////////////////////////////////////////////////////////////
- #define INTERNAL_CATCH_REGISTER_TESTCASE( Function, ... ) \
- Catch::AutoReg( Function, CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( __VA_ARGS__ ) );
-
-#else
- ///////////////////////////////////////////////////////////////////////////////
- #define INTERNAL_CATCH_TESTCASE2( TestName, Name, Desc ) \
- static void TestName(); \
- namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &TestName, CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( Name, Desc ) ); }\
- static void TestName()
- #define INTERNAL_CATCH_TESTCASE( Name, Desc ) \
- INTERNAL_CATCH_TESTCASE2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), Name, Desc )
-
- ///////////////////////////////////////////////////////////////////////////////
- #define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, Name, Desc ) \
- namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &QualifiedMethod, "&" #QualifiedMethod, Catch::NameAndDesc( Name, Desc ), CATCH_INTERNAL_LINEINFO ); }
-
- ///////////////////////////////////////////////////////////////////////////////
- #define INTERNAL_CATCH_TEST_CASE_METHOD2( TestCaseName, ClassName, TestName, Desc )\
- namespace{ \
- struct TestCaseName : ClassName{ \
- void test(); \
- }; \
- Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( &TestCaseName::test, #ClassName, Catch::NameAndDesc( TestName, Desc ), CATCH_INTERNAL_LINEINFO ); \
- } \
- void TestCaseName::test()
- #define INTERNAL_CATCH_TEST_CASE_METHOD( ClassName, TestName, Desc )\
- INTERNAL_CATCH_TEST_CASE_METHOD2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), ClassName, TestName, Desc )
-
- ///////////////////////////////////////////////////////////////////////////////
- #define INTERNAL_CATCH_REGISTER_TESTCASE( Function, Name, Desc ) \
- Catch::AutoReg( Function, CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( Name, Desc ) );
-#endif
-
-// #included from: internal/catch_capture.hpp
-#define TWOBLUECUBES_CATCH_CAPTURE_HPP_INCLUDED
-
-// #included from: catch_result_builder.h
-#define TWOBLUECUBES_CATCH_RESULT_BUILDER_H_INCLUDED
-
-// #included from: catch_result_type.h
-#define TWOBLUECUBES_CATCH_RESULT_TYPE_H_INCLUDED
-
-namespace Catch {
-
- // 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
-
- }; };
-
- inline bool isOk( ResultWas::OfType resultType ) {
- return ( resultType & ResultWas::FailureBit ) == 0;
- }
- inline bool isJustInfo( int flags ) {
- return flags == ResultWas::Info;
- }
-
- // 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
- }; };
-
- inline ResultDisposition::Flags operator | ( ResultDisposition::Flags lhs, ResultDisposition::Flags rhs ) {
- return static_cast<ResultDisposition::Flags>( static_cast<int>( lhs ) | static_cast<int>( rhs ) );
- }
-
- inline bool shouldContinueOnFailure( int flags ) { return ( flags & ResultDisposition::ContinueOnFailure ) != 0; }
- inline bool isFalseTest( int flags ) { return ( flags & ResultDisposition::FalseTest ) != 0; }
- inline bool shouldSuppressFailure( int flags ) { return ( flags & ResultDisposition::SuppressFail ) != 0; }
-
-} // end namespace Catch
-
-// #included from: catch_assertionresult.h
-#define TWOBLUECUBES_CATCH_ASSERTIONRESULT_H_INCLUDED
-
-#include <string>
-
-namespace Catch {
-
- struct STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison;
-
- struct DecomposedExpression
- {
- virtual ~DecomposedExpression() {}
- virtual bool isBinaryExpression() const {
- return false;
- }
- virtual void reconstructExpression( std::string& dest ) const = 0;
-
- // Only simple binary comparisons can be decomposed.
- // If more complex check is required then wrap sub-expressions in parentheses.
- template<typename T> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator + ( T const& );
- template<typename T> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator - ( T const& );
- template<typename T> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator * ( T const& );
- template<typename T> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator / ( T const& );
- template<typename T> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator % ( T const& );
- template<typename T> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator && ( T const& );
- template<typename T> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator || ( T const& );
- };
-
- struct AssertionInfo
- {
- AssertionInfo() {}
- AssertionInfo( std::string const& _macroName,
- SourceLineInfo const& _lineInfo,
- std::string const& _capturedExpression,
- ResultDisposition::Flags _resultDisposition );
-
- std::string macroName;
- SourceLineInfo lineInfo;
- std::string capturedExpression;
- ResultDisposition::Flags resultDisposition;
- };
-
- struct AssertionResultData
- {
- AssertionResultData() : decomposedExpression( CATCH_NULL )
- , resultType( ResultWas::Unknown )
- , negated( false )
- , parenthesized( false ) {}
-
- void negate( bool parenthesize ) {
- negated = !negated;
- parenthesized = parenthesize;
- if( resultType == ResultWas::Ok )
- resultType = ResultWas::ExpressionFailed;
- else if( resultType == ResultWas::ExpressionFailed )
- resultType = ResultWas::Ok;
- }
-
- std::string const& reconstructExpression() const {
- if( decomposedExpression != CATCH_NULL ) {
- decomposedExpression->reconstructExpression( reconstructedExpression );
- if( parenthesized ) {
- reconstructedExpression.insert( 0, 1, '(' );
- reconstructedExpression.append( 1, ')' );
- }
- if( negated ) {
- reconstructedExpression.insert( 0, 1, '!' );
- }
- decomposedExpression = CATCH_NULL;
- }
- return reconstructedExpression;
- }
-
- mutable DecomposedExpression const* decomposedExpression;
- mutable std::string reconstructedExpression;
- std::string message;
- ResultWas::OfType resultType;
- bool negated;
- bool parenthesized;
- };
-
- class AssertionResult {
- public:
- AssertionResult();
- AssertionResult( AssertionInfo const& info, AssertionResultData const& data );
- ~AssertionResult();
-# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS
- AssertionResult( AssertionResult const& ) = default;
- AssertionResult( AssertionResult && ) = default;
- AssertionResult& operator = ( AssertionResult const& ) = default;
- AssertionResult& operator = ( AssertionResult && ) = default;
-# endif
-
- 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;
- std::string getMessage() const;
- SourceLineInfo getSourceInfo() const;
- std::string getTestMacroName() const;
- void discardDecomposedExpression() const;
- void expandDecomposedExpression() const;
-
- protected:
- AssertionInfo m_info;
- AssertionResultData m_resultData;
- };
-
-} // end namespace Catch
-
-// #included from: catch_matchers.hpp
-#define TWOBLUECUBES_CATCH_MATCHERS_HPP_INCLUDED
-
-namespace Catch {
-namespace Matchers {
- namespace Impl {
-
- namespace Generic {
- template<typename ExpressionT> class AllOf;
- template<typename ExpressionT> class AnyOf;
- template<typename ExpressionT> class Not;
- }
-
- template<typename ExpressionT>
- struct Matcher : SharedImpl<IShared>
- {
- typedef ExpressionT ExpressionType;
-
- virtual ~Matcher() {}
- virtual Ptr<Matcher> clone() const = 0;
- virtual bool match( ExpressionT const& expr ) const = 0;
- virtual std::string toString() const = 0;
-
- Generic::AllOf<ExpressionT> operator && ( Matcher<ExpressionT> const& other ) const;
- Generic::AnyOf<ExpressionT> operator || ( Matcher<ExpressionT> const& other ) const;
- Generic::Not<ExpressionT> operator ! () const;
- };
-
- template<typename DerivedT, typename ExpressionT>
- struct MatcherImpl : Matcher<ExpressionT> {
-
- virtual Ptr<Matcher<ExpressionT> > clone() const {
- return Ptr<Matcher<ExpressionT> >( new DerivedT( static_cast<DerivedT const&>( *this ) ) );
- }
- };
-
- namespace Generic {
- template<typename ExpressionT>
- class Not : public MatcherImpl<Not<ExpressionT>, ExpressionT> {
- public:
- explicit Not( Matcher<ExpressionT> const& matcher ) : m_matcher(matcher.clone()) {}
- Not( Not const& other ) : m_matcher( other.m_matcher ) {}
-
- virtual bool match( ExpressionT const& expr ) const CATCH_OVERRIDE {
- return !m_matcher->match( expr );
- }
-
- virtual std::string toString() const CATCH_OVERRIDE {
- return "not " + m_matcher->toString();
- }
- private:
- Ptr< Matcher<ExpressionT> > m_matcher;
- };
-
- template<typename ExpressionT>
- class AllOf : public MatcherImpl<AllOf<ExpressionT>, ExpressionT> {
- public:
-
- AllOf() {}
- AllOf( AllOf const& other ) : m_matchers( other.m_matchers ) {}
-
- AllOf& add( Matcher<ExpressionT> const& matcher ) {
- m_matchers.push_back( matcher.clone() );
- return *this;
- }
- virtual bool match( ExpressionT const& expr ) const
- {
- for( std::size_t i = 0; i < m_matchers.size(); ++i )
- if( !m_matchers[i]->match( expr ) )
- return false;
- return true;
- }
- virtual std::string toString() const {
- std::ostringstream oss;
- oss << "( ";
- for( std::size_t i = 0; i < m_matchers.size(); ++i ) {
- if( i != 0 )
- oss << " and ";
- oss << m_matchers[i]->toString();
- }
- oss << " )";
- return oss.str();
- }
-
- AllOf operator && ( Matcher<ExpressionT> const& other ) const {
- AllOf allOfExpr( *this );
- allOfExpr.add( other );
- return allOfExpr;
- }
-
- private:
- std::vector<Ptr<Matcher<ExpressionT> > > m_matchers;
- };
-
- template<typename ExpressionT>
- class AnyOf : public MatcherImpl<AnyOf<ExpressionT>, ExpressionT> {
- public:
-
- AnyOf() {}
- AnyOf( AnyOf const& other ) : m_matchers( other.m_matchers ) {}
-
- AnyOf& add( Matcher<ExpressionT> const& matcher ) {
- m_matchers.push_back( matcher.clone() );
- return *this;
- }
- virtual bool match( ExpressionT const& expr ) const
- {
- for( std::size_t i = 0; i < m_matchers.size(); ++i )
- if( m_matchers[i]->match( expr ) )
- return true;
- return false;
- }
- virtual std::string toString() const {
- std::ostringstream oss;
- oss << "( ";
- for( std::size_t i = 0; i < m_matchers.size(); ++i ) {
- if( i != 0 )
- oss << " or ";
- oss << m_matchers[i]->toString();
- }
- oss << " )";
- return oss.str();
- }
-
- AnyOf operator || ( Matcher<ExpressionT> const& other ) const {
- AnyOf anyOfExpr( *this );
- anyOfExpr.add( other );
- return anyOfExpr;
- }
-
- private:
- std::vector<Ptr<Matcher<ExpressionT> > > m_matchers;
- };
-
- } // namespace Generic
-
- template<typename ExpressionT>
- Generic::AllOf<ExpressionT> Matcher<ExpressionT>::operator && ( Matcher<ExpressionT> const& other ) const {
- Generic::AllOf<ExpressionT> allOfExpr;
- allOfExpr.add( *this );
- allOfExpr.add( other );
- return allOfExpr;
- }
-
- template<typename ExpressionT>
- Generic::AnyOf<ExpressionT> Matcher<ExpressionT>::operator || ( Matcher<ExpressionT> const& other ) const {
- Generic::AnyOf<ExpressionT> anyOfExpr;
- anyOfExpr.add( *this );
- anyOfExpr.add( other );
- return anyOfExpr;
- }
-
- template<typename ExpressionT>
- Generic::Not<ExpressionT> Matcher<ExpressionT>::operator ! () const {
- return Generic::Not<ExpressionT>( *this );
- }
-
- namespace StdString {
-
- inline std::string makeString( std::string const& str ) { return str; }
- inline std::string makeString( const char* str ) { return str ? std::string( str ) : std::string(); }
-
- struct CasedString
- {
- CasedString( std::string const& str, CaseSensitive::Choice caseSensitivity )
- : m_caseSensitivity( caseSensitivity ),
- m_str( adjustString( str ) )
- {}
- std::string adjustString( std::string const& str ) const {
- return m_caseSensitivity == CaseSensitive::No
- ? toLower( str )
- : str;
-
- }
- std::string toStringSuffix() const
- {
- return m_caseSensitivity == CaseSensitive::No
- ? " (case insensitive)"
- : std::string();
- }
- CaseSensitive::Choice m_caseSensitivity;
- std::string m_str;
- };
-
- struct Equals : MatcherImpl<Equals, std::string> {
- Equals( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes )
- : m_data( str, caseSensitivity )
- {}
- Equals( Equals const& other ) : m_data( other.m_data ){}
-
- virtual ~Equals();
-
- virtual bool match( std::string const& expr ) const {
- return m_data.m_str == m_data.adjustString( expr );;
- }
- virtual std::string toString() const {
- return "equals: \"" + m_data.m_str + '"' + m_data.toStringSuffix();
- }
-
- CasedString m_data;
- };
-
- struct Contains : MatcherImpl<Contains, std::string> {
- Contains( std::string const& substr, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes )
- : m_data( substr, caseSensitivity ){}
- Contains( Contains const& other ) : m_data( other.m_data ){}
-
- virtual ~Contains();
-
- virtual bool match( std::string const& expr ) const {
- return m_data.adjustString( expr ).find( m_data.m_str ) != std::string::npos;
- }
- virtual std::string toString() const {
- return "contains: \"" + m_data.m_str + '"' + m_data.toStringSuffix();
- }
-
- CasedString m_data;
- };
-
- struct StartsWith : MatcherImpl<StartsWith, std::string> {
- StartsWith( std::string const& substr, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes )
- : m_data( substr, caseSensitivity ){}
-
- StartsWith( StartsWith const& other ) : m_data( other.m_data ){}
-
- virtual ~StartsWith();
-
- virtual bool match( std::string const& expr ) const {
- return startsWith( m_data.adjustString( expr ), m_data.m_str );
- }
- virtual std::string toString() const {
- return "starts with: \"" + m_data.m_str + '"' + m_data.toStringSuffix();
- }
-
- CasedString m_data;
- };
-
- struct EndsWith : MatcherImpl<EndsWith, std::string> {
- EndsWith( std::string const& substr, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes )
- : m_data( substr, caseSensitivity ){}
- EndsWith( EndsWith const& other ) : m_data( other.m_data ){}
-
- virtual ~EndsWith();
-
- virtual bool match( std::string const& expr ) const {
- return endsWith( m_data.adjustString( expr ), m_data.m_str );
- }
- virtual std::string toString() const {
- return "ends with: \"" + m_data.m_str + '"' + m_data.toStringSuffix();
- }
-
- CasedString m_data;
- };
- } // namespace StdString
- } // namespace Impl
-
- // The following functions create the actual matcher objects.
- // This allows the types to be inferred
- template<typename ExpressionT>
- inline Impl::Generic::Not<ExpressionT> Not( Impl::Matcher<ExpressionT> const& m ) {
- return Impl::Generic::Not<ExpressionT>( m );
- }
-
- template<typename ExpressionT>
- inline Impl::Generic::AllOf<ExpressionT> AllOf( Impl::Matcher<ExpressionT> const& m1,
- Impl::Matcher<ExpressionT> const& m2 ) {
- return Impl::Generic::AllOf<ExpressionT>().add( m1 ).add( m2 );
- }
- template<typename ExpressionT>
- inline Impl::Generic::AllOf<ExpressionT> AllOf( Impl::Matcher<ExpressionT> const& m1,
- Impl::Matcher<ExpressionT> const& m2,
- Impl::Matcher<ExpressionT> const& m3 ) {
- return Impl::Generic::AllOf<ExpressionT>().add( m1 ).add( m2 ).add( m3 );
- }
- template<typename ExpressionT>
- inline Impl::Generic::AnyOf<ExpressionT> AnyOf( Impl::Matcher<ExpressionT> const& m1,
- Impl::Matcher<ExpressionT> const& m2 ) {
- return Impl::Generic::AnyOf<ExpressionT>().add( m1 ).add( m2 );
- }
- template<typename ExpressionT>
- inline Impl::Generic::AnyOf<ExpressionT> AnyOf( Impl::Matcher<ExpressionT> const& m1,
- Impl::Matcher<ExpressionT> const& m2,
- Impl::Matcher<ExpressionT> const& m3 ) {
- return Impl::Generic::AnyOf<ExpressionT>().add( m1 ).add( m2 ).add( m3 );
- }
-
- inline Impl::StdString::Equals Equals( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) {
- return Impl::StdString::Equals( str, caseSensitivity );
- }
- inline Impl::StdString::Equals Equals( const char* str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) {
- return Impl::StdString::Equals( Impl::StdString::makeString( str ), caseSensitivity );
- }
- inline Impl::StdString::Contains Contains( std::string const& substr, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) {
- return Impl::StdString::Contains( substr, caseSensitivity );
- }
- inline Impl::StdString::Contains Contains( const char* substr, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) {
- return Impl::StdString::Contains( Impl::StdString::makeString( substr ), caseSensitivity );
- }
- inline Impl::StdString::StartsWith StartsWith( std::string const& substr ) {
- return Impl::StdString::StartsWith( substr );
- }
- inline Impl::StdString::StartsWith StartsWith( const char* substr ) {
- return Impl::StdString::StartsWith( Impl::StdString::makeString( substr ) );
- }
- inline Impl::StdString::EndsWith EndsWith( std::string const& substr ) {
- return Impl::StdString::EndsWith( substr );
- }
- inline Impl::StdString::EndsWith EndsWith( const char* substr ) {
- return Impl::StdString::EndsWith( Impl::StdString::makeString( substr ) );
- }
-
-} // namespace Matchers
-
-using namespace Matchers;
-
-} // namespace Catch
-
-namespace Catch {
-
- struct TestFailureException{};
-
- template<typename T> class ExpressionLhs;
-
- struct CopyableStream {
- CopyableStream() {}
- CopyableStream( CopyableStream const& other ) {
- oss << other.oss.str();
- }
- CopyableStream& operator=( CopyableStream const& other ) {
- oss.str(std::string());
- oss << other.oss.str();
- return *this;
- }
- std::ostringstream oss;
- };
-
- class ResultBuilder : public DecomposedExpression {
- public:
- ResultBuilder( char const* macroName,
- SourceLineInfo const& lineInfo,
- char const* capturedExpression,
- ResultDisposition::Flags resultDisposition,
- char const* secondArg = "" );
-
- template<typename T>
- ExpressionLhs<T const&> operator <= ( T const& operand );
- ExpressionLhs<bool> operator <= ( bool value );
-
- template<typename T>
- ResultBuilder& operator << ( T const& value ) {
- m_stream.oss << value;
- return *this;
- }
-
- ResultBuilder& setResultType( ResultWas::OfType result );
- ResultBuilder& setResultType( bool result );
-
- void endExpression( DecomposedExpression const& expr );
-
- virtual void reconstructExpression( std::string& dest ) const CATCH_OVERRIDE;
-
- AssertionResult build() const;
- AssertionResult build( DecomposedExpression const& expr ) const;
-
- void useActiveException( ResultDisposition::Flags resultDisposition = ResultDisposition::Normal );
- void captureResult( ResultWas::OfType resultType );
- void captureExpression();
- void captureExpectedException( std::string const& expectedMessage );
- void captureExpectedException( Matchers::Impl::Matcher<std::string> const& matcher );
- void handleResult( AssertionResult const& result );
- void react();
- bool shouldDebugBreak() const;
- bool allowThrows() const;
-
- template<typename ArgT, typename MatcherT>
- void captureMatch( ArgT const& arg, MatcherT const& matcher, char const* matcherString );
-
- private:
- AssertionInfo m_assertionInfo;
- AssertionResultData m_data;
- CopyableStream m_stream;
-
- bool m_shouldDebugBreak;
- bool m_shouldThrow;
- };
-
-} // namespace Catch
-
-// Include after due to circular dependency:
-// #included from: catch_expression_lhs.hpp
-#define TWOBLUECUBES_CATCH_EXPRESSION_LHS_HPP_INCLUDED
-
-// #included from: catch_evaluate.hpp
-#define TWOBLUECUBES_CATCH_EVALUATE_HPP_INCLUDED
-
-#ifdef _MSC_VER
-#pragma warning(push)
-#pragma warning(disable:4389) // '==' : signed/unsigned mismatch
-#endif
-
-#include <cstddef>
-
-namespace Catch {
-namespace Internal {
-
- enum Operator {
- IsEqualTo,
- IsNotEqualTo,
- IsLessThan,
- IsGreaterThan,
- IsLessThanOrEqualTo,
- IsGreaterThanOrEqualTo
- };
-
- template<Operator Op> struct OperatorTraits { static const char* getName(){ return "*error*"; } };
- template<> struct OperatorTraits<IsEqualTo> { static const char* getName(){ return "=="; } };
- template<> struct OperatorTraits<IsNotEqualTo> { static const char* getName(){ return "!="; } };
- template<> struct OperatorTraits<IsLessThan> { static const char* getName(){ return "<"; } };
- template<> struct OperatorTraits<IsGreaterThan> { static const char* getName(){ return ">"; } };
- template<> struct OperatorTraits<IsLessThanOrEqualTo> { static const char* getName(){ return "<="; } };
- template<> struct OperatorTraits<IsGreaterThanOrEqualTo>{ static const char* getName(){ return ">="; } };
-
- template<typename T>
- inline T& opCast(T const& t) { return const_cast<T&>(t); }
-
-// nullptr_t support based on pull request #154 from Konstantin Baumann
-#ifdef CATCH_CONFIG_CPP11_NULLPTR
- inline std::nullptr_t opCast(std::nullptr_t) { return nullptr; }
-#endif // CATCH_CONFIG_CPP11_NULLPTR
-
- // So the compare overloads can be operator agnostic we convey the operator as a template
- // enum, which is used to specialise an Evaluator for doing the comparison.
- template<typename T1, typename T2, Operator Op>
- class Evaluator{};
-
- template<typename T1, typename T2>
- struct Evaluator<T1, T2, IsEqualTo> {
- static bool evaluate( T1 const& lhs, T2 const& rhs) {
- return bool( opCast( lhs ) == opCast( rhs ) );
- }
- };
- template<typename T1, typename T2>
- struct Evaluator<T1, T2, IsNotEqualTo> {
- static bool evaluate( T1 const& lhs, T2 const& rhs ) {
- return bool( opCast( lhs ) != opCast( rhs ) );
- }
- };
- template<typename T1, typename T2>
- struct Evaluator<T1, T2, IsLessThan> {
- static bool evaluate( T1 const& lhs, T2 const& rhs ) {
- return bool( opCast( lhs ) < opCast( rhs ) );
- }
- };
- template<typename T1, typename T2>
- struct Evaluator<T1, T2, IsGreaterThan> {
- static bool evaluate( T1 const& lhs, T2 const& rhs ) {
- return bool( opCast( lhs ) > opCast( rhs ) );
- }
- };
- template<typename T1, typename T2>
- struct Evaluator<T1, T2, IsGreaterThanOrEqualTo> {
- static bool evaluate( T1 const& lhs, T2 const& rhs ) {
- return bool( opCast( lhs ) >= opCast( rhs ) );
- }
- };
- template<typename T1, typename T2>
- struct Evaluator<T1, T2, IsLessThanOrEqualTo> {
- static bool evaluate( T1 const& lhs, T2 const& rhs ) {
- return bool( opCast( lhs ) <= opCast( rhs ) );
- }
- };
-
- template<Operator Op, typename T1, typename T2>
- bool applyEvaluator( T1 const& lhs, T2 const& rhs ) {
- return Evaluator<T1, T2, Op>::evaluate( lhs, rhs );
- }
-
- // This level of indirection allows us to specialise for integer types
- // to avoid signed/ unsigned warnings
-
- // "base" overload
- template<Operator Op, typename T1, typename T2>
- bool compare( T1 const& lhs, T2 const& rhs ) {
- return Evaluator<T1, T2, Op>::evaluate( lhs, rhs );
- }
-
- // unsigned X to int
- template<Operator Op> bool compare( unsigned int lhs, int rhs ) {
- return applyEvaluator<Op>( lhs, static_cast<unsigned int>( rhs ) );
- }
- template<Operator Op> bool compare( unsigned long lhs, int rhs ) {
- return applyEvaluator<Op>( lhs, static_cast<unsigned int>( rhs ) );
- }
- template<Operator Op> bool compare( unsigned char lhs, int rhs ) {
- return applyEvaluator<Op>( lhs, static_cast<unsigned int>( rhs ) );
- }
-
- // unsigned X to long
- template<Operator Op> bool compare( unsigned int lhs, long rhs ) {
- return applyEvaluator<Op>( lhs, static_cast<unsigned long>( rhs ) );
- }
- template<Operator Op> bool compare( unsigned long lhs, long rhs ) {
- return applyEvaluator<Op>( lhs, static_cast<unsigned long>( rhs ) );
- }
- template<Operator Op> bool compare( unsigned char lhs, long rhs ) {
- return applyEvaluator<Op>( lhs, static_cast<unsigned long>( rhs ) );
- }
-
- // int to unsigned X
- template<Operator Op> bool compare( int lhs, unsigned int rhs ) {
- return applyEvaluator<Op>( static_cast<unsigned int>( lhs ), rhs );
- }
- template<Operator Op> bool compare( int lhs, unsigned long rhs ) {
- return applyEvaluator<Op>( static_cast<unsigned int>( lhs ), rhs );
- }
- template<Operator Op> bool compare( int lhs, unsigned char rhs ) {
- return applyEvaluator<Op>( static_cast<unsigned int>( lhs ), rhs );
- }
-
- // long to unsigned X
- template<Operator Op> bool compare( long lhs, unsigned int rhs ) {
- return applyEvaluator<Op>( static_cast<unsigned long>( lhs ), rhs );
- }
- template<Operator Op> bool compare( long lhs, unsigned long rhs ) {
- return applyEvaluator<Op>( static_cast<unsigned long>( lhs ), rhs );
- }
- template<Operator Op> bool compare( long lhs, unsigned char rhs ) {
- return applyEvaluator<Op>( static_cast<unsigned long>( lhs ), rhs );
- }
-
- // pointer to long (when comparing against NULL)
- template<Operator Op, typename T> bool compare( long lhs, T* rhs ) {
- return Evaluator<T*, T*, Op>::evaluate( reinterpret_cast<T*>( lhs ), rhs );
- }
- template<Operator Op, typename T> bool compare( T* lhs, long rhs ) {
- return Evaluator<T*, T*, Op>::evaluate( lhs, reinterpret_cast<T*>( rhs ) );
- }
-
- // pointer to int (when comparing against NULL)
- template<Operator Op, typename T> bool compare( int lhs, T* rhs ) {
- return Evaluator<T*, T*, Op>::evaluate( reinterpret_cast<T*>( lhs ), rhs );
- }
- template<Operator Op, typename T> bool compare( T* lhs, int rhs ) {
- return Evaluator<T*, T*, Op>::evaluate( lhs, reinterpret_cast<T*>( rhs ) );
- }
-
-#ifdef CATCH_CONFIG_CPP11_LONG_LONG
- // long long to unsigned X
- template<Operator Op> bool compare( long long lhs, unsigned int rhs ) {
- return applyEvaluator<Op>( static_cast<unsigned long>( lhs ), rhs );
- }
- template<Operator Op> bool compare( long long lhs, unsigned long rhs ) {
- return applyEvaluator<Op>( static_cast<unsigned long>( lhs ), rhs );
- }
- template<Operator Op> bool compare( long long lhs, unsigned long long rhs ) {
- return applyEvaluator<Op>( static_cast<unsigned long>( lhs ), rhs );
- }
- template<Operator Op> bool compare( long long lhs, unsigned char rhs ) {
- return applyEvaluator<Op>( static_cast<unsigned long>( lhs ), rhs );
- }
-
- // unsigned long long to X
- template<Operator Op> bool compare( unsigned long long lhs, int rhs ) {
- return applyEvaluator<Op>( static_cast<long>( lhs ), rhs );
- }
- template<Operator Op> bool compare( unsigned long long lhs, long rhs ) {
- return applyEvaluator<Op>( static_cast<long>( lhs ), rhs );
- }
- template<Operator Op> bool compare( unsigned long long lhs, long long rhs ) {
- return applyEvaluator<Op>( static_cast<long>( lhs ), rhs );
- }
- template<Operator Op> bool compare( unsigned long long lhs, char rhs ) {
- return applyEvaluator<Op>( static_cast<long>( lhs ), rhs );
- }
-
- // pointer to long long (when comparing against NULL)
- template<Operator Op, typename T> bool compare( long long lhs, T* rhs ) {
- return Evaluator<T*, T*, Op>::evaluate( reinterpret_cast<T*>( lhs ), rhs );
- }
- template<Operator Op, typename T> bool compare( T* lhs, long long rhs ) {
- return Evaluator<T*, T*, Op>::evaluate( lhs, reinterpret_cast<T*>( rhs ) );
- }
-#endif // CATCH_CONFIG_CPP11_LONG_LONG
-
-#ifdef CATCH_CONFIG_CPP11_NULLPTR
- // pointer to nullptr_t (when comparing against nullptr)
- template<Operator Op, typename T> bool compare( std::nullptr_t, T* rhs ) {
- return Evaluator<T*, T*, Op>::evaluate( nullptr, rhs );
- }
- template<Operator Op, typename T> bool compare( T* lhs, std::nullptr_t ) {
- return Evaluator<T*, T*, Op>::evaluate( lhs, nullptr );
- }
-#endif // CATCH_CONFIG_CPP11_NULLPTR
-
-} // end of namespace Internal
-} // end of namespace Catch
-
-#ifdef _MSC_VER
-#pragma warning(pop)
-#endif
-
-// #included from: catch_tostring.h
-#define TWOBLUECUBES_CATCH_TOSTRING_H_INCLUDED
-
-#include <sstream>
-#include <iomanip>
-#include <limits>
-#include <vector>
-#include <cstddef>
-
-#ifdef __OBJC__
-// #included from: catch_objc_arc.hpp
-#define TWOBLUECUBES_CATCH_OBJC_ARC_HPP_INCLUDED
-
-#import <Foundation/Foundation.h>
-
-#ifdef __has_feature
-#define CATCH_ARC_ENABLED __has_feature(objc_arc)
-#else
-#define CATCH_ARC_ENABLED 0
-#endif
-
-void arcSafeRelease( NSObject* obj );
-id performOptionalSelector( id obj, SEL sel );
-
-#if !CATCH_ARC_ENABLED
-inline void arcSafeRelease( NSObject* obj ) {
- [obj release];
-}
-inline id performOptionalSelector( id obj, SEL sel ) {
- if( [obj respondsToSelector: sel] )
- return [obj performSelector: sel];
- return nil;
-}
-#define CATCH_UNSAFE_UNRETAINED
-#define CATCH_ARC_STRONG
-#else
-inline void arcSafeRelease( NSObject* ){}
-inline id performOptionalSelector( id obj, SEL sel ) {
-#ifdef __clang__
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
-#endif
- if( [obj respondsToSelector: sel] )
- return [obj performSelector: sel];
-#ifdef __clang__
-#pragma clang diagnostic pop
-#endif
- return nil;
-}
-#define CATCH_UNSAFE_UNRETAINED __unsafe_unretained
-#define CATCH_ARC_STRONG __strong
-#endif
-
-#endif
-
-#ifdef CATCH_CONFIG_CPP11_TUPLE
-#include <tuple>
-#endif
-
-#ifdef CATCH_CONFIG_CPP11_IS_ENUM
-#include <type_traits>
-#endif
-
-namespace Catch {
-
-// Why we're here.
-template<typename T>
-std::string toString( T const& value );
-
-// Built in overloads
-
-std::string toString( std::string const& value );
-std::string toString( std::wstring const& value );
-std::string toString( const char* const value );
-std::string toString( char* const value );
-std::string toString( const wchar_t* const value );
-std::string toString( wchar_t* const value );
-std::string toString( int value );
-std::string toString( unsigned long value );
-std::string toString( unsigned int value );
-std::string toString( const double value );
-std::string toString( const float value );
-std::string toString( bool value );
-std::string toString( char value );
-std::string toString( signed char value );
-std::string toString( unsigned char value );
-
-#ifdef CATCH_CONFIG_CPP11_LONG_LONG
-std::string toString( long long value );
-std::string toString( unsigned long long value );
-#endif
-
-#ifdef CATCH_CONFIG_CPP11_NULLPTR
-std::string toString( std::nullptr_t );
-#endif
-
-#ifdef __OBJC__
- std::string toString( NSString const * const& nsstring );
- std::string toString( NSString * CATCH_ARC_STRONG const& nsstring );
- std::string toString( NSObject* const& nsObject );
-#endif
-
-namespace Detail {
-
- extern const std::string unprintableString;
-
- struct BorgType {
- template<typename T> BorgType( T const& );
- };
-
- struct TrueType { char sizer[1]; };
- struct FalseType { char sizer[2]; };
-
- TrueType& testStreamable( std::ostream& );
- FalseType testStreamable( FalseType );
-
- FalseType operator<<( std::ostream const&, BorgType const& );
-
- template<typename T>
- struct IsStreamInsertable {
- static std::ostream &s;
- static T const&t;
- enum { value = sizeof( testStreamable(s << t) ) == sizeof( TrueType ) };
- };
-
-#if defined(CATCH_CONFIG_CPP11_IS_ENUM)
- template<typename T,
- bool IsEnum = std::is_enum<T>::value
- >
- struct EnumStringMaker
- {
- static std::string convert( T const& ) { return unprintableString; }
- };
-
- template<typename T>
- struct EnumStringMaker<T,true>
- {
- static std::string convert( T const& v )
- {
- return ::Catch::toString(
- static_cast<typename std::underlying_type<T>::type>(v)
- );
- }
- };
-#endif
- template<bool C>
- struct StringMakerBase {
-#if defined(CATCH_CONFIG_CPP11_IS_ENUM)
- template<typename T>
- static std::string convert( T const& v )
- {
- return EnumStringMaker<T>::convert( v );
- }
-#else
- template<typename T>
- static std::string convert( T const& ) { return unprintableString; }
-#endif
- };
-
- template<>
- struct StringMakerBase<true> {
- template<typename T>
- static std::string convert( T const& _value ) {
- std::ostringstream oss;
- oss << _value;
- return oss.str();
- }
- };
-
- std::string rawMemoryToString( const void *object, std::size_t size );
-
- template<typename T>
- inline std::string rawMemoryToString( const T& object ) {
- return rawMemoryToString( &object, sizeof(object) );
- }
-
-} // end namespace Detail
-
-template<typename T>
-struct StringMaker :
- Detail::StringMakerBase<Detail::IsStreamInsertable<T>::value> {};
-
-template<typename T>
-struct StringMaker<T*> {
- template<typename U>
- static std::string convert( U* p ) {
- if( !p )
- return "NULL";
- else
- return Detail::rawMemoryToString( p );
- }
-};
-
-template<typename R, typename C>
-struct StringMaker<R C::*> {
- static std::string convert( R C::* p ) {
- if( !p )
- return "NULL";
- else
- return Detail::rawMemoryToString( p );
- }
-};
-
-namespace Detail {
- template<typename InputIterator>
- std::string rangeToString( InputIterator first, InputIterator last );
-}
-
-//template<typename T, typename Allocator>
-//struct StringMaker<std::vector<T, Allocator> > {
-// static std::string convert( std::vector<T,Allocator> const& v ) {
-// return Detail::rangeToString( v.begin(), v.end() );
-// }
-//};
-
-template<typename T, typename Allocator>
-std::string toString( std::vector<T,Allocator> const& v ) {
- return Detail::rangeToString( v.begin(), v.end() );
-}
-
-#ifdef CATCH_CONFIG_CPP11_TUPLE
-
-// toString for tuples
-namespace TupleDetail {
- template<
- typename Tuple,
- std::size_t N = 0,
- bool = (N < std::tuple_size<Tuple>::value)
- >
- struct ElementPrinter {
- static void print( const Tuple& tuple, std::ostream& os )
- {
- os << ( N ? ", " : " " )
- << Catch::toString(std::get<N>(tuple));
- ElementPrinter<Tuple,N+1>::print(tuple,os);
- }
- };
-
- template<
- typename Tuple,
- std::size_t N
- >
- struct ElementPrinter<Tuple,N,false> {
- static void print( const Tuple&, std::ostream& ) {}
- };
-
-}
-
-template<typename ...Types>
-struct StringMaker<std::tuple<Types...>> {
-
- static std::string convert( const std::tuple<Types...>& tuple )
- {
- std::ostringstream os;
- os << '{';
- TupleDetail::ElementPrinter<std::tuple<Types...>>::print( tuple, os );
- os << " }";
- return os.str();
- }
-};
-#endif // CATCH_CONFIG_CPP11_TUPLE
-
-namespace Detail {
- template<typename T>
- std::string makeString( T const& value ) {
- return StringMaker<T>::convert( value );
- }
-} // end namespace Detail
-
-/// \brief converts any type to a string
-///
-/// The default template forwards on to ostringstream - except when an
-/// ostringstream overload does not exist - in which case it attempts to detect
-/// that and writes {?}.
-/// Overload (not specialise) this template for custom typs that you don't want
-/// to provide an ostream overload for.
-template<typename T>
-std::string toString( T const& value ) {
- return StringMaker<T>::convert( value );
-}
-
- namespace Detail {
- template<typename InputIterator>
- std::string rangeToString( InputIterator first, InputIterator last ) {
- std::ostringstream oss;
- oss << "{ ";
- if( first != last ) {
- oss << Catch::toString( *first );
- for( ++first ; first != last ; ++first )
- oss << ", " << Catch::toString( *first );
- }
- oss << " }";
- return oss.str();
- }
-}
-
-} // end namespace Catch
-
-namespace Catch {
-
-template<typename LhsT, Internal::Operator Op, typename RhsT>
-class BinaryExpression;
-
-template<typename ArgT, typename MatcherT>
-class MatchExpression;
-
-// Wraps the LHS of an expression and overloads comparison operators
-// for also capturing those and RHS (if any)
-template<typename T>
-class ExpressionLhs : public DecomposedExpression {
-public:
- ExpressionLhs( ResultBuilder& rb, T lhs ) : m_rb( rb ), m_lhs( lhs ), m_truthy(false) {}
-
- template<typename RhsT>
- BinaryExpression<T, Internal::IsEqualTo, RhsT const&>
- operator == ( RhsT const& rhs ) {
- return captureExpression<Internal::IsEqualTo>( rhs );
- }
-
- template<typename RhsT>
- BinaryExpression<T, Internal::IsNotEqualTo, RhsT const&>
- operator != ( RhsT const& rhs ) {
- return captureExpression<Internal::IsNotEqualTo>( rhs );
- }
-
- template<typename RhsT>
- BinaryExpression<T, Internal::IsLessThan, RhsT const&>
- operator < ( RhsT const& rhs ) {
- return captureExpression<Internal::IsLessThan>( rhs );
- }
-
- template<typename RhsT>
- BinaryExpression<T, Internal::IsGreaterThan, RhsT const&>
- operator > ( RhsT const& rhs ) {
- return captureExpression<Internal::IsGreaterThan>( rhs );
- }
-
- template<typename RhsT>
- BinaryExpression<T, Internal::IsLessThanOrEqualTo, RhsT const&>
- operator <= ( RhsT const& rhs ) {
- return captureExpression<Internal::IsLessThanOrEqualTo>( rhs );
- }
-
- template<typename RhsT>
- BinaryExpression<T, Internal::IsGreaterThanOrEqualTo, RhsT const&>
- operator >= ( RhsT const& rhs ) {
- return captureExpression<Internal::IsGreaterThanOrEqualTo>( rhs );
- }
-
- BinaryExpression<T, Internal::IsEqualTo, bool> operator == ( bool rhs ) {
- return captureExpression<Internal::IsEqualTo>( rhs );
- }
-
- BinaryExpression<T, Internal::IsNotEqualTo, bool> operator != ( bool rhs ) {
- return captureExpression<Internal::IsNotEqualTo>( rhs );
- }
-
- void endExpression() {
- m_truthy = m_lhs ? true : false;
- m_rb
- .setResultType( m_truthy )
- .endExpression( *this );
- }
-
- virtual void reconstructExpression( std::string& dest ) const CATCH_OVERRIDE {
- dest = Catch::toString( m_truthy );
- }
-
-private:
- template<Internal::Operator Op, typename RhsT>
- BinaryExpression<T, Op, RhsT&> captureExpression( RhsT& rhs ) const {
- return BinaryExpression<T, Op, RhsT&>( m_rb, m_lhs, rhs );
- }
-
- template<Internal::Operator Op>
- BinaryExpression<T, Op, bool> captureExpression( bool rhs ) const {
- return BinaryExpression<T, Op, bool>( m_rb, m_lhs, rhs );
- }
-
-private:
- ResultBuilder& m_rb;
- T m_lhs;
- bool m_truthy;
-};
-
-template<typename LhsT, Internal::Operator Op, typename RhsT>
-class BinaryExpression : public DecomposedExpression {
-public:
- BinaryExpression( ResultBuilder& rb, LhsT lhs, RhsT rhs )
- : m_rb( rb ), m_lhs( lhs ), m_rhs( rhs ) {}
-
- void endExpression() const {
- m_rb
- .setResultType( Internal::compare<Op>( m_lhs, m_rhs ) )
- .endExpression( *this );
- }
-
- virtual bool isBinaryExpression() const CATCH_OVERRIDE {
- return true;
- }
-
- virtual void reconstructExpression( std::string& dest ) const CATCH_OVERRIDE {
- std::string lhs = Catch::toString( m_lhs );
- std::string rhs = Catch::toString( m_rhs );
- char delim = lhs.size() + rhs.size() < 40 &&
- lhs.find('\n') == std::string::npos &&
- rhs.find('\n') == std::string::npos ? ' ' : '\n';
- dest.reserve( 7 + lhs.size() + rhs.size() );
- // 2 for spaces around operator
- // 2 for operator
- // 2 for parentheses (conditionally added later)
- // 1 for negation (conditionally added later)
- dest = lhs;
- dest += delim;
- dest += Internal::OperatorTraits<Op>::getName();
- dest += delim;
- dest += rhs;
- }
-
-private:
- ResultBuilder& m_rb;
- LhsT m_lhs;
- RhsT m_rhs;
-};
-
-template<typename ArgT, typename MatcherT>
-class MatchExpression : public DecomposedExpression {
-public:
- MatchExpression( ArgT arg, MatcherT matcher, char const* matcherString )
- : m_arg( arg ), m_matcher( matcher ), m_matcherString( matcherString ) {}
-
- virtual bool isBinaryExpression() const CATCH_OVERRIDE {
- return true;
- }
-
- virtual void reconstructExpression( std::string& dest ) const CATCH_OVERRIDE {
- std::string matcherAsString = m_matcher.toString();
- dest = Catch::toString( m_arg );
- dest += ' ';
- if( matcherAsString == Detail::unprintableString )
- dest += m_matcherString;
- else
- dest += matcherAsString;
- }
-
-private:
- ArgT m_arg;
- MatcherT m_matcher;
- char const* m_matcherString;
-};
-
-} // end namespace Catch
-
-
-namespace Catch {
-
- template<typename T>
- inline ExpressionLhs<T const&> ResultBuilder::operator <= ( T const& operand ) {
- return ExpressionLhs<T const&>( *this, operand );
- }
-
- inline ExpressionLhs<bool> ResultBuilder::operator <= ( bool value ) {
- return ExpressionLhs<bool>( *this, value );
- }
-
- template<typename ArgT, typename MatcherT>
- inline void ResultBuilder::captureMatch( ArgT const& arg, MatcherT const& matcher,
- char const* matcherString ) {
- MatchExpression<ArgT const&, MatcherT const&> expr( arg, matcher, matcherString );
- setResultType( matcher.match( arg ) );
- endExpression( expr );
- }
-
-} // namespace Catch
-
-// #included from: catch_message.h
-#define TWOBLUECUBES_CATCH_MESSAGE_H_INCLUDED
-
-#include <string>
-
-namespace Catch {
-
- struct MessageInfo {
- MessageInfo( std::string const& _macroName,
- SourceLineInfo const& _lineInfo,
- ResultWas::OfType _type );
-
- std::string macroName;
- SourceLineInfo lineInfo;
- ResultWas::OfType type;
- std::string message;
- unsigned int sequence;
-
- 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;
- };
-
- struct MessageBuilder {
- MessageBuilder( std::string const& macroName,
- SourceLineInfo const& lineInfo,
- ResultWas::OfType type )
- : m_info( macroName, lineInfo, type )
- {}
-
- template<typename T>
- MessageBuilder& operator << ( T const& value ) {
- m_stream << value;
- return *this;
- }
-
- MessageInfo m_info;
- std::ostringstream m_stream;
- };
-
- class ScopedMessage {
- public:
- ScopedMessage( MessageBuilder const& builder );
- ScopedMessage( ScopedMessage const& other );
- ~ScopedMessage();
-
- MessageInfo m_info;
- };
-
-} // end namespace Catch
-
-// #included from: catch_interfaces_capture.h
-#define TWOBLUECUBES_CATCH_INTERFACES_CAPTURE_H_INCLUDED
-
-#include <string>
-
-namespace Catch {
-
- class TestCase;
- class AssertionResult;
- struct AssertionInfo;
- struct SectionInfo;
- struct SectionEndInfo;
- struct MessageInfo;
- class ScopedMessageBuilder;
- struct Counts;
-
- struct IResultCapture {
-
- virtual ~IResultCapture();
-
- virtual void assertionEnded( AssertionResult const& result ) = 0;
- virtual bool sectionStarted( SectionInfo const& sectionInfo,
- Counts& assertions ) = 0;
- virtual void sectionEnded( SectionEndInfo const& endInfo ) = 0;
- virtual void sectionEndedEarly( SectionEndInfo const& endInfo ) = 0;
- virtual void pushScopedMessage( MessageInfo const& message ) = 0;
- virtual void popScopedMessage( MessageInfo const& message ) = 0;
-
- virtual std::string getCurrentTestName() const = 0;
- virtual const AssertionResult* getLastResult() const = 0;
-
- virtual void handleFatalErrorCondition( std::string const& message ) = 0;
- };
-
- IResultCapture& getResultCapture();
-}
-
-// #included from: catch_debugger.h
-#define TWOBLUECUBES_CATCH_DEBUGGER_H_INCLUDED
-
-// #included from: catch_platform.h
-#define TWOBLUECUBES_CATCH_PLATFORM_H_INCLUDED
-
-#if defined(__MAC_OS_X_VERSION_MIN_REQUIRED)
-# define CATCH_PLATFORM_MAC
-#elif defined(__IPHONE_OS_VERSION_MIN_REQUIRED)
-# define CATCH_PLATFORM_IPHONE
-#elif defined(linux) || defined(__linux) || defined(__linux__)
-# define CATCH_PLATFORM_LINUX
-#elif defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER)
-# define CATCH_PLATFORM_WINDOWS
-# if !defined(NOMINMAX) && !defined(CATCH_CONFIG_NO_NOMINMAX)
-# define CATCH_DEFINES_NOMINMAX
-# endif
-# if !defined(WIN32_LEAN_AND_MEAN) && !defined(CATCH_CONFIG_NO_WIN32_LEAN_AND_MEAN)
-# define CATCH_DEFINES_WIN32_LEAN_AND_MEAN
-# endif
-#endif
-
-#include <string>
-
-namespace Catch{
-
- bool isDebuggerActive();
- void writeToDebugConsole( std::string const& text );
-}
-
-#ifdef CATCH_PLATFORM_MAC
-
- // The following code snippet based on:
- // http://cocoawithlove.com/2008/03/break-into-debugger.html
- #if defined(__ppc64__) || defined(__ppc__)
- #define CATCH_TRAP() \
- __asm__("li r0, 20\nsc\nnop\nli r0, 37\nli r4, 2\nsc\nnop\n" \
- : : : "memory","r0","r3","r4" )
- #else
- #define CATCH_TRAP() __asm__("int $3\n" : : )
- #endif
-
-#elif defined(CATCH_PLATFORM_LINUX)
- // If we can use inline assembler, do it because this allows us to break
- // directly at the location of the failing check instead of breaking inside
- // raise() called from it, i.e. one stack frame below.
- #if defined(__GNUC__) && (defined(__i386) || defined(__x86_64))
- #define CATCH_TRAP() asm volatile ("int $3")
- #else // Fall back to the generic way.
- #include <signal.h>
-
- #define CATCH_TRAP() raise(SIGTRAP)
- #endif
-#elif defined(_MSC_VER)
- #define CATCH_TRAP() __debugbreak()
-#elif defined(__MINGW32__)
- extern "C" __declspec(dllimport) void __stdcall DebugBreak();
- #define CATCH_TRAP() DebugBreak()
-#endif
-
-#ifdef CATCH_TRAP
- #define CATCH_BREAK_INTO_DEBUGGER() if( Catch::isDebuggerActive() ) { CATCH_TRAP(); }
-#else
- #define CATCH_BREAK_INTO_DEBUGGER() Catch::alwaysTrue();
-#endif
-
-// #included from: catch_interfaces_runner.h
-#define TWOBLUECUBES_CATCH_INTERFACES_RUNNER_H_INCLUDED
-
-namespace Catch {
- class TestCase;
-
- struct IRunner {
- virtual ~IRunner();
- virtual bool aborting() const = 0;
- };
-}
-
-// #included from: catch_type_traits.hpp
-#define TWOBLUECUBES_CATCH_TYPE_TRAITS_HPP_INCLUDED
-
-#if defined(CATCH_CONFIG_CPP11_TYPE_TRAITS)
-#include <type_traits>
-#endif
-
-namespace Catch {
-
-#if defined(CATCH_CONFIG_CPP11_TYPE_TRAITS)
-
- template <typename T>
- using add_lvalue_reference = std::add_lvalue_reference<T>;
-
- template <typename T>
- using add_const = std::add_const<T>;
-
-#else
-
- template <typename T>
- struct add_const {
- typedef const T type;
- };
-
- template <typename T>
- struct add_lvalue_reference {
- typedef T& type;
- };
- template <typename T>
- struct add_lvalue_reference<T&> {
- typedef T& type;
- };
- // No && overload, because that is C++11, in which case we have
- // proper type_traits implementation from the standard library
-
-#endif
-
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// In the event of a failure works out if the debugger needs to be invoked
-// and/or an exception thrown and takes appropriate action.
-// This needs to be done as a macro so the debugger will stop in the user
-// source code rather than in Catch library code
-#define INTERNAL_CATCH_REACT( resultBuilder ) \
- if( resultBuilder.shouldDebugBreak() ) CATCH_BREAK_INTO_DEBUGGER(); \
- resultBuilder.react();
-
-///////////////////////////////////////////////////////////////////////////////
-#define INTERNAL_CATCH_TEST( expr, resultDisposition, macroName ) \
- do { \
- Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \
- try { \
- CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \
- ( __catchResult <= expr ).endExpression(); \
- } \
- catch( ... ) { \
- __catchResult.useActiveException( resultDisposition ); \
- } \
- INTERNAL_CATCH_REACT( __catchResult ) \
- } while( Catch::isTrue( false && static_cast<bool>( !!(expr) ) ) ) // expr here is never evaluated at runtime but it forces the compiler to give it a look
- // The double negation silences MSVC's C4800 warning, the static_cast forces short-circuit evaluation if the type has overloaded &&.
-
-///////////////////////////////////////////////////////////////////////////////
-#define INTERNAL_CATCH_IF( expr, resultDisposition, macroName ) \
- INTERNAL_CATCH_TEST( expr, resultDisposition, macroName ); \
- if( Catch::getResultCapture().getLastResult()->succeeded() )
-
-///////////////////////////////////////////////////////////////////////////////
-#define INTERNAL_CATCH_ELSE( expr, resultDisposition, macroName ) \
- INTERNAL_CATCH_TEST( expr, resultDisposition, macroName ); \
- if( !Catch::getResultCapture().getLastResult()->succeeded() )
-
-///////////////////////////////////////////////////////////////////////////////
-#define INTERNAL_CATCH_NO_THROW( expr, resultDisposition, macroName ) \
- do { \
- Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \
- try { \
- static_cast<void>(expr); \
- __catchResult.captureResult( Catch::ResultWas::Ok ); \
- } \
- catch( ... ) { \
- __catchResult.useActiveException( resultDisposition ); \
- } \
- INTERNAL_CATCH_REACT( __catchResult ) \
- } while( Catch::alwaysFalse() )
-
-///////////////////////////////////////////////////////////////////////////////
-#define INTERNAL_CATCH_THROWS( expr, resultDisposition, matcher, macroName ) \
- do { \
- Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition, #matcher ); \
- if( __catchResult.allowThrows() ) \
- try { \
- static_cast<void>(expr); \
- __catchResult.captureResult( Catch::ResultWas::DidntThrowException ); \
- } \
- catch( ... ) { \
- __catchResult.captureExpectedException( matcher ); \
- } \
- else \
- __catchResult.captureResult( Catch::ResultWas::Ok ); \
- INTERNAL_CATCH_REACT( __catchResult ) \
- } while( Catch::alwaysFalse() )
-
-///////////////////////////////////////////////////////////////////////////////
-#define INTERNAL_CATCH_THROWS_AS( expr, exceptionType, resultDisposition, macroName ) \
- do { \
- Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr ", " #exceptionType, resultDisposition ); \
- if( __catchResult.allowThrows() ) \
- try { \
- static_cast<void>(expr); \
- __catchResult.captureResult( Catch::ResultWas::DidntThrowException ); \
- } \
- catch( Catch::add_const<Catch::add_lvalue_reference<exceptionType>::type>::type ) { \
- __catchResult.captureResult( Catch::ResultWas::Ok ); \
- } \
- catch( ... ) { \
- __catchResult.useActiveException( resultDisposition ); \
- } \
- else \
- __catchResult.captureResult( Catch::ResultWas::Ok ); \
- INTERNAL_CATCH_REACT( __catchResult ) \
- } while( Catch::alwaysFalse() )
-
-///////////////////////////////////////////////////////////////////////////////
-#ifdef CATCH_CONFIG_VARIADIC_MACROS
- #define INTERNAL_CATCH_MSG( messageType, resultDisposition, macroName, ... ) \
- do { \
- Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, "", resultDisposition ); \
- __catchResult << __VA_ARGS__ + ::Catch::StreamEndStop(); \
- __catchResult.captureResult( messageType ); \
- INTERNAL_CATCH_REACT( __catchResult ) \
- } while( Catch::alwaysFalse() )
-#else
- #define INTERNAL_CATCH_MSG( messageType, resultDisposition, macroName, log ) \
- do { \
- Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, "", resultDisposition ); \
- __catchResult << log + ::Catch::StreamEndStop(); \
- __catchResult.captureResult( messageType ); \
- INTERNAL_CATCH_REACT( __catchResult ) \
- } while( Catch::alwaysFalse() )
-#endif
-
-///////////////////////////////////////////////////////////////////////////////
-#define INTERNAL_CATCH_INFO( log, macroName ) \
- Catch::ScopedMessage INTERNAL_CATCH_UNIQUE_NAME( scopedMessage ) = Catch::MessageBuilder( macroName, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info ) << log;
-
-///////////////////////////////////////////////////////////////////////////////
-#define INTERNAL_CHECK_THAT( arg, matcher, resultDisposition, macroName ) \
- do { \
- Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #arg ", " #matcher, resultDisposition ); \
- try { \
- __catchResult.captureMatch( arg, matcher, #matcher ); \
- } catch( ... ) { \
- __catchResult.useActiveException( resultDisposition | Catch::ResultDisposition::ContinueOnFailure ); \
- } \
- INTERNAL_CATCH_REACT( __catchResult ) \
- } while( Catch::alwaysFalse() )
-
-// #included from: internal/catch_section.h
-#define TWOBLUECUBES_CATCH_SECTION_H_INCLUDED
-
-// #included from: catch_section_info.h
-#define TWOBLUECUBES_CATCH_SECTION_INFO_H_INCLUDED
-
-// #included from: catch_totals.hpp
-#define TWOBLUECUBES_CATCH_TOTALS_HPP_INCLUDED
-
-#include <cstddef>
-
-namespace Catch {
-
- struct Counts {
- Counts() : passed( 0 ), failed( 0 ), failedButOk( 0 ) {}
-
- Counts operator - ( Counts const& other ) const {
- Counts diff;
- diff.passed = passed - other.passed;
- diff.failed = failed - other.failed;
- diff.failedButOk = failedButOk - other.failedButOk;
- return diff;
- }
- Counts& operator += ( Counts const& other ) {
- passed += other.passed;
- failed += other.failed;
- failedButOk += other.failedButOk;
- return *this;
- }
-
- std::size_t total() const {
- return passed + failed + failedButOk;
- }
- bool allPassed() const {
- return failed == 0 && failedButOk == 0;
- }
- bool allOk() const {
- return failed == 0;
- }
-
- std::size_t passed;
- std::size_t failed;
- std::size_t failedButOk;
- };
-
- struct Totals {
-
- Totals operator - ( Totals const& other ) const {
- Totals diff;
- diff.assertions = assertions - other.assertions;
- diff.testCases = testCases - other.testCases;
- return diff;
- }
-
- Totals delta( Totals const& prevTotals ) const {
- Totals diff = *this - prevTotals;
- if( diff.assertions.failed > 0 )
- ++diff.testCases.failed;
- else if( diff.assertions.failedButOk > 0 )
- ++diff.testCases.failedButOk;
- else
- ++diff.testCases.passed;
- return diff;
- }
-
- Totals& operator += ( Totals const& other ) {
- assertions += other.assertions;
- testCases += other.testCases;
- return *this;
- }
-
- Counts assertions;
- Counts testCases;
- };
-}
-
-#include <string>
-
-namespace Catch {
-
- struct SectionInfo {
- SectionInfo
- ( SourceLineInfo const& _lineInfo,
- std::string const& _name,
- std::string const& _description = std::string() );
-
- std::string name;
- std::string description;
- SourceLineInfo lineInfo;
- };
-
- struct SectionEndInfo {
- SectionEndInfo( SectionInfo const& _sectionInfo, Counts const& _prevAssertions, double _durationInSeconds )
- : sectionInfo( _sectionInfo ), prevAssertions( _prevAssertions ), durationInSeconds( _durationInSeconds )
- {}
-
- SectionInfo sectionInfo;
- Counts prevAssertions;
- double durationInSeconds;
- };
-
-} // end namespace Catch
-
-// #included from: catch_timer.h
-#define TWOBLUECUBES_CATCH_TIMER_H_INCLUDED
-
-#ifdef CATCH_PLATFORM_WINDOWS
-typedef unsigned long long uint64_t;
-#else
-#include <stdint.h>
-#endif
-
-namespace Catch {
-
- class Timer {
- public:
- Timer() : m_ticks( 0 ) {}
- void start();
- unsigned int getElapsedMicroseconds() const;
- unsigned int getElapsedMilliseconds() const;
- double getElapsedSeconds() const;
-
- private:
- uint64_t m_ticks;
- };
-
-} // namespace Catch
-
-#include <string>
-
-namespace Catch {
-
- class Section : NonCopyable {
- public:
- Section( SectionInfo const& info );
- ~Section();
-
- // This indicates whether the section should be executed or not
- operator bool() const;
-
- private:
- SectionInfo m_info;
-
- std::string m_name;
- Counts m_assertions;
- bool m_sectionIncluded;
- Timer m_timer;
- };
-
-} // end namespace Catch
-
-#ifdef CATCH_CONFIG_VARIADIC_MACROS
- #define INTERNAL_CATCH_SECTION( ... ) \
- if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::SectionInfo( CATCH_INTERNAL_LINEINFO, __VA_ARGS__ ) )
-#else
- #define INTERNAL_CATCH_SECTION( name, desc ) \
- if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::SectionInfo( CATCH_INTERNAL_LINEINFO, name, desc ) )
-#endif
-
-// #included from: internal/catch_generators.hpp
-#define TWOBLUECUBES_CATCH_GENERATORS_HPP_INCLUDED
-
-#include <iterator>
-#include <vector>
-#include <string>
-#include <stdlib.h>
-
-namespace Catch {
-
-template<typename T>
-struct IGenerator {
- virtual ~IGenerator() {}
- virtual T getValue( std::size_t index ) const = 0;
- virtual std::size_t size () const = 0;
-};
-
-template<typename T>
-class BetweenGenerator : public IGenerator<T> {
-public:
- BetweenGenerator( T from, T to ) : m_from( from ), m_to( to ){}
-
- virtual T getValue( std::size_t index ) const {
- return m_from+static_cast<int>( index );
- }
-
- virtual std::size_t size() const {
- return static_cast<std::size_t>( 1+m_to-m_from );
- }
-
-private:
-
- T m_from;
- T m_to;
-};
-
-template<typename T>
-class ValuesGenerator : public IGenerator<T> {
-public:
- ValuesGenerator(){}
-
- void add( T value ) {
- m_values.push_back( value );
- }
-
- virtual T getValue( std::size_t index ) const {
- return m_values[index];
- }
-
- virtual std::size_t size() const {
- return m_values.size();
- }
-
-private:
- std::vector<T> m_values;
-};
-
-template<typename T>
-class CompositeGenerator {
-public:
- CompositeGenerator() : m_totalSize( 0 ) {}
-
- // *** Move semantics, similar to auto_ptr ***
- CompositeGenerator( CompositeGenerator& other )
- : m_fileInfo( other.m_fileInfo ),
- m_totalSize( 0 )
- {
- move( other );
- }
-
- CompositeGenerator& setFileInfo( const char* fileInfo ) {
- m_fileInfo = fileInfo;
- return *this;
- }
-
- ~CompositeGenerator() {
- deleteAll( m_composed );
- }
-
- operator T () const {
- size_t overallIndex = getCurrentContext().getGeneratorIndex( m_fileInfo, m_totalSize );
-
- typename std::vector<const IGenerator<T>*>::const_iterator it = m_composed.begin();
- typename std::vector<const IGenerator<T>*>::const_iterator itEnd = m_composed.end();
- for( size_t index = 0; it != itEnd; ++it )
- {
- const IGenerator<T>* generator = *it;
- if( overallIndex >= index && overallIndex < index + generator->size() )
- {
- return generator->getValue( overallIndex-index );
- }
- index += generator->size();
- }
- CATCH_INTERNAL_ERROR( "Indexed past end of generated range" );
- return T(); // Suppress spurious "not all control paths return a value" warning in Visual Studio - if you know how to fix this please do so
- }
-
- void add( const IGenerator<T>* generator ) {
- m_totalSize += generator->size();
- m_composed.push_back( generator );
- }
-
- CompositeGenerator& then( CompositeGenerator& other ) {
- move( other );
- return *this;
- }
-
- CompositeGenerator& then( T value ) {
- ValuesGenerator<T>* valuesGen = new ValuesGenerator<T>();
- valuesGen->add( value );
- add( valuesGen );
- return *this;
- }
-
-private:
-
- void move( CompositeGenerator& other ) {
- std::copy( other.m_composed.begin(), other.m_composed.end(), std::back_inserter( m_composed ) );
- m_totalSize += other.m_totalSize;
- other.m_composed.clear();
- }
-
- std::vector<const IGenerator<T>*> m_composed;
- std::string m_fileInfo;
- size_t m_totalSize;
-};
-
-namespace Generators
-{
- template<typename T>
- CompositeGenerator<T> between( T from, T to ) {
- CompositeGenerator<T> generators;
- generators.add( new BetweenGenerator<T>( from, to ) );
- return generators;
- }
-
- template<typename T>
- CompositeGenerator<T> values( T val1, T val2 ) {
- CompositeGenerator<T> generators;
- ValuesGenerator<T>* valuesGen = new ValuesGenerator<T>();
- valuesGen->add( val1 );
- valuesGen->add( val2 );
- generators.add( valuesGen );
- return generators;
- }
-
- template<typename T>
- CompositeGenerator<T> values( T val1, T val2, T val3 ){
- CompositeGenerator<T> generators;
- ValuesGenerator<T>* valuesGen = new ValuesGenerator<T>();
- valuesGen->add( val1 );
- valuesGen->add( val2 );
- valuesGen->add( val3 );
- generators.add( valuesGen );
- return generators;
- }
-
- template<typename T>
- CompositeGenerator<T> values( T val1, T val2, T val3, T val4 ) {
- CompositeGenerator<T> generators;
- ValuesGenerator<T>* valuesGen = new ValuesGenerator<T>();
- valuesGen->add( val1 );
- valuesGen->add( val2 );
- valuesGen->add( val3 );
- valuesGen->add( val4 );
- generators.add( valuesGen );
- return generators;
- }
-
-} // end namespace Generators
-
-using namespace Generators;
-
-} // end namespace Catch
-
-#define INTERNAL_CATCH_LINESTR2( line ) #line
-#define INTERNAL_CATCH_LINESTR( line ) INTERNAL_CATCH_LINESTR2( line )
-
-#define INTERNAL_CATCH_GENERATE( expr ) expr.setFileInfo( __FILE__ "(" INTERNAL_CATCH_LINESTR( __LINE__ ) ")" )
-
-// #included from: internal/catch_interfaces_exception.h
-#define TWOBLUECUBES_CATCH_INTERFACES_EXCEPTION_H_INCLUDED
-
-#include <string>
-#include <vector>
-
-// #included from: catch_interfaces_registry_hub.h
-#define TWOBLUECUBES_CATCH_INTERFACES_REGISTRY_HUB_H_INCLUDED
-
-#include <string>
-
-namespace Catch {
-
- class TestCase;
- struct ITestCaseRegistry;
- struct IExceptionTranslatorRegistry;
- struct IExceptionTranslator;
- struct IReporterRegistry;
- struct IReporterFactory;
-
- struct IRegistryHub {
- virtual ~IRegistryHub();
-
- virtual IReporterRegistry const& getReporterRegistry() const = 0;
- virtual ITestCaseRegistry const& getTestCaseRegistry() const = 0;
- virtual IExceptionTranslatorRegistry& getExceptionTranslatorRegistry() = 0;
- };
-
- struct IMutableRegistryHub {
- virtual ~IMutableRegistryHub();
- virtual void registerReporter( std::string const& name, Ptr<IReporterFactory> const& factory ) = 0;
- virtual void registerListener( Ptr<IReporterFactory> const& factory ) = 0;
- virtual void registerTest( TestCase const& testInfo ) = 0;
- virtual void registerTranslator( const IExceptionTranslator* translator ) = 0;
- };
-
- IRegistryHub& getRegistryHub();
- IMutableRegistryHub& getMutableRegistryHub();
- void cleanUp();
- std::string translateActiveException();
-
-}
-
-namespace Catch {
-
- typedef std::string(*exceptionTranslateFunction)();
-
- struct IExceptionTranslator;
- typedef std::vector<const IExceptionTranslator*> ExceptionTranslators;
-
- struct IExceptionTranslator {
- virtual ~IExceptionTranslator();
- virtual std::string translate( ExceptionTranslators::const_iterator it, ExceptionTranslators::const_iterator itEnd ) const = 0;
- };
-
- struct IExceptionTranslatorRegistry {
- virtual ~IExceptionTranslatorRegistry();
-
- virtual std::string translateActiveException() const = 0;
- };
-
- class ExceptionTranslatorRegistrar {
- template<typename T>
- class ExceptionTranslator : public IExceptionTranslator {
- public:
-
- ExceptionTranslator( std::string(*translateFunction)( T& ) )
- : m_translateFunction( translateFunction )
- {}
-
- virtual std::string translate( ExceptionTranslators::const_iterator it, ExceptionTranslators::const_iterator itEnd ) const CATCH_OVERRIDE {
- try {
- if( it == itEnd )
- throw;
- else
- return (*it)->translate( it+1, itEnd );
- }
- catch( T& ex ) {
- return m_translateFunction( ex );
- }
- }
-
- protected:
- std::string(*m_translateFunction)( T& );
- };
-
- public:
- template<typename T>
- ExceptionTranslatorRegistrar( std::string(*translateFunction)( T& ) ) {
- getMutableRegistryHub().registerTranslator
- ( new ExceptionTranslator<T>( translateFunction ) );
- }
- };
-}
-
-///////////////////////////////////////////////////////////////////////////////
-#define INTERNAL_CATCH_TRANSLATE_EXCEPTION2( translatorName, signature ) \
- static std::string translatorName( signature ); \
- namespace{ Catch::ExceptionTranslatorRegistrar INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionRegistrar )( &translatorName ); }\
- static std::string translatorName( signature )
-
-#define INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION2( INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator ), signature )
-
-// #included from: internal/catch_approx.hpp
-#define TWOBLUECUBES_CATCH_APPROX_HPP_INCLUDED
-
-#include <cmath>
-#include <limits>
-
-#if defined(CATCH_CONFIG_CPP11_TYPE_TRAITS)
-#include <type_traits>
-#endif
-
-namespace Catch {
-namespace Detail {
-
- class Approx {
- public:
- explicit Approx ( double value )
- : m_epsilon( std::numeric_limits<float>::epsilon()*100 ),
- m_scale( 1.0 ),
- m_value( value )
- {}
-
- Approx( Approx const& other )
- : m_epsilon( other.m_epsilon ),
- m_scale( other.m_scale ),
- m_value( other.m_value )
- {}
-
- static Approx custom() {
- return Approx( 0 );
- }
-
- Approx operator()( double value ) {
- Approx approx( value );
- approx.epsilon( m_epsilon );
- approx.scale( m_scale );
- return approx;
- }
-
-#if defined(CATCH_CONFIG_CPP11_TYPE_TRAITS)
- template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
- friend bool operator == ( const T& lhs, Approx const& rhs ) {
- // Thanks to Richard Harris for his help refining this formula
- auto lhs_v = double(lhs);
- return std::fabs( lhs_v - rhs.m_value ) < rhs.m_epsilon * (rhs.m_scale + (std::max)( std::fabs(lhs_v), std::fabs(rhs.m_value) ) );
- }
-
- template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
- friend bool operator == ( Approx const& lhs, const T& rhs ) {
- return operator==( rhs, lhs );
- }
-
- template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
- friend bool operator != ( T lhs, Approx const& rhs ) {
- return !operator==( lhs, rhs );
- }
-
- template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
- friend bool operator != ( Approx const& lhs, T rhs ) {
- return !operator==( rhs, lhs );
- }
-
- template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
- friend bool operator <= ( T lhs, Approx const& rhs )
- {
- return double(lhs) < rhs.m_value || lhs == rhs;
- }
-
- template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
- friend bool operator <= ( Approx const& lhs, T rhs )
- {
- return lhs.m_value < double(rhs) || lhs == rhs;
- }
-
- template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
- friend bool operator >= ( T lhs, Approx const& rhs )
- {
- return double(lhs) > rhs.m_value || lhs == rhs;
- }
-
- template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
- friend bool operator >= ( Approx const& lhs, T rhs )
- {
- return lhs.m_value > double(rhs) || lhs == rhs;
- }
-#else
- friend bool operator == ( double lhs, Approx const& rhs ) {
- // Thanks to Richard Harris for his help refining this formula
- return std::fabs( lhs - rhs.m_value ) < rhs.m_epsilon * (rhs.m_scale + (std::max)( std::fabs(lhs), std::fabs(rhs.m_value) ) );
- }
-
- friend bool operator == ( Approx const& lhs, double rhs ) {
- return operator==( rhs, lhs );
- }
-
- friend bool operator != ( double lhs, Approx const& rhs ) {
- return !operator==( lhs, rhs );
- }
-
- friend bool operator != ( Approx const& lhs, double rhs ) {
- return !operator==( rhs, lhs );
- }
-
- friend bool operator <= ( double lhs, Approx const& rhs )
- {
- return lhs < rhs.m_value || lhs == rhs;
- }
-
- friend bool operator <= ( Approx const& lhs, double rhs )
- {
- return lhs.m_value < rhs || lhs == rhs;
- }
-
- friend bool operator >= ( double lhs, Approx const& rhs )
- {
- return lhs > rhs.m_value || lhs == rhs;
- }
-
- friend bool operator >= ( Approx const& lhs, double rhs )
- {
- return lhs.m_value > rhs || lhs == rhs;
- }
-#endif
-
- Approx& epsilon( double newEpsilon ) {
- m_epsilon = newEpsilon;
- return *this;
- }
-
- Approx& scale( double newScale ) {
- m_scale = newScale;
- return *this;
- }
-
- std::string toString() const {
- std::ostringstream oss;
- oss << "Approx( " << Catch::toString( m_value ) << " )";
- return oss.str();
- }
-
- private:
- double m_epsilon;
- double m_scale;
- double m_value;
- };
-}
-
-template<>
-inline std::string toString<Detail::Approx>( Detail::Approx const& value ) {
- return value.toString();
-}
-
-} // end namespace Catch
-
-// #included from: internal/catch_interfaces_tag_alias_registry.h
-#define TWOBLUECUBES_CATCH_INTERFACES_TAG_ALIAS_REGISTRY_H_INCLUDED
-
-// #included from: catch_tag_alias.h
-#define TWOBLUECUBES_CATCH_TAG_ALIAS_H_INCLUDED
-
-#include <string>
-
-namespace Catch {
-
- struct TagAlias {
- TagAlias( std::string _tag, SourceLineInfo _lineInfo ) : tag( _tag ), lineInfo( _lineInfo ) {}
-
- std::string tag;
- SourceLineInfo lineInfo;
- };
-
- struct RegistrarForTagAliases {
- RegistrarForTagAliases( char const* alias, char const* tag, SourceLineInfo const& lineInfo );
- };
-
-} // end namespace Catch
-
-#define CATCH_REGISTER_TAG_ALIAS( alias, spec ) namespace{ Catch::RegistrarForTagAliases INTERNAL_CATCH_UNIQUE_NAME( AutoRegisterTagAlias )( alias, spec, CATCH_INTERNAL_LINEINFO ); }
-// #included from: catch_option.hpp
-#define TWOBLUECUBES_CATCH_OPTION_HPP_INCLUDED
-
-namespace Catch {
-
- // An optional type
- template<typename T>
- class Option {
- public:
- Option() : nullableValue( CATCH_NULL ) {}
- Option( T const& _value )
- : nullableValue( new( storage ) T( _value ) )
- {}
- Option( Option const& _other )
- : nullableValue( _other ? new( storage ) T( *_other ) : CATCH_NULL )
- {}
-
- ~Option() {
- reset();
- }
-
- Option& operator= ( Option const& _other ) {
- if( &_other != this ) {
- reset();
- if( _other )
- nullableValue = new( storage ) T( *_other );
- }
- return *this;
- }
- Option& operator = ( T const& _value ) {
- reset();
- nullableValue = new( storage ) T( _value );
- return *this;
- }
-
- void reset() {
- if( nullableValue )
- nullableValue->~T();
- nullableValue = CATCH_NULL;
- }
-
- T& operator*() { return *nullableValue; }
- T const& operator*() const { return *nullableValue; }
- T* operator->() { return nullableValue; }
- const T* operator->() const { return nullableValue; }
-
- T valueOr( T const& defaultValue ) const {
- return nullableValue ? *nullableValue : defaultValue;
- }
-
- bool some() const { return nullableValue != CATCH_NULL; }
- bool none() const { return nullableValue == CATCH_NULL; }
-
- bool operator !() const { return nullableValue == CATCH_NULL; }
- operator SafeBool::type() const {
- return SafeBool::makeSafe( some() );
- }
-
- private:
- T* nullableValue;
- char storage[sizeof(T)];
- };
-
-} // end namespace Catch
-
-namespace Catch {
-
- struct ITagAliasRegistry {
- virtual ~ITagAliasRegistry();
- virtual Option<TagAlias> find( std::string const& alias ) const = 0;
- virtual std::string expandAliases( std::string const& unexpandedTestSpec ) const = 0;
-
- static ITagAliasRegistry const& get();
- };
-
-} // end namespace Catch
-
-// These files are included here so the single_include script doesn't put them
-// in the conditionally compiled sections
-// #included from: internal/catch_test_case_info.h
-#define TWOBLUECUBES_CATCH_TEST_CASE_INFO_H_INCLUDED
-
-#include <string>
-#include <set>
-
-#ifdef __clang__
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wpadded"
-#endif
-
-namespace Catch {
-
- struct ITestCase;
-
- struct TestCaseInfo {
- enum SpecialProperties{
- None = 0,
- IsHidden = 1 << 1,
- ShouldFail = 1 << 2,
- MayFail = 1 << 3,
- Throws = 1 << 4,
- NonPortable = 1 << 5
- };
-
- TestCaseInfo( std::string const& _name,
- std::string const& _className,
- std::string const& _description,
- std::set<std::string> const& _tags,
- SourceLineInfo const& _lineInfo );
-
- TestCaseInfo( TestCaseInfo const& other );
-
- friend void setTags( TestCaseInfo& testCaseInfo, std::set<std::string> const& tags );
-
- bool isHidden() const;
- bool throws() const;
- bool okToFail() const;
- bool expectedToFail() const;
-
- std::string name;
- std::string className;
- std::string description;
- std::set<std::string> tags;
- std::set<std::string> lcaseTags;
- std::string tagsAsString;
- SourceLineInfo lineInfo;
- SpecialProperties properties;
- };
-
- class TestCase : public TestCaseInfo {
- public:
-
- TestCase( ITestCase* testCase, TestCaseInfo const& info );
- TestCase( TestCase const& other );
-
- TestCase withName( std::string const& _newName ) const;
-
- void invoke() const;
-
- TestCaseInfo const& getTestCaseInfo() const;
-
- void swap( TestCase& other );
- bool operator == ( TestCase const& other ) const;
- bool operator < ( TestCase const& other ) const;
- TestCase& operator = ( TestCase const& other );
-
- private:
- Ptr<ITestCase> test;
- };
-
- TestCase makeTestCase( ITestCase* testCase,
- std::string const& className,
- std::string const& name,
- std::string const& description,
- SourceLineInfo const& lineInfo );
-}
-
-#ifdef __clang__
-#pragma clang diagnostic pop
-#endif
-
-
-#ifdef __OBJC__
-// #included from: internal/catch_objc.hpp
-#define TWOBLUECUBES_CATCH_OBJC_HPP_INCLUDED
-
-#import <objc/runtime.h>
-
-#include <string>
-
-// NB. Any general catch headers included here must be included
-// in catch.hpp first to make sure they are included by the single
-// header for non obj-usage
-
-///////////////////////////////////////////////////////////////////////////////
-// This protocol is really only here for (self) documenting purposes, since
-// all its methods are optional.
-@protocol OcFixture
-
-@optional
-
--(void) setUp;
--(void) tearDown;
-
-@end
-
-namespace Catch {
-
- class OcMethod : public SharedImpl<ITestCase> {
-
- public:
- OcMethod( Class cls, SEL sel ) : m_cls( cls ), m_sel( sel ) {}
-
- virtual void invoke() const {
- id obj = [[m_cls alloc] init];
-
- performOptionalSelector( obj, @selector(setUp) );
- performOptionalSelector( obj, m_sel );
- performOptionalSelector( obj, @selector(tearDown) );
-
- arcSafeRelease( obj );
- }
- private:
- virtual ~OcMethod() {}
-
- Class m_cls;
- SEL m_sel;
- };
-
- namespace Detail{
-
- inline std::string getAnnotation( Class cls,
- std::string const& annotationName,
- std::string const& testCaseName ) {
- NSString* selStr = [[NSString alloc] initWithFormat:@"Catch_%s_%s", annotationName.c_str(), testCaseName.c_str()];
- SEL sel = NSSelectorFromString( selStr );
- arcSafeRelease( selStr );
- id value = performOptionalSelector( cls, sel );
- if( value )
- return [(NSString*)value UTF8String];
- return "";
- }
- }
-
- inline size_t registerTestMethods() {
- size_t noTestMethods = 0;
- int noClasses = objc_getClassList( CATCH_NULL, 0 );
-
- Class* classes = (CATCH_UNSAFE_UNRETAINED Class *)malloc( sizeof(Class) * noClasses);
- objc_getClassList( classes, noClasses );
-
- for( int c = 0; c < noClasses; c++ ) {
- Class cls = classes[c];
- {
- u_int count;
- Method* methods = class_copyMethodList( cls, &count );
- for( u_int m = 0; m < count ; m++ ) {
- SEL selector = method_getName(methods[m]);
- std::string methodName = sel_getName(selector);
- if( startsWith( methodName, "Catch_TestCase_" ) ) {
- std::string testCaseName = methodName.substr( 15 );
- std::string name = Detail::getAnnotation( cls, "Name", testCaseName );
- std::string desc = Detail::getAnnotation( cls, "Description", testCaseName );
- const char* className = class_getName( cls );
-
- getMutableRegistryHub().registerTest( makeTestCase( new OcMethod( cls, selector ), className, name.c_str(), desc.c_str(), SourceLineInfo() ) );
- noTestMethods++;
- }
- }
- free(methods);
- }
- }
- return noTestMethods;
- }
-
- namespace Matchers {
- namespace Impl {
- namespace NSStringMatchers {
-
- template<typename MatcherT>
- struct StringHolder : MatcherImpl<MatcherT, NSString*>{
- StringHolder( NSString* substr ) : m_substr( [substr copy] ){}
- StringHolder( StringHolder const& other ) : m_substr( [other.m_substr copy] ){}
- StringHolder() {
- arcSafeRelease( m_substr );
- }
-
- NSString* m_substr;
- };
-
- struct Equals : StringHolder<Equals> {
- Equals( NSString* substr ) : StringHolder( substr ){}
-
- virtual bool match( ExpressionType const& str ) const {
- return (str != nil || m_substr == nil ) &&
- [str isEqualToString:m_substr];
- }
-
- virtual std::string toString() const {
- return "equals string: " + Catch::toString( m_substr );
- }
- };
-
- struct Contains : StringHolder<Contains> {
- Contains( NSString* substr ) : StringHolder( substr ){}
-
- virtual bool match( ExpressionType const& str ) const {
- return (str != nil || m_substr == nil ) &&
- [str rangeOfString:m_substr].location != NSNotFound;
- }
-
- virtual std::string toString() const {
- return "contains string: " + Catch::toString( m_substr );
- }
- };
-
- struct StartsWith : StringHolder<StartsWith> {
- StartsWith( NSString* substr ) : StringHolder( substr ){}
-
- virtual bool match( ExpressionType const& str ) const {
- return (str != nil || m_substr == nil ) &&
- [str rangeOfString:m_substr].location == 0;
- }
-
- virtual std::string toString() const {
- return "starts with: " + Catch::toString( m_substr );
- }
- };
- struct EndsWith : StringHolder<EndsWith> {
- EndsWith( NSString* substr ) : StringHolder( substr ){}
-
- virtual bool match( ExpressionType const& str ) const {
- return (str != nil || m_substr == nil ) &&
- [str rangeOfString:m_substr].location == [str length] - [m_substr length];
- }
-
- virtual std::string toString() const {
- return "ends with: " + Catch::toString( m_substr );
- }
- };
-
- } // namespace NSStringMatchers
- } // namespace Impl
-
- inline Impl::NSStringMatchers::Equals
- Equals( NSString* substr ){ return Impl::NSStringMatchers::Equals( substr ); }
-
- inline Impl::NSStringMatchers::Contains
- Contains( NSString* substr ){ return Impl::NSStringMatchers::Contains( substr ); }
-
- inline Impl::NSStringMatchers::StartsWith
- StartsWith( NSString* substr ){ return Impl::NSStringMatchers::StartsWith( substr ); }
-
- inline Impl::NSStringMatchers::EndsWith
- EndsWith( NSString* substr ){ return Impl::NSStringMatchers::EndsWith( substr ); }
-
- } // namespace Matchers
-
- using namespace Matchers;
-
-} // namespace Catch
-
-///////////////////////////////////////////////////////////////////////////////
-#define OC_TEST_CASE( name, desc )\
-+(NSString*) INTERNAL_CATCH_UNIQUE_NAME( Catch_Name_test ) \
-{\
-return @ name; \
-}\
-+(NSString*) INTERNAL_CATCH_UNIQUE_NAME( Catch_Description_test ) \
-{ \
-return @ desc; \
-} \
--(void) INTERNAL_CATCH_UNIQUE_NAME( Catch_TestCase_test )
-
-#endif
-
-#ifdef CATCH_IMPL
-// #included from: internal/catch_impl.hpp
-#define TWOBLUECUBES_CATCH_IMPL_HPP_INCLUDED
-
-// Collect all the implementation files together here
-// These are the equivalent of what would usually be cpp files
-
-#ifdef __clang__
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wweak-vtables"
-#endif
-
-// #included from: ../catch_session.hpp
-#define TWOBLUECUBES_CATCH_RUNNER_HPP_INCLUDED
-
-// #included from: internal/catch_commandline.hpp
-#define TWOBLUECUBES_CATCH_COMMANDLINE_HPP_INCLUDED
-
-// #included from: catch_config.hpp
-#define TWOBLUECUBES_CATCH_CONFIG_HPP_INCLUDED
-
-// #included from: catch_test_spec_parser.hpp
-#define TWOBLUECUBES_CATCH_TEST_SPEC_PARSER_HPP_INCLUDED
-
-#ifdef __clang__
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wpadded"
-#endif
-
-// #included from: catch_test_spec.hpp
-#define TWOBLUECUBES_CATCH_TEST_SPEC_HPP_INCLUDED
-
-#ifdef __clang__
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wpadded"
-#endif
-
-// #included from: catch_wildcard_pattern.hpp
-#define TWOBLUECUBES_CATCH_WILDCARD_PATTERN_HPP_INCLUDED
-
-#include <stdexcept>
-
-namespace Catch
-{
- class WildcardPattern {
- enum WildcardPosition {
- NoWildcard = 0,
- WildcardAtStart = 1,
- WildcardAtEnd = 2,
- WildcardAtBothEnds = WildcardAtStart | WildcardAtEnd
- };
-
- public:
-
- WildcardPattern( std::string const& pattern, CaseSensitive::Choice caseSensitivity )
- : m_caseSensitivity( caseSensitivity ),
- m_wildcard( NoWildcard ),
- m_pattern( adjustCase( pattern ) )
- {
- if( startsWith( m_pattern, '*' ) ) {
- m_pattern = m_pattern.substr( 1 );
- m_wildcard = WildcardAtStart;
- }
- if( endsWith( m_pattern, '*' ) ) {
- m_pattern = m_pattern.substr( 0, m_pattern.size()-1 );
- m_wildcard = static_cast<WildcardPosition>( m_wildcard | WildcardAtEnd );
- }
- }
- virtual ~WildcardPattern();
- virtual bool matches( std::string const& str ) const {
- switch( m_wildcard ) {
- case NoWildcard:
- return m_pattern == adjustCase( str );
- case WildcardAtStart:
- return endsWith( adjustCase( str ), m_pattern );
- case WildcardAtEnd:
- return startsWith( adjustCase( str ), m_pattern );
- case WildcardAtBothEnds:
- return contains( adjustCase( str ), m_pattern );
- }
-
-#ifdef __clang__
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wunreachable-code"
-#endif
- throw std::logic_error( "Unknown enum" );
-#ifdef __clang__
-#pragma clang diagnostic pop
-#endif
- }
- private:
- std::string adjustCase( std::string const& str ) const {
- return m_caseSensitivity == CaseSensitive::No ? toLower( str ) : str;
- }
- CaseSensitive::Choice m_caseSensitivity;
- WildcardPosition m_wildcard;
- std::string m_pattern;
- };
-}
-
-#include <string>
-#include <vector>
-
-namespace Catch {
-
- class TestSpec {
- struct Pattern : SharedImpl<> {
- virtual ~Pattern();
- virtual bool matches( TestCaseInfo const& testCase ) const = 0;
- };
- class NamePattern : public Pattern {
- public:
- NamePattern( std::string const& name )
- : m_wildcardPattern( toLower( name ), CaseSensitive::No )
- {}
- virtual ~NamePattern();
- virtual bool matches( TestCaseInfo const& testCase ) const {
- return m_wildcardPattern.matches( toLower( testCase.name ) );
- }
- private:
- WildcardPattern m_wildcardPattern;
- };
-
- class TagPattern : public Pattern {
- public:
- TagPattern( std::string const& tag ) : m_tag( toLower( tag ) ) {}
- virtual ~TagPattern();
- virtual bool matches( TestCaseInfo const& testCase ) const {
- return testCase.lcaseTags.find( m_tag ) != testCase.lcaseTags.end();
- }
- private:
- std::string m_tag;
- };
-
- class ExcludedPattern : public Pattern {
- public:
- ExcludedPattern( Ptr<Pattern> const& underlyingPattern ) : m_underlyingPattern( underlyingPattern ) {}
- virtual ~ExcludedPattern();
- virtual bool matches( TestCaseInfo const& testCase ) const { return !m_underlyingPattern->matches( testCase ); }
- private:
- Ptr<Pattern> m_underlyingPattern;
- };
-
- struct Filter {
- std::vector<Ptr<Pattern> > m_patterns;
-
- bool matches( TestCaseInfo const& testCase ) const {
- // All patterns in a filter must match for the filter to be a match
- for( std::vector<Ptr<Pattern> >::const_iterator it = m_patterns.begin(), itEnd = m_patterns.end(); it != itEnd; ++it ) {
- if( !(*it)->matches( testCase ) )
- return false;
- }
- return true;
- }
- };
-
- public:
- bool hasFilters() const {
- return !m_filters.empty();
- }
- bool matches( TestCaseInfo const& testCase ) const {
- // A TestSpec matches if any filter matches
- for( std::vector<Filter>::const_iterator it = m_filters.begin(), itEnd = m_filters.end(); it != itEnd; ++it )
- if( it->matches( testCase ) )
- return true;
- return false;
- }
-
- private:
- std::vector<Filter> m_filters;
-
- friend class TestSpecParser;
- };
-}
-
-#ifdef __clang__
-#pragma clang diagnostic pop
-#endif
-
-namespace Catch {
-
- class TestSpecParser {
- enum Mode{ None, Name, QuotedName, Tag, EscapedName };
- Mode m_mode;
- bool m_exclusion;
- std::size_t m_start, m_pos;
- std::string m_arg;
- std::vector<std::size_t> m_escapeChars;
- TestSpec::Filter m_currentFilter;
- TestSpec m_testSpec;
- ITagAliasRegistry const* m_tagAliases;
-
- public:
- TestSpecParser( ITagAliasRegistry const& tagAliases ) : m_tagAliases( &tagAliases ) {}
-
- TestSpecParser& parse( std::string const& arg ) {
- m_mode = None;
- m_exclusion = false;
- m_start = std::string::npos;
- m_arg = m_tagAliases->expandAliases( arg );
- m_escapeChars.clear();
- for( m_pos = 0; m_pos < m_arg.size(); ++m_pos )
- visitChar( m_arg[m_pos] );
- if( m_mode == Name )
- addPattern<TestSpec::NamePattern>();
- return *this;
- }
- TestSpec testSpec() {
- addFilter();
- return m_testSpec;
- }
- private:
- void visitChar( char c ) {
- if( m_mode == None ) {
- switch( c ) {
- case ' ': return;
- case '~': m_exclusion = true; return;
- case '[': return startNewMode( Tag, ++m_pos );
- case '"': return startNewMode( QuotedName, ++m_pos );
- case '\\': return escape();
- default: startNewMode( Name, m_pos ); break;
- }
- }
- if( m_mode == Name ) {
- if( c == ',' ) {
- addPattern<TestSpec::NamePattern>();
- addFilter();
- }
- else if( c == '[' ) {
- if( subString() == "exclude:" )
- m_exclusion = true;
- else
- addPattern<TestSpec::NamePattern>();
- startNewMode( Tag, ++m_pos );
- }
- else if( c == '\\' )
- escape();
- }
- else if( m_mode == EscapedName )
- m_mode = Name;
- else if( m_mode == QuotedName && c == '"' )
- addPattern<TestSpec::NamePattern>();
- else if( m_mode == Tag && c == ']' )
- addPattern<TestSpec::TagPattern>();
- }
- void startNewMode( Mode mode, std::size_t start ) {
- m_mode = mode;
- m_start = start;
- }
- void escape() {
- if( m_mode == None )
- m_start = m_pos;
- m_mode = EscapedName;
- m_escapeChars.push_back( m_pos );
- }
- std::string subString() const { return m_arg.substr( m_start, m_pos - m_start ); }
- template<typename T>
- void addPattern() {
- std::string token = subString();
- for( size_t i = 0; i < m_escapeChars.size(); ++i )
- token = token.substr( 0, m_escapeChars[i]-i ) + token.substr( m_escapeChars[i]+1-i );
- m_escapeChars.clear();
- if( startsWith( token, "exclude:" ) ) {
- m_exclusion = true;
- token = token.substr( 8 );
- }
- if( !token.empty() ) {
- Ptr<TestSpec::Pattern> pattern = new T( token );
- if( m_exclusion )
- pattern = new TestSpec::ExcludedPattern( pattern );
- m_currentFilter.m_patterns.push_back( pattern );
- }
- m_exclusion = false;
- m_mode = None;
- }
- void addFilter() {
- if( !m_currentFilter.m_patterns.empty() ) {
- m_testSpec.m_filters.push_back( m_currentFilter );
- m_currentFilter = TestSpec::Filter();
- }
- }
- };
- inline TestSpec parseTestSpec( std::string const& arg ) {
- return TestSpecParser( ITagAliasRegistry::get() ).parse( arg ).testSpec();
- }
-
-} // namespace Catch
-
-#ifdef __clang__
-#pragma clang diagnostic pop
-#endif
-
-// #included from: catch_interfaces_config.h
-#define TWOBLUECUBES_CATCH_INTERFACES_CONFIG_H_INCLUDED
-
-#include <iosfwd>
-#include <string>
-#include <vector>
-
-namespace Catch {
-
- struct Verbosity { enum Level {
- NoOutput = 0,
- Quiet,
- Normal
- }; };
-
- struct WarnAbout { enum What {
- Nothing = 0x00,
- NoAssertions = 0x01
- }; };
-
- struct ShowDurations { enum OrNot {
- DefaultForReporter,
- Always,
- Never
- }; };
- struct RunTests { enum InWhatOrder {
- InDeclarationOrder,
- InLexicographicalOrder,
- InRandomOrder
- }; };
- struct UseColour { enum YesOrNo {
- Auto,
- Yes,
- No
- }; };
-
- class TestSpec;
-
- struct IConfig : IShared {
-
- virtual ~IConfig();
-
- virtual bool allowThrows() const = 0;
- virtual std::ostream& stream() const = 0;
- virtual std::string name() const = 0;
- virtual bool includeSuccessfulResults() const = 0;
- virtual bool shouldDebugBreak() const = 0;
- virtual bool warnAboutMissingAssertions() const = 0;
- virtual int abortAfter() const = 0;
- virtual bool showInvisibles() const = 0;
- virtual ShowDurations::OrNot showDurations() const = 0;
- virtual TestSpec const& testSpec() const = 0;
- virtual RunTests::InWhatOrder runOrder() const = 0;
- virtual unsigned int rngSeed() const = 0;
- virtual UseColour::YesOrNo useColour() const = 0;
- virtual std::vector<std::string> const& getSectionsToRun() const = 0;
-
- };
-}
-
-// #included from: catch_stream.h
-#define TWOBLUECUBES_CATCH_STREAM_H_INCLUDED
-
-// #included from: catch_streambuf.h
-#define TWOBLUECUBES_CATCH_STREAMBUF_H_INCLUDED
-
-#include <streambuf>
-
-namespace Catch {
-
- class StreamBufBase : public std::streambuf {
- public:
- virtual ~StreamBufBase() CATCH_NOEXCEPT;
- };
-}
-
-#include <streambuf>
-#include <ostream>
-#include <fstream>
-#include <memory>
-
-namespace Catch {
-
- std::ostream& cout();
- std::ostream& cerr();
-
- struct IStream {
- virtual ~IStream() CATCH_NOEXCEPT;
- virtual std::ostream& stream() const = 0;
- };
-
- class FileStream : public IStream {
- mutable std::ofstream m_ofs;
- public:
- FileStream( std::string const& filename );
- virtual ~FileStream() CATCH_NOEXCEPT;
- public: // IStream
- virtual std::ostream& stream() const CATCH_OVERRIDE;
- };
-
- class CoutStream : public IStream {
- mutable std::ostream m_os;
- public:
- CoutStream();
- virtual ~CoutStream() CATCH_NOEXCEPT;
-
- public: // IStream
- virtual std::ostream& stream() const CATCH_OVERRIDE;
- };
-
- class DebugOutStream : public IStream {
- CATCH_AUTO_PTR( StreamBufBase ) m_streamBuf;
- mutable std::ostream m_os;
- public:
- DebugOutStream();
- virtual ~DebugOutStream() CATCH_NOEXCEPT;
-
- public: // IStream
- virtual std::ostream& stream() const CATCH_OVERRIDE;
- };
-}
-
-#include <memory>
-#include <vector>
-#include <string>
-#include <stdexcept>
-
-#ifndef CATCH_CONFIG_CONSOLE_WIDTH
-#define CATCH_CONFIG_CONSOLE_WIDTH 80
-#endif
-
-namespace Catch {
-
- struct ConfigData {
-
- ConfigData()
- : listTests( false ),
- listTags( false ),
- listReporters( false ),
- listTestNamesOnly( false ),
- showSuccessfulTests( false ),
- shouldDebugBreak( false ),
- noThrow( false ),
- showHelp( false ),
- showInvisibles( false ),
- filenamesAsTags( false ),
- abortAfter( -1 ),
- rngSeed( 0 ),
- verbosity( Verbosity::Normal ),
- warnings( WarnAbout::Nothing ),
- showDurations( ShowDurations::DefaultForReporter ),
- runOrder( RunTests::InDeclarationOrder ),
- useColour( UseColour::Auto )
- {}
-
- bool listTests;
- bool listTags;
- bool listReporters;
- bool listTestNamesOnly;
-
- bool showSuccessfulTests;
- bool shouldDebugBreak;
- bool noThrow;
- bool showHelp;
- bool showInvisibles;
- bool filenamesAsTags;
-
- int abortAfter;
- unsigned int rngSeed;
-
- Verbosity::Level verbosity;
- WarnAbout::What warnings;
- ShowDurations::OrNot showDurations;
- RunTests::InWhatOrder runOrder;
- UseColour::YesOrNo useColour;
-
- std::string outputFilename;
- std::string name;
- std::string processName;
-
- std::vector<std::string> reporterNames;
- std::vector<std::string> testsOrTags;
- std::vector<std::string> sectionsToRun;
- };
-
- class Config : public SharedImpl<IConfig> {
- private:
- Config( Config const& other );
- Config& operator = ( Config const& other );
- virtual void dummy();
- public:
-
- Config()
- {}
-
- Config( ConfigData const& data )
- : m_data( data ),
- m_stream( openStream() )
- {
- if( !data.testsOrTags.empty() ) {
- TestSpecParser parser( ITagAliasRegistry::get() );
- for( std::size_t i = 0; i < data.testsOrTags.size(); ++i )
- parser.parse( data.testsOrTags[i] );
- m_testSpec = parser.testSpec();
- }
- }
-
- virtual ~Config() {}
-
- std::string const& getFilename() const {
- return m_data.outputFilename ;
- }
-
- bool listTests() const { return m_data.listTests; }
- bool listTestNamesOnly() const { return m_data.listTestNamesOnly; }
- bool listTags() const { return m_data.listTags; }
- bool listReporters() const { return m_data.listReporters; }
-
- std::string getProcessName() const { return m_data.processName; }
-
- std::vector<std::string> const& getReporterNames() const { return m_data.reporterNames; }
- std::vector<std::string> const& getSectionsToRun() const CATCH_OVERRIDE { return m_data.sectionsToRun; }
-
- virtual TestSpec const& testSpec() const CATCH_OVERRIDE { return m_testSpec; }
-
- bool showHelp() const { return m_data.showHelp; }
-
- // IConfig interface
- virtual bool allowThrows() const CATCH_OVERRIDE { return !m_data.noThrow; }
- virtual std::ostream& stream() const CATCH_OVERRIDE { return m_stream->stream(); }
- virtual std::string name() const CATCH_OVERRIDE { return m_data.name.empty() ? m_data.processName : m_data.name; }
- virtual bool includeSuccessfulResults() const CATCH_OVERRIDE { return m_data.showSuccessfulTests; }
- virtual bool warnAboutMissingAssertions() const CATCH_OVERRIDE { return m_data.warnings & WarnAbout::NoAssertions; }
- virtual ShowDurations::OrNot showDurations() const CATCH_OVERRIDE { return m_data.showDurations; }
- virtual RunTests::InWhatOrder runOrder() const CATCH_OVERRIDE { return m_data.runOrder; }
- virtual unsigned int rngSeed() const CATCH_OVERRIDE { return m_data.rngSeed; }
- virtual UseColour::YesOrNo useColour() const CATCH_OVERRIDE { return m_data.useColour; }
- virtual bool shouldDebugBreak() const CATCH_OVERRIDE { return m_data.shouldDebugBreak; }
- virtual int abortAfter() const CATCH_OVERRIDE { return m_data.abortAfter; }
- virtual bool showInvisibles() const CATCH_OVERRIDE { return m_data.showInvisibles; }
-
- private:
-
- IStream const* openStream() {
- if( m_data.outputFilename.empty() )
- return new CoutStream();
- else if( m_data.outputFilename[0] == '%' ) {
- if( m_data.outputFilename == "%debug" )
- return new DebugOutStream();
- else
- throw std::domain_error( "Unrecognised stream: " + m_data.outputFilename );
- }
- else
- return new FileStream( m_data.outputFilename );
- }
- ConfigData m_data;
-
- CATCH_AUTO_PTR( IStream const ) m_stream;
- TestSpec m_testSpec;
- };
-
-} // end namespace Catch
-
-// #included from: catch_clara.h
-#define TWOBLUECUBES_CATCH_CLARA_H_INCLUDED
-
-// Use Catch's value for console width (store Clara's off to the side, if present)
-#ifdef CLARA_CONFIG_CONSOLE_WIDTH
-#define CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH CLARA_CONFIG_CONSOLE_WIDTH
-#undef CLARA_CONFIG_CONSOLE_WIDTH
-#endif
-#define CLARA_CONFIG_CONSOLE_WIDTH CATCH_CONFIG_CONSOLE_WIDTH
-
-// Declare Clara inside the Catch namespace
-#define STITCH_CLARA_OPEN_NAMESPACE namespace Catch {
-// #included from: ../external/clara.h
-
-// Version 0.0.2.4
-
-// Only use header guard if we are not using an outer namespace
-#if !defined(TWOBLUECUBES_CLARA_H_INCLUDED) || defined(STITCH_CLARA_OPEN_NAMESPACE)
-
-#ifndef STITCH_CLARA_OPEN_NAMESPACE
-#define TWOBLUECUBES_CLARA_H_INCLUDED
-#define STITCH_CLARA_OPEN_NAMESPACE
-#define STITCH_CLARA_CLOSE_NAMESPACE
-#else
-#define STITCH_CLARA_CLOSE_NAMESPACE }
-#endif
-
-#define STITCH_TBC_TEXT_FORMAT_OPEN_NAMESPACE STITCH_CLARA_OPEN_NAMESPACE
-
-// ----------- #included from tbc_text_format.h -----------
-
-// Only use header guard if we are not using an outer namespace
-#if !defined(TBC_TEXT_FORMAT_H_INCLUDED) || defined(STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE)
-#ifndef STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE
-#define TBC_TEXT_FORMAT_H_INCLUDED
-#endif
-
-#include <string>
-#include <vector>
-#include <sstream>
-#include <algorithm>
-
-// Use optional outer namespace
-#ifdef STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE
-namespace STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE {
-#endif
-
-namespace Tbc {
-
-#ifdef TBC_TEXT_FORMAT_CONSOLE_WIDTH
- const unsigned int consoleWidth = TBC_TEXT_FORMAT_CONSOLE_WIDTH;
-#else
- const unsigned int consoleWidth = 80;
-#endif
-
- struct TextAttributes {
- TextAttributes()
- : initialIndent( std::string::npos ),
- indent( 0 ),
- width( consoleWidth-1 ),
- tabChar( '\t' )
- {}
-
- TextAttributes& setInitialIndent( std::size_t _value ) { initialIndent = _value; return *this; }
- TextAttributes& setIndent( std::size_t _value ) { indent = _value; return *this; }
- TextAttributes& setWidth( std::size_t _value ) { width = _value; return *this; }
- TextAttributes& setTabChar( char _value ) { tabChar = _value; return *this; }
-
- std::size_t initialIndent; // indent of first line, or npos
- std::size_t indent; // indent of subsequent lines, or all if initialIndent is npos
- std::size_t width; // maximum width of text, including indent. Longer text will wrap
- char tabChar; // If this char is seen the indent is changed to current pos
- };
-
- class Text {
- public:
- Text( std::string const& _str, TextAttributes const& _attr = TextAttributes() )
- : attr( _attr )
- {
- std::string wrappableChars = " [({.,/|\\-";
- std::size_t indent = _attr.initialIndent != std::string::npos
- ? _attr.initialIndent
- : _attr.indent;
- std::string remainder = _str;
-
- while( !remainder.empty() ) {
- if( lines.size() >= 1000 ) {
- lines.push_back( "... message truncated due to excessive size" );
- return;
- }
- std::size_t tabPos = std::string::npos;
- std::size_t width = (std::min)( remainder.size(), _attr.width - indent );
- std::size_t pos = remainder.find_first_of( '\n' );
- if( pos <= width ) {
- width = pos;
- }
- pos = remainder.find_last_of( _attr.tabChar, width );
- if( pos != std::string::npos ) {
- tabPos = pos;
- if( remainder[width] == '\n' )
- width--;
- remainder = remainder.substr( 0, tabPos ) + remainder.substr( tabPos+1 );
- }
-
- if( width == remainder.size() ) {
- spliceLine( indent, remainder, width );
- }
- else if( remainder[width] == '\n' ) {
- spliceLine( indent, remainder, width );
- if( width <= 1 || remainder.size() != 1 )
- remainder = remainder.substr( 1 );
- indent = _attr.indent;
- }
- else {
- pos = remainder.find_last_of( wrappableChars, width );
- if( pos != std::string::npos && pos > 0 ) {
- spliceLine( indent, remainder, pos );
- if( remainder[0] == ' ' )
- remainder = remainder.substr( 1 );
- }
- else {
- spliceLine( indent, remainder, width-1 );
- lines.back() += "-";
- }
- if( lines.size() == 1 )
- indent = _attr.indent;
- if( tabPos != std::string::npos )
- indent += tabPos;
- }
- }
- }
-
- void spliceLine( std::size_t _indent, std::string& _remainder, std::size_t _pos ) {
- lines.push_back( std::string( _indent, ' ' ) + _remainder.substr( 0, _pos ) );
- _remainder = _remainder.substr( _pos );
- }
-
- typedef std::vector<std::string>::const_iterator const_iterator;
-
- const_iterator begin() const { return lines.begin(); }
- const_iterator end() const { return lines.end(); }
- std::string const& last() const { return lines.back(); }
- std::size_t size() const { return lines.size(); }
- std::string const& operator[]( std::size_t _index ) const { return lines[_index]; }
- std::string toString() const {
- std::ostringstream oss;
- oss << *this;
- return oss.str();
- }
-
- inline friend std::ostream& operator << ( std::ostream& _stream, Text const& _text ) {
- for( Text::const_iterator it = _text.begin(), itEnd = _text.end();
- it != itEnd; ++it ) {
- if( it != _text.begin() )
- _stream << "\n";
- _stream << *it;
- }
- return _stream;
- }
-
- private:
- std::string str;
- TextAttributes attr;
- std::vector<std::string> lines;
- };
-
-} // end namespace Tbc
-
-#ifdef STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE
-} // end outer namespace
-#endif
-
-#endif // TBC_TEXT_FORMAT_H_INCLUDED
-
-// ----------- end of #include from tbc_text_format.h -----------
-// ........... back in clara.h
-
-#undef STITCH_TBC_TEXT_FORMAT_OPEN_NAMESPACE
-
-// ----------- #included from clara_compilers.h -----------
-
-#ifndef TWOBLUECUBES_CLARA_COMPILERS_H_INCLUDED
-#define TWOBLUECUBES_CLARA_COMPILERS_H_INCLUDED
-
-// Detect a number of compiler features - mostly C++11/14 conformance - by compiler
-// The following features are defined:
-//
-// CLARA_CONFIG_CPP11_NULLPTR : is nullptr supported?
-// CLARA_CONFIG_CPP11_NOEXCEPT : is noexcept supported?
-// CLARA_CONFIG_CPP11_GENERATED_METHODS : The delete and default keywords for compiler generated methods
-// CLARA_CONFIG_CPP11_OVERRIDE : is override supported?
-// CLARA_CONFIG_CPP11_UNIQUE_PTR : is unique_ptr supported (otherwise use auto_ptr)
-
-// CLARA_CONFIG_CPP11_OR_GREATER : Is C++11 supported?
-
-// CLARA_CONFIG_VARIADIC_MACROS : are variadic macros supported?
-
-// In general each macro has a _NO_<feature name> form
-// (e.g. CLARA_CONFIG_CPP11_NO_NULLPTR) 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.
-
-// All the C++11 features can be disabled with CLARA_CONFIG_NO_CPP11
-
-#ifdef __clang__
-
-#if __has_feature(cxx_nullptr)
-#define CLARA_INTERNAL_CONFIG_CPP11_NULLPTR
-#endif
-
-#if __has_feature(cxx_noexcept)
-#define CLARA_INTERNAL_CONFIG_CPP11_NOEXCEPT
-#endif
-
-#endif // __clang__
-
-////////////////////////////////////////////////////////////////////////////////
-// GCC
-#ifdef __GNUC__
-
-#if __GNUC__ == 4 && __GNUC_MINOR__ >= 6 && defined(__GXX_EXPERIMENTAL_CXX0X__)
-#define CLARA_INTERNAL_CONFIG_CPP11_NULLPTR
-#endif
-
-// - otherwise more recent versions define __cplusplus >= 201103L
-// and will get picked up below
-
-#endif // __GNUC__
-
-////////////////////////////////////////////////////////////////////////////////
-// Visual C++
-#ifdef _MSC_VER
-
-#if (_MSC_VER >= 1600)
-#define CLARA_INTERNAL_CONFIG_CPP11_NULLPTR
-#define CLARA_INTERNAL_CONFIG_CPP11_UNIQUE_PTR
-#endif
-
-#if (_MSC_VER >= 1900 ) // (VC++ 13 (VS2015))
-#define CLARA_INTERNAL_CONFIG_CPP11_NOEXCEPT
-#define CLARA_INTERNAL_CONFIG_CPP11_GENERATED_METHODS
-#endif
-
-#endif // _MSC_VER
-
-////////////////////////////////////////////////////////////////////////////////
-// C++ language feature support
-
-// catch all support for C++11
-#if defined(__cplusplus) && __cplusplus >= 201103L
-
-#define CLARA_CPP11_OR_GREATER
-
-#if !defined(CLARA_INTERNAL_CONFIG_CPP11_NULLPTR)
-#define CLARA_INTERNAL_CONFIG_CPP11_NULLPTR
-#endif
-
-#ifndef CLARA_INTERNAL_CONFIG_CPP11_NOEXCEPT
-#define CLARA_INTERNAL_CONFIG_CPP11_NOEXCEPT
-#endif
-
-#ifndef CLARA_INTERNAL_CONFIG_CPP11_GENERATED_METHODS
-#define CLARA_INTERNAL_CONFIG_CPP11_GENERATED_METHODS
-#endif
-
-#if !defined(CLARA_INTERNAL_CONFIG_CPP11_OVERRIDE)
-#define CLARA_INTERNAL_CONFIG_CPP11_OVERRIDE
-#endif
-#if !defined(CLARA_INTERNAL_CONFIG_CPP11_UNIQUE_PTR)
-#define CLARA_INTERNAL_CONFIG_CPP11_UNIQUE_PTR
-#endif
-
-#endif // __cplusplus >= 201103L
-
-// Now set the actual defines based on the above + anything the user has configured
-#if defined(CLARA_INTERNAL_CONFIG_CPP11_NULLPTR) && !defined(CLARA_CONFIG_CPP11_NO_NULLPTR) && !defined(CLARA_CONFIG_CPP11_NULLPTR) && !defined(CLARA_CONFIG_NO_CPP11)
-#define CLARA_CONFIG_CPP11_NULLPTR
-#endif
-#if defined(CLARA_INTERNAL_CONFIG_CPP11_NOEXCEPT) && !defined(CLARA_CONFIG_CPP11_NO_NOEXCEPT) && !defined(CLARA_CONFIG_CPP11_NOEXCEPT) && !defined(CLARA_CONFIG_NO_CPP11)
-#define CLARA_CONFIG_CPP11_NOEXCEPT
-#endif
-#if defined(CLARA_INTERNAL_CONFIG_CPP11_GENERATED_METHODS) && !defined(CLARA_CONFIG_CPP11_NO_GENERATED_METHODS) && !defined(CLARA_CONFIG_CPP11_GENERATED_METHODS) && !defined(CLARA_CONFIG_NO_CPP11)
-#define CLARA_CONFIG_CPP11_GENERATED_METHODS
-#endif
-#if defined(CLARA_INTERNAL_CONFIG_CPP11_OVERRIDE) && !defined(CLARA_CONFIG_NO_OVERRIDE) && !defined(CLARA_CONFIG_CPP11_OVERRIDE) && !defined(CLARA_CONFIG_NO_CPP11)
-#define CLARA_CONFIG_CPP11_OVERRIDE
-#endif
-#if defined(CLARA_INTERNAL_CONFIG_CPP11_UNIQUE_PTR) && !defined(CLARA_CONFIG_NO_UNIQUE_PTR) && !defined(CLARA_CONFIG_CPP11_UNIQUE_PTR) && !defined(CLARA_CONFIG_NO_CPP11)
-#define CLARA_CONFIG_CPP11_UNIQUE_PTR
-#endif
-
-// noexcept support:
-#if defined(CLARA_CONFIG_CPP11_NOEXCEPT) && !defined(CLARA_NOEXCEPT)
-#define CLARA_NOEXCEPT noexcept
-# define CLARA_NOEXCEPT_IS(x) noexcept(x)
-#else
-#define CLARA_NOEXCEPT throw()
-# define CLARA_NOEXCEPT_IS(x)
-#endif
-
-// nullptr support
-#ifdef CLARA_CONFIG_CPP11_NULLPTR
-#define CLARA_NULL nullptr
-#else
-#define CLARA_NULL NULL
-#endif
-
-// override support
-#ifdef CLARA_CONFIG_CPP11_OVERRIDE
-#define CLARA_OVERRIDE override
-#else
-#define CLARA_OVERRIDE
-#endif
-
-// unique_ptr support
-#ifdef CLARA_CONFIG_CPP11_UNIQUE_PTR
-# define CLARA_AUTO_PTR( T ) std::unique_ptr<T>
-#else
-# define CLARA_AUTO_PTR( T ) std::auto_ptr<T>
-#endif
-
-#endif // TWOBLUECUBES_CLARA_COMPILERS_H_INCLUDED
-
-// ----------- end of #include from clara_compilers.h -----------
-// ........... back in clara.h
-
-#include <map>
-#include <stdexcept>
-#include <memory>
-
-#if defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER)
-#define CLARA_PLATFORM_WINDOWS
-#endif
-
-// Use optional outer namespace
-#ifdef STITCH_CLARA_OPEN_NAMESPACE
-STITCH_CLARA_OPEN_NAMESPACE
-#endif
-
-namespace Clara {
-
- struct UnpositionalTag {};
-
- extern UnpositionalTag _;
-
-#ifdef CLARA_CONFIG_MAIN
- UnpositionalTag _;
-#endif
-
- namespace Detail {
-
-#ifdef CLARA_CONSOLE_WIDTH
- const unsigned int consoleWidth = CLARA_CONFIG_CONSOLE_WIDTH;
-#else
- const unsigned int consoleWidth = 80;
-#endif
-
- using namespace Tbc;
-
- inline bool startsWith( std::string const& str, std::string const& prefix ) {
- return str.size() >= prefix.size() && str.substr( 0, prefix.size() ) == prefix;
- }
-
- template<typename T> struct RemoveConstRef{ typedef T type; };
- template<typename T> struct RemoveConstRef<T&>{ typedef T type; };
- template<typename T> struct RemoveConstRef<T const&>{ typedef T type; };
- template<typename T> struct RemoveConstRef<T const>{ typedef T type; };
-
- template<typename T> struct IsBool { static const bool value = false; };
- template<> struct IsBool<bool> { static const bool value = true; };
-
- template<typename T>
- void convertInto( std::string const& _source, T& _dest ) {
- std::stringstream ss;
- ss << _source;
- ss >> _dest;
- if( ss.fail() )
- throw std::runtime_error( "Unable to convert " + _source + " to destination type" );
- }
- inline void convertInto( std::string const& _source, std::string& _dest ) {
- _dest = _source;
- }
- char toLowerCh(char c) {
- return static_cast<char>( ::tolower( c ) );
- }
- inline void convertInto( std::string const& _source, bool& _dest ) {
- std::string sourceLC = _source;
- std::transform( sourceLC.begin(), sourceLC.end(), sourceLC.begin(), toLowerCh );
- if( sourceLC == "y" || sourceLC == "1" || sourceLC == "true" || sourceLC == "yes" || sourceLC == "on" )
- _dest = true;
- else if( sourceLC == "n" || sourceLC == "0" || sourceLC == "false" || sourceLC == "no" || sourceLC == "off" )
- _dest = false;
- else
- throw std::runtime_error( "Expected a boolean value but did not recognise:\n '" + _source + "'" );
- }
-
- template<typename ConfigT>
- struct IArgFunction {
- virtual ~IArgFunction() {}
-#ifdef CLARA_CONFIG_CPP11_GENERATED_METHODS
- IArgFunction() = default;
- IArgFunction( IArgFunction const& ) = default;
-#endif
- virtual void set( ConfigT& config, std::string const& value ) const = 0;
- virtual bool takesArg() const = 0;
- virtual IArgFunction* clone() const = 0;
- };
-
- template<typename ConfigT>
- class BoundArgFunction {
- public:
- BoundArgFunction() : functionObj( CLARA_NULL ) {}
- BoundArgFunction( IArgFunction<ConfigT>* _functionObj ) : functionObj( _functionObj ) {}
- BoundArgFunction( BoundArgFunction const& other ) : functionObj( other.functionObj ? other.functionObj->clone() : CLARA_NULL ) {}
- BoundArgFunction& operator = ( BoundArgFunction const& other ) {
- IArgFunction<ConfigT>* newFunctionObj = other.functionObj ? other.functionObj->clone() : CLARA_NULL;
- delete functionObj;
- functionObj = newFunctionObj;
- return *this;
- }
- ~BoundArgFunction() { delete functionObj; }
-
- void set( ConfigT& config, std::string const& value ) const {
- functionObj->set( config, value );
- }
- bool takesArg() const { return functionObj->takesArg(); }
-
- bool isSet() const {
- return functionObj != CLARA_NULL;
- }
- private:
- IArgFunction<ConfigT>* functionObj;
- };
-
- template<typename C>
- struct NullBinder : IArgFunction<C>{
- virtual void set( C&, std::string const& ) const {}
- virtual bool takesArg() const { return true; }
- virtual IArgFunction<C>* clone() const { return new NullBinder( *this ); }
- };
-
- template<typename C, typename M>
- struct BoundDataMember : IArgFunction<C>{
- BoundDataMember( M C::* _member ) : member( _member ) {}
- virtual void set( C& p, std::string const& stringValue ) const {
- convertInto( stringValue, p.*member );
- }
- virtual bool takesArg() const { return !IsBool<M>::value; }
- virtual IArgFunction<C>* clone() const { return new BoundDataMember( *this ); }
- M C::* member;
- };
- template<typename C, typename M>
- struct BoundUnaryMethod : IArgFunction<C>{
- BoundUnaryMethod( void (C::*_member)( M ) ) : member( _member ) {}
- virtual void set( C& p, std::string const& stringValue ) const {
- typename RemoveConstRef<M>::type value;
- convertInto( stringValue, value );
- (p.*member)( value );
- }
- virtual bool takesArg() const { return !IsBool<M>::value; }
- virtual IArgFunction<C>* clone() const { return new BoundUnaryMethod( *this ); }
- void (C::*member)( M );
- };
- template<typename C>
- struct BoundNullaryMethod : IArgFunction<C>{
- BoundNullaryMethod( void (C::*_member)() ) : member( _member ) {}
- virtual void set( C& p, std::string const& stringValue ) const {
- bool value;
- convertInto( stringValue, value );
- if( value )
- (p.*member)();
- }
- virtual bool takesArg() const { return false; }
- virtual IArgFunction<C>* clone() const { return new BoundNullaryMethod( *this ); }
- void (C::*member)();
- };
-
- template<typename C>
- struct BoundUnaryFunction : IArgFunction<C>{
- BoundUnaryFunction( void (*_function)( C& ) ) : function( _function ) {}
- virtual void set( C& obj, std::string const& stringValue ) const {
- bool value;
- convertInto( stringValue, value );
- if( value )
- function( obj );
- }
- virtual bool takesArg() const { return false; }
- virtual IArgFunction<C>* clone() const { return new BoundUnaryFunction( *this ); }
- void (*function)( C& );
- };
-
- template<typename C, typename T>
- struct BoundBinaryFunction : IArgFunction<C>{
- BoundBinaryFunction( void (*_function)( C&, T ) ) : function( _function ) {}
- virtual void set( C& obj, std::string const& stringValue ) const {
- typename RemoveConstRef<T>::type value;
- convertInto( stringValue, value );
- function( obj, value );
- }
- virtual bool takesArg() const { return !IsBool<T>::value; }
- virtual IArgFunction<C>* clone() const { return new BoundBinaryFunction( *this ); }
- void (*function)( C&, T );
- };
-
- } // namespace Detail
-
- inline std::vector<std::string> argsToVector( int argc, char const* const* const argv ) {
- std::vector<std::string> args( static_cast<std::size_t>( argc ) );
- for( std::size_t i = 0; i < static_cast<std::size_t>( argc ); ++i )
- args[i] = argv[i];
-
- return args;
- }
-
- class Parser {
- enum Mode { None, MaybeShortOpt, SlashOpt, ShortOpt, LongOpt, Positional };
- Mode mode;
- std::size_t from;
- bool inQuotes;
- public:
-
- struct Token {
- enum Type { Positional, ShortOpt, LongOpt };
- Token( Type _type, std::string const& _data ) : type( _type ), data( _data ) {}
- Type type;
- std::string data;
- };
-
- Parser() : mode( None ), from( 0 ), inQuotes( false ){}
-
- void parseIntoTokens( std::vector<std::string> const& args, std::vector<Token>& tokens ) {
- const std::string doubleDash = "--";
- for( std::size_t i = 1; i < args.size() && args[i] != doubleDash; ++i )
- parseIntoTokens( args[i], tokens);
- }
-
- void parseIntoTokens( std::string const& arg, std::vector<Token>& tokens ) {
- for( std::size_t i = 0; i <= arg.size(); ++i ) {
- char c = arg[i];
- if( c == '"' )
- inQuotes = !inQuotes;
- mode = handleMode( i, c, arg, tokens );
- }
- }
- Mode handleMode( std::size_t i, char c, std::string const& arg, std::vector<Token>& tokens ) {
- switch( mode ) {
- case None: return handleNone( i, c );
- case MaybeShortOpt: return handleMaybeShortOpt( i, c );
- case ShortOpt:
- case LongOpt:
- case SlashOpt: return handleOpt( i, c, arg, tokens );
- case Positional: return handlePositional( i, c, arg, tokens );
- default: throw std::logic_error( "Unknown mode" );
- }
- }
-
- Mode handleNone( std::size_t i, char c ) {
- if( inQuotes ) {
- from = i;
- return Positional;
- }
- switch( c ) {
- case '-': return MaybeShortOpt;
-#ifdef CLARA_PLATFORM_WINDOWS
- case '/': from = i+1; return SlashOpt;
-#endif
- default: from = i; return Positional;
- }
- }
- Mode handleMaybeShortOpt( std::size_t i, char c ) {
- switch( c ) {
- case '-': from = i+1; return LongOpt;
- default: from = i; return ShortOpt;
- }
- }
- Mode handleOpt( std::size_t i, char c, std::string const& arg, std::vector<Token>& tokens ) {
- if( std::string( ":=\0", 3 ).find( c ) == std::string::npos )
- return mode;
-
- std::string optName = arg.substr( from, i-from );
- if( mode == ShortOpt )
- for( std::size_t j = 0; j < optName.size(); ++j )
- tokens.push_back( Token( Token::ShortOpt, optName.substr( j, 1 ) ) );
- else if( mode == SlashOpt && optName.size() == 1 )
- tokens.push_back( Token( Token::ShortOpt, optName ) );
- else
- tokens.push_back( Token( Token::LongOpt, optName ) );
- return None;
- }
- Mode handlePositional( std::size_t i, char c, std::string const& arg, std::vector<Token>& tokens ) {
- if( inQuotes || std::string( "\0", 1 ).find( c ) == std::string::npos )
- return mode;
-
- std::string data = arg.substr( from, i-from );
- tokens.push_back( Token( Token::Positional, data ) );
- return None;
- }
- };
-
- template<typename ConfigT>
- struct CommonArgProperties {
- CommonArgProperties() {}
- CommonArgProperties( Detail::BoundArgFunction<ConfigT> const& _boundField ) : boundField( _boundField ) {}
-
- Detail::BoundArgFunction<ConfigT> boundField;
- std::string description;
- std::string detail;
- std::string placeholder; // Only value if boundField takes an arg
-
- bool takesArg() const {
- return !placeholder.empty();
- }
- void validate() const {
- if( !boundField.isSet() )
- throw std::logic_error( "option not bound" );
- }
- };
- struct OptionArgProperties {
- std::vector<std::string> shortNames;
- std::string longName;
-
- bool hasShortName( std::string const& shortName ) const {
- return std::find( shortNames.begin(), shortNames.end(), shortName ) != shortNames.end();
- }
- bool hasLongName( std::string const& _longName ) const {
- return _longName == longName;
- }
- };
- struct PositionalArgProperties {
- PositionalArgProperties() : position( -1 ) {}
- int position; // -1 means non-positional (floating)
-
- bool isFixedPositional() const {
- return position != -1;
- }
- };
-
- template<typename ConfigT>
- class CommandLine {
-
- struct Arg : CommonArgProperties<ConfigT>, OptionArgProperties, PositionalArgProperties {
- Arg() {}
- Arg( Detail::BoundArgFunction<ConfigT> const& _boundField ) : CommonArgProperties<ConfigT>( _boundField ) {}
-
- using CommonArgProperties<ConfigT>::placeholder; // !TBD
-
- std::string dbgName() const {
- if( !longName.empty() )
- return "--" + longName;
- if( !shortNames.empty() )
- return "-" + shortNames[0];
- return "positional args";
- }
- std::string commands() const {
- std::ostringstream oss;
- bool first = true;
- std::vector<std::string>::const_iterator it = shortNames.begin(), itEnd = shortNames.end();
- for(; it != itEnd; ++it ) {
- if( first )
- first = false;
- else
- oss << ", ";
- oss << "-" << *it;
- }
- if( !longName.empty() ) {
- if( !first )
- oss << ", ";
- oss << "--" << longName;
- }
- if( !placeholder.empty() )
- oss << " <" << placeholder << ">";
- return oss.str();
- }
- };
-
- typedef CLARA_AUTO_PTR( Arg ) ArgAutoPtr;
-
- friend void addOptName( Arg& arg, std::string const& optName )
- {
- if( optName.empty() )
- return;
- if( Detail::startsWith( optName, "--" ) ) {
- if( !arg.longName.empty() )
- throw std::logic_error( "Only one long opt may be specified. '"
- + arg.longName
- + "' already specified, now attempting to add '"
- + optName + "'" );
- arg.longName = optName.substr( 2 );
- }
- else if( Detail::startsWith( optName, "-" ) )
- arg.shortNames.push_back( optName.substr( 1 ) );
- else
- throw std::logic_error( "option must begin with - or --. Option was: '" + optName + "'" );
- }
- friend void setPositionalArg( Arg& arg, int position )
- {
- arg.position = position;
- }
-
- class ArgBuilder {
- public:
- ArgBuilder( Arg* arg ) : m_arg( arg ) {}
-
- // Bind a non-boolean data member (requires placeholder string)
- template<typename C, typename M>
- void bind( M C::* field, std::string const& placeholder ) {
- m_arg->boundField = new Detail::BoundDataMember<C,M>( field );
- m_arg->placeholder = placeholder;
- }
- // Bind a boolean data member (no placeholder required)
- template<typename C>
- void bind( bool C::* field ) {
- m_arg->boundField = new Detail::BoundDataMember<C,bool>( field );
- }
-
- // Bind a method taking a single, non-boolean argument (requires a placeholder string)
- template<typename C, typename M>
- void bind( void (C::* unaryMethod)( M ), std::string const& placeholder ) {
- m_arg->boundField = new Detail::BoundUnaryMethod<C,M>( unaryMethod );
- m_arg->placeholder = placeholder;
- }
-
- // Bind a method taking a single, boolean argument (no placeholder string required)
- template<typename C>
- void bind( void (C::* unaryMethod)( bool ) ) {
- m_arg->boundField = new Detail::BoundUnaryMethod<C,bool>( unaryMethod );
- }
-
- // Bind a method that takes no arguments (will be called if opt is present)
- template<typename C>
- void bind( void (C::* nullaryMethod)() ) {
- m_arg->boundField = new Detail::BoundNullaryMethod<C>( nullaryMethod );
- }
-
- // Bind a free function taking a single argument - the object to operate on (no placeholder string required)
- template<typename C>
- void bind( void (* unaryFunction)( C& ) ) {
- m_arg->boundField = new Detail::BoundUnaryFunction<C>( unaryFunction );
- }
-
- // Bind a free function taking a single argument - the object to operate on (requires a placeholder string)
- template<typename C, typename T>
- void bind( void (* binaryFunction)( C&, T ), std::string const& placeholder ) {
- m_arg->boundField = new Detail::BoundBinaryFunction<C, T>( binaryFunction );
- m_arg->placeholder = placeholder;
- }
-
- ArgBuilder& describe( std::string const& description ) {
- m_arg->description = description;
- return *this;
- }
- ArgBuilder& detail( std::string const& detail ) {
- m_arg->detail = detail;
- return *this;
- }
-
- protected:
- Arg* m_arg;
- };
-
- class OptBuilder : public ArgBuilder {
- public:
- OptBuilder( Arg* arg ) : ArgBuilder( arg ) {}
- OptBuilder( OptBuilder& other ) : ArgBuilder( other ) {}
-
- OptBuilder& operator[]( std::string const& optName ) {
- addOptName( *ArgBuilder::m_arg, optName );
- return *this;
- }
- };
-
- public:
-
- CommandLine()
- : m_boundProcessName( new Detail::NullBinder<ConfigT>() ),
- m_highestSpecifiedArgPosition( 0 ),
- m_throwOnUnrecognisedTokens( false )
- {}
- CommandLine( CommandLine const& other )
- : m_boundProcessName( other.m_boundProcessName ),
- m_options ( other.m_options ),
- m_positionalArgs( other.m_positionalArgs ),
- m_highestSpecifiedArgPosition( other.m_highestSpecifiedArgPosition ),
- m_throwOnUnrecognisedTokens( other.m_throwOnUnrecognisedTokens )
- {
- if( other.m_floatingArg.get() )
- m_floatingArg.reset( new Arg( *other.m_floatingArg ) );
- }
-
- CommandLine& setThrowOnUnrecognisedTokens( bool shouldThrow = true ) {
- m_throwOnUnrecognisedTokens = shouldThrow;
- return *this;
- }
-
- OptBuilder operator[]( std::string const& optName ) {
- m_options.push_back( Arg() );
- addOptName( m_options.back(), optName );
- OptBuilder builder( &m_options.back() );
- return builder;
- }
-
- ArgBuilder operator[]( int position ) {
- m_positionalArgs.insert( std::make_pair( position, Arg() ) );
- if( position > m_highestSpecifiedArgPosition )
- m_highestSpecifiedArgPosition = position;
- setPositionalArg( m_positionalArgs[position], position );
- ArgBuilder builder( &m_positionalArgs[position] );
- return builder;
- }
-
- // Invoke this with the _ instance
- ArgBuilder operator[]( UnpositionalTag ) {
- if( m_floatingArg.get() )
- throw std::logic_error( "Only one unpositional argument can be added" );
- m_floatingArg.reset( new Arg() );
- ArgBuilder builder( m_floatingArg.get() );
- return builder;
- }
-
- template<typename C, typename M>
- void bindProcessName( M C::* field ) {
- m_boundProcessName = new Detail::BoundDataMember<C,M>( field );
- }
- template<typename C, typename M>
- void bindProcessName( void (C::*_unaryMethod)( M ) ) {
- m_boundProcessName = new Detail::BoundUnaryMethod<C,M>( _unaryMethod );
- }
-
- void optUsage( std::ostream& os, std::size_t indent = 0, std::size_t width = Detail::consoleWidth ) const {
- typename std::vector<Arg>::const_iterator itBegin = m_options.begin(), itEnd = m_options.end(), it;
- std::size_t maxWidth = 0;
- for( it = itBegin; it != itEnd; ++it )
- maxWidth = (std::max)( maxWidth, it->commands().size() );
-
- for( it = itBegin; it != itEnd; ++it ) {
- Detail::Text usage( it->commands(), Detail::TextAttributes()
- .setWidth( maxWidth+indent )
- .setIndent( indent ) );
- Detail::Text desc( it->description, Detail::TextAttributes()
- .setWidth( width - maxWidth - 3 ) );
-
- for( std::size_t i = 0; i < (std::max)( usage.size(), desc.size() ); ++i ) {
- std::string usageCol = i < usage.size() ? usage[i] : "";
- os << usageCol;
-
- if( i < desc.size() && !desc[i].empty() )
- os << std::string( indent + 2 + maxWidth - usageCol.size(), ' ' )
- << desc[i];
- os << "\n";
- }
- }
- }
- std::string optUsage() const {
- std::ostringstream oss;
- optUsage( oss );
- return oss.str();
- }
-
- void argSynopsis( std::ostream& os ) const {
- for( int i = 1; i <= m_highestSpecifiedArgPosition; ++i ) {
- if( i > 1 )
- os << " ";
- typename std::map<int, Arg>::const_iterator it = m_positionalArgs.find( i );
- if( it != m_positionalArgs.end() )
- os << "<" << it->second.placeholder << ">";
- else if( m_floatingArg.get() )
- os << "<" << m_floatingArg->placeholder << ">";
- else
- throw std::logic_error( "non consecutive positional arguments with no floating args" );
- }
- // !TBD No indication of mandatory args
- if( m_floatingArg.get() ) {
- if( m_highestSpecifiedArgPosition > 1 )
- os << " ";
- os << "[<" << m_floatingArg->placeholder << "> ...]";
- }
- }
- std::string argSynopsis() const {
- std::ostringstream oss;
- argSynopsis( oss );
- return oss.str();
- }
-
- void usage( std::ostream& os, std::string const& procName ) const {
- validate();
- os << "usage:\n " << procName << " ";
- argSynopsis( os );
- if( !m_options.empty() ) {
- os << " [options]\n\nwhere options are: \n";
- optUsage( os, 2 );
- }
- os << "\n";
- }
- std::string usage( std::string const& procName ) const {
- std::ostringstream oss;
- usage( oss, procName );
- return oss.str();
- }
-
- ConfigT parse( std::vector<std::string> const& args ) const {
- ConfigT config;
- parseInto( args, config );
- return config;
- }
-
- std::vector<Parser::Token> parseInto( std::vector<std::string> const& args, ConfigT& config ) const {
- std::string processName = args[0];
- std::size_t lastSlash = processName.find_last_of( "/\\" );
- if( lastSlash != std::string::npos )
- processName = processName.substr( lastSlash+1 );
- m_boundProcessName.set( config, processName );
- std::vector<Parser::Token> tokens;
- Parser parser;
- parser.parseIntoTokens( args, tokens );
- return populate( tokens, config );
- }
-
- std::vector<Parser::Token> populate( std::vector<Parser::Token> const& tokens, ConfigT& config ) const {
- validate();
- std::vector<Parser::Token> unusedTokens = populateOptions( tokens, config );
- unusedTokens = populateFixedArgs( unusedTokens, config );
- unusedTokens = populateFloatingArgs( unusedTokens, config );
- return unusedTokens;
- }
-
- std::vector<Parser::Token> populateOptions( std::vector<Parser::Token> const& tokens, ConfigT& config ) const {
- std::vector<Parser::Token> unusedTokens;
- std::vector<std::string> errors;
- for( std::size_t i = 0; i < tokens.size(); ++i ) {
- Parser::Token const& token = tokens[i];
- typename std::vector<Arg>::const_iterator it = m_options.begin(), itEnd = m_options.end();
- for(; it != itEnd; ++it ) {
- Arg const& arg = *it;
-
- try {
- if( ( token.type == Parser::Token::ShortOpt && arg.hasShortName( token.data ) ) ||
- ( token.type == Parser::Token::LongOpt && arg.hasLongName( token.data ) ) ) {
- if( arg.takesArg() ) {
- if( i == tokens.size()-1 || tokens[i+1].type != Parser::Token::Positional )
- errors.push_back( "Expected argument to option: " + token.data );
- else
- arg.boundField.set( config, tokens[++i].data );
- }
- else {
- arg.boundField.set( config, "true" );
- }
- break;
- }
- }
- catch( std::exception& ex ) {
- errors.push_back( std::string( ex.what() ) + "\n- while parsing: (" + arg.commands() + ")" );
- }
- }
- if( it == itEnd ) {
- if( token.type == Parser::Token::Positional || !m_throwOnUnrecognisedTokens )
- unusedTokens.push_back( token );
- else if( errors.empty() && m_throwOnUnrecognisedTokens )
- errors.push_back( "unrecognised option: " + token.data );
- }
- }
- if( !errors.empty() ) {
- std::ostringstream oss;
- for( std::vector<std::string>::const_iterator it = errors.begin(), itEnd = errors.end();
- it != itEnd;
- ++it ) {
- if( it != errors.begin() )
- oss << "\n";
- oss << *it;
- }
- throw std::runtime_error( oss.str() );
- }
- return unusedTokens;
- }
- std::vector<Parser::Token> populateFixedArgs( std::vector<Parser::Token> const& tokens, ConfigT& config ) const {
- std::vector<Parser::Token> unusedTokens;
- int position = 1;
- for( std::size_t i = 0; i < tokens.size(); ++i ) {
- Parser::Token const& token = tokens[i];
- typename std::map<int, Arg>::const_iterator it = m_positionalArgs.find( position );
- if( it != m_positionalArgs.end() )
- it->second.boundField.set( config, token.data );
- else
- unusedTokens.push_back( token );
- if( token.type == Parser::Token::Positional )
- position++;
- }
- return unusedTokens;
- }
- std::vector<Parser::Token> populateFloatingArgs( std::vector<Parser::Token> const& tokens, ConfigT& config ) const {
- if( !m_floatingArg.get() )
- return tokens;
- std::vector<Parser::Token> unusedTokens;
- for( std::size_t i = 0; i < tokens.size(); ++i ) {
- Parser::Token const& token = tokens[i];
- if( token.type == Parser::Token::Positional )
- m_floatingArg->boundField.set( config, token.data );
- else
- unusedTokens.push_back( token );
- }
- return unusedTokens;
- }
-
- void validate() const
- {
- if( m_options.empty() && m_positionalArgs.empty() && !m_floatingArg.get() )
- throw std::logic_error( "No options or arguments specified" );
-
- for( typename std::vector<Arg>::const_iterator it = m_options.begin(),
- itEnd = m_options.end();
- it != itEnd; ++it )
- it->validate();
- }
-
- private:
- Detail::BoundArgFunction<ConfigT> m_boundProcessName;
- std::vector<Arg> m_options;
- std::map<int, Arg> m_positionalArgs;
- ArgAutoPtr m_floatingArg;
- int m_highestSpecifiedArgPosition;
- bool m_throwOnUnrecognisedTokens;
- };
-
-} // end namespace Clara
-
-STITCH_CLARA_CLOSE_NAMESPACE
-#undef STITCH_CLARA_OPEN_NAMESPACE
-#undef STITCH_CLARA_CLOSE_NAMESPACE
-
-#endif // TWOBLUECUBES_CLARA_H_INCLUDED
-#undef STITCH_CLARA_OPEN_NAMESPACE
-
-// Restore Clara's value for console width, if present
-#ifdef CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH
-#define CLARA_CONFIG_CONSOLE_WIDTH CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH
-#undef CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH
-#endif
-
-#include <fstream>
-#include <ctime>
-
-namespace Catch {
-
- inline void abortAfterFirst( ConfigData& config ) { config.abortAfter = 1; }
- inline void abortAfterX( ConfigData& config, int x ) {
- if( x < 1 )
- throw std::runtime_error( "Value after -x or --abortAfter must be greater than zero" );
- config.abortAfter = x;
- }
- inline void addTestOrTags( ConfigData& config, std::string const& _testSpec ) { config.testsOrTags.push_back( _testSpec ); }
- inline void addSectionToRun( ConfigData& config, std::string const& sectionName ) { config.sectionsToRun.push_back( sectionName ); }
- inline void addReporterName( ConfigData& config, std::string const& _reporterName ) { config.reporterNames.push_back( _reporterName ); }
-
- inline void addWarning( ConfigData& config, std::string const& _warning ) {
- if( _warning == "NoAssertions" )
- config.warnings = static_cast<WarnAbout::What>( config.warnings | WarnAbout::NoAssertions );
- else
- throw std::runtime_error( "Unrecognised warning: '" + _warning + '\'' );
- }
- inline void setOrder( ConfigData& config, std::string const& order ) {
- if( startsWith( "declared", order ) )
- config.runOrder = RunTests::InDeclarationOrder;
- else if( startsWith( "lexical", order ) )
- config.runOrder = RunTests::InLexicographicalOrder;
- else if( startsWith( "random", order ) )
- config.runOrder = RunTests::InRandomOrder;
- else
- throw std::runtime_error( "Unrecognised ordering: '" + order + '\'' );
- }
- inline void setRngSeed( ConfigData& config, std::string const& seed ) {
- if( seed == "time" ) {
- config.rngSeed = static_cast<unsigned int>( std::time(0) );
- }
- else {
- std::stringstream ss;
- ss << seed;
- ss >> config.rngSeed;
- if( ss.fail() )
- throw std::runtime_error( "Argument to --rng-seed should be the word 'time' or a number" );
- }
- }
- inline void setVerbosity( ConfigData& config, int level ) {
- // !TBD: accept strings?
- config.verbosity = static_cast<Verbosity::Level>( level );
- }
- inline void setShowDurations( ConfigData& config, bool _showDurations ) {
- config.showDurations = _showDurations
- ? ShowDurations::Always
- : ShowDurations::Never;
- }
- inline void setUseColour( ConfigData& config, std::string const& value ) {
- std::string mode = toLower( value );
-
- if( mode == "yes" )
- config.useColour = UseColour::Yes;
- else if( mode == "no" )
- config.useColour = UseColour::No;
- else if( mode == "auto" )
- config.useColour = UseColour::Auto;
- else
- throw std::runtime_error( "colour mode must be one of: auto, yes or no" );
- }
- inline void forceColour( ConfigData& config ) {
- config.useColour = UseColour::Yes;
- }
- inline void loadTestNamesFromFile( ConfigData& config, std::string const& _filename ) {
- std::ifstream f( _filename.c_str() );
- if( !f.is_open() )
- throw std::domain_error( "Unable to load input file: " + _filename );
-
- std::string line;
- while( std::getline( f, line ) ) {
- line = trim(line);
- if( !line.empty() && !startsWith( line, '#' ) ) {
- if( !startsWith( line, '"' ) )
- line = '"' + line + '"';
- addTestOrTags( config, line + ',' );
- }
- }
- }
-
- inline Clara::CommandLine<ConfigData> makeCommandLineParser() {
-
- using namespace Clara;
- CommandLine<ConfigData> cli;
-
- cli.bindProcessName( &ConfigData::processName );
-
- cli["-?"]["-h"]["--help"]
- .describe( "display usage information" )
- .bind( &ConfigData::showHelp );
-
- cli["-l"]["--list-tests"]
- .describe( "list all/matching test cases" )
- .bind( &ConfigData::listTests );
-
- cli["-t"]["--list-tags"]
- .describe( "list all/matching tags" )
- .bind( &ConfigData::listTags );
-
- cli["-s"]["--success"]
- .describe( "include successful tests in output" )
- .bind( &ConfigData::showSuccessfulTests );
-
- cli["-b"]["--break"]
- .describe( "break into debugger on failure" )
- .bind( &ConfigData::shouldDebugBreak );
-
- cli["-e"]["--nothrow"]
- .describe( "skip exception tests" )
- .bind( &ConfigData::noThrow );
-
- cli["-i"]["--invisibles"]
- .describe( "show invisibles (tabs, newlines)" )
- .bind( &ConfigData::showInvisibles );
-
- cli["-o"]["--out"]
- .describe( "output filename" )
- .bind( &ConfigData::outputFilename, "filename" );
-
- cli["-r"]["--reporter"]
-// .placeholder( "name[:filename]" )
- .describe( "reporter to use (defaults to console)" )
- .bind( &addReporterName, "name" );
-
- cli["-n"]["--name"]
- .describe( "suite name" )
- .bind( &ConfigData::name, "name" );
-
- cli["-a"]["--abort"]
- .describe( "abort at first failure" )
- .bind( &abortAfterFirst );
-
- cli["-x"]["--abortx"]
- .describe( "abort after x failures" )
- .bind( &abortAfterX, "no. failures" );
-
- cli["-w"]["--warn"]
- .describe( "enable warnings" )
- .bind( &addWarning, "warning name" );
-
-// - needs updating if reinstated
-// cli.into( &setVerbosity )
-// .describe( "level of verbosity (0=no output)" )
-// .shortOpt( "v")
-// .longOpt( "verbosity" )
-// .placeholder( "level" );
-
- cli[_]
- .describe( "which test or tests to use" )
- .bind( &addTestOrTags, "test name, pattern or tags" );
-
- cli["-d"]["--durations"]
- .describe( "show test durations" )
- .bind( &setShowDurations, "yes|no" );
-
- cli["-f"]["--input-file"]
- .describe( "load test names to run from a file" )
- .bind( &loadTestNamesFromFile, "filename" );
-
- cli["-#"]["--filenames-as-tags"]
- .describe( "adds a tag for the filename" )
- .bind( &ConfigData::filenamesAsTags );
-
- cli["-c"]["--section"]
- .describe( "specify section to run" )
- .bind( &addSectionToRun, "section name" );
-
- // Less common commands which don't have a short form
- cli["--list-test-names-only"]
- .describe( "list all/matching test cases names only" )
- .bind( &ConfigData::listTestNamesOnly );
-
- cli["--list-reporters"]
- .describe( "list all reporters" )
- .bind( &ConfigData::listReporters );
-
- cli["--order"]
- .describe( "test case order (defaults to decl)" )
- .bind( &setOrder, "decl|lex|rand" );
-
- cli["--rng-seed"]
- .describe( "set a specific seed for random numbers" )
- .bind( &setRngSeed, "'time'|number" );
-
- cli["--force-colour"]
- .describe( "force colourised output (deprecated)" )
- .bind( &forceColour );
-
- cli["--use-colour"]
- .describe( "should output be colourised" )
- .bind( &setUseColour, "yes|no" );
-
- return cli;
- }
-
-} // end namespace Catch
-
-// #included from: internal/catch_list.hpp
-#define TWOBLUECUBES_CATCH_LIST_HPP_INCLUDED
-
-// #included from: catch_text.h
-#define TWOBLUECUBES_CATCH_TEXT_H_INCLUDED
-
-#define TBC_TEXT_FORMAT_CONSOLE_WIDTH CATCH_CONFIG_CONSOLE_WIDTH
-
-#define CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE Catch
-// #included from: ../external/tbc_text_format.h
-// Only use header guard if we are not using an outer namespace
-#ifndef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE
-# ifdef TWOBLUECUBES_TEXT_FORMAT_H_INCLUDED
-# ifndef TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED
-# define TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED
-# endif
-# else
-# define TWOBLUECUBES_TEXT_FORMAT_H_INCLUDED
-# endif
-#endif
-#ifndef TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED
-#include <string>
-#include <vector>
-#include <sstream>
-
-// Use optional outer namespace
-#ifdef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE
-namespace CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE {
-#endif
-
-namespace Tbc {
-
-#ifdef TBC_TEXT_FORMAT_CONSOLE_WIDTH
- const unsigned int consoleWidth = TBC_TEXT_FORMAT_CONSOLE_WIDTH;
-#else
- const unsigned int consoleWidth = 80;
-#endif
-
- struct TextAttributes {
- TextAttributes()
- : initialIndent( std::string::npos ),
- indent( 0 ),
- width( consoleWidth-1 )
- {}
-
- TextAttributes& setInitialIndent( std::size_t _value ) { initialIndent = _value; return *this; }
- TextAttributes& setIndent( std::size_t _value ) { indent = _value; return *this; }
- TextAttributes& setWidth( std::size_t _value ) { width = _value; return *this; }
-
- std::size_t initialIndent; // indent of first line, or npos
- std::size_t indent; // indent of subsequent lines, or all if initialIndent is npos
- std::size_t width; // maximum width of text, including indent. Longer text will wrap
- };
-
- class Text {
- public:
- Text( std::string const& _str, TextAttributes const& _attr = TextAttributes() )
- : attr( _attr )
- {
- const std::string wrappableBeforeChars = "[({<\t";
- const std::string wrappableAfterChars = "])}>-,./|\\";
- const std::string wrappableInsteadOfChars = " \n\r";
- std::string indent = _attr.initialIndent != std::string::npos
- ? std::string( _attr.initialIndent, ' ' )
- : std::string( _attr.indent, ' ' );
-
- typedef std::string::const_iterator iterator;
- iterator it = _str.begin();
- const iterator strEnd = _str.end();
-
- while( it != strEnd ) {
-
- if( lines.size() >= 1000 ) {
- lines.push_back( "... message truncated due to excessive size" );
- return;
- }
-
- std::string suffix;
- std::size_t width = (std::min)( static_cast<size_t>( strEnd-it ), _attr.width-static_cast<size_t>( indent.size() ) );
- iterator itEnd = it+width;
- iterator itNext = _str.end();
-
- iterator itNewLine = std::find( it, itEnd, '\n' );
- if( itNewLine != itEnd )
- itEnd = itNewLine;
-
- if( itEnd != strEnd ) {
- bool foundWrapPoint = false;
- iterator findIt = itEnd;
- do {
- if( wrappableAfterChars.find( *findIt ) != std::string::npos && findIt != itEnd ) {
- itEnd = findIt+1;
- itNext = findIt+1;
- foundWrapPoint = true;
- }
- else if( findIt > it && wrappableBeforeChars.find( *findIt ) != std::string::npos ) {
- itEnd = findIt;
- itNext = findIt;
- foundWrapPoint = true;
- }
- else if( wrappableInsteadOfChars.find( *findIt ) != std::string::npos ) {
- itNext = findIt+1;
- itEnd = findIt;
- foundWrapPoint = true;
- }
- if( findIt == it )
- break;
- else
- --findIt;
- }
- while( !foundWrapPoint );
-
- if( !foundWrapPoint ) {
- // No good wrap char, so we'll break mid word and add a hyphen
- --itEnd;
- itNext = itEnd;
- suffix = "-";
- }
- else {
- while( itEnd > it && wrappableInsteadOfChars.find( *(itEnd-1) ) != std::string::npos )
- --itEnd;
- }
- }
- lines.push_back( indent + std::string( it, itEnd ) + suffix );
-
- if( indent.size() != _attr.indent )
- indent = std::string( _attr.indent, ' ' );
- it = itNext;
- }
- }
-
- typedef std::vector<std::string>::const_iterator const_iterator;
-
- const_iterator begin() const { return lines.begin(); }
- const_iterator end() const { return lines.end(); }
- std::string const& last() const { return lines.back(); }
- std::size_t size() const { return lines.size(); }
- std::string const& operator[]( std::size_t _index ) const { return lines[_index]; }
- std::string toString() const {
- std::ostringstream oss;
- oss << *this;
- return oss.str();
- }
-
- inline friend std::ostream& operator << ( std::ostream& _stream, Text const& _text ) {
- for( Text::const_iterator it = _text.begin(), itEnd = _text.end();
- it != itEnd; ++it ) {
- if( it != _text.begin() )
- _stream << "\n";
- _stream << *it;
- }
- return _stream;
- }
-
- private:
- std::string str;
- TextAttributes attr;
- std::vector<std::string> lines;
- };
-
-} // end namespace Tbc
-
-#ifdef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE
-} // end outer namespace
-#endif
-
-#endif // TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED
-#undef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE
-
-namespace Catch {
- using Tbc::Text;
- using Tbc::TextAttributes;
-}
-
-// #included from: catch_console_colour.hpp
-#define TWOBLUECUBES_CATCH_CONSOLE_COLOUR_HPP_INCLUDED
-
-namespace Catch {
-
- struct Colour {
- enum Code {
- None = 0,
-
- White,
- Red,
- Green,
- Blue,
- Cyan,
- Yellow,
- Grey,
-
- Bright = 0x10,
-
- BrightRed = Bright | Red,
- BrightGreen = Bright | Green,
- LightGrey = Bright | Grey,
- BrightWhite = Bright | White,
-
- // By intention
- FileName = LightGrey,
- Warning = Yellow,
- ResultError = BrightRed,
- ResultSuccess = BrightGreen,
- ResultExpectedFailure = Warning,
-
- Error = BrightRed,
- Success = Green,
-
- OriginalExpression = Cyan,
- ReconstructedExpression = Yellow,
-
- SecondaryText = LightGrey,
- Headers = White
- };
-
- // Use constructed object for RAII guard
- Colour( Code _colourCode );
- Colour( Colour const& other );
- ~Colour();
-
- // Use static method for one-shot changes
- static void use( Code _colourCode );
-
- private:
- bool m_moved;
- };
-
- inline std::ostream& operator << ( std::ostream& os, Colour const& ) { return os; }
-
-} // end namespace Catch
-
-// #included from: catch_interfaces_reporter.h
-#define TWOBLUECUBES_CATCH_INTERFACES_REPORTER_H_INCLUDED
-
-#include <string>
-#include <ostream>
-#include <map>
-
-namespace Catch
-{
- struct ReporterConfig {
- explicit ReporterConfig( Ptr<IConfig const> const& _fullConfig )
- : m_stream( &_fullConfig->stream() ), m_fullConfig( _fullConfig ) {}
-
- ReporterConfig( Ptr<IConfig const> const& _fullConfig, std::ostream& _stream )
- : m_stream( &_stream ), m_fullConfig( _fullConfig ) {}
-
- std::ostream& stream() const { return *m_stream; }
- Ptr<IConfig const> fullConfig() const { return m_fullConfig; }
-
- private:
- std::ostream* m_stream;
- Ptr<IConfig const> m_fullConfig;
- };
-
- struct ReporterPreferences {
- ReporterPreferences()
- : shouldRedirectStdOut( false )
- {}
-
- bool shouldRedirectStdOut;
- };
-
- template<typename T>
- struct LazyStat : Option<T> {
- LazyStat() : used( false ) {}
- LazyStat& operator=( T const& _value ) {
- Option<T>::operator=( _value );
- used = false;
- return *this;
- }
- void reset() {
- Option<T>::reset();
- used = false;
- }
- bool used;
- };
-
- struct TestRunInfo {
- TestRunInfo( std::string const& _name ) : name( _name ) {}
- std::string name;
- };
- struct GroupInfo {
- GroupInfo( std::string const& _name,
- std::size_t _groupIndex,
- std::size_t _groupsCount )
- : name( _name ),
- groupIndex( _groupIndex ),
- groupsCounts( _groupsCount )
- {}
-
- std::string name;
- std::size_t groupIndex;
- std::size_t groupsCounts;
- };
-
- struct AssertionStats {
- AssertionStats( AssertionResult const& _assertionResult,
- std::vector<MessageInfo> const& _infoMessages,
- Totals const& _totals )
- : assertionResult( _assertionResult ),
- infoMessages( _infoMessages ),
- totals( _totals )
- {
- if( assertionResult.hasMessage() ) {
- // Copy message into messages list.
- // !TBD This should have been done earlier, somewhere
- MessageBuilder builder( assertionResult.getTestMacroName(), assertionResult.getSourceInfo(), assertionResult.getResultType() );
- builder << assertionResult.getMessage();
- builder.m_info.message = builder.m_stream.str();
-
- infoMessages.push_back( builder.m_info );
- }
- }
- virtual ~AssertionStats();
-
-# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS
- AssertionStats( AssertionStats const& ) = default;
- AssertionStats( AssertionStats && ) = default;
- AssertionStats& operator = ( AssertionStats const& ) = default;
- AssertionStats& operator = ( AssertionStats && ) = default;
-# endif
-
- AssertionResult assertionResult;
- std::vector<MessageInfo> infoMessages;
- Totals totals;
- };
-
- struct SectionStats {
- SectionStats( SectionInfo const& _sectionInfo,
- Counts const& _assertions,
- double _durationInSeconds,
- bool _missingAssertions )
- : sectionInfo( _sectionInfo ),
- assertions( _assertions ),
- durationInSeconds( _durationInSeconds ),
- missingAssertions( _missingAssertions )
- {}
- virtual ~SectionStats();
-# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS
- SectionStats( SectionStats const& ) = default;
- SectionStats( SectionStats && ) = default;
- SectionStats& operator = ( SectionStats const& ) = default;
- SectionStats& operator = ( SectionStats && ) = default;
-# endif
-
- SectionInfo sectionInfo;
- Counts assertions;
- double durationInSeconds;
- bool missingAssertions;
- };
-
- struct TestCaseStats {
- TestCaseStats( TestCaseInfo const& _testInfo,
- Totals const& _totals,
- std::string const& _stdOut,
- std::string const& _stdErr,
- bool _aborting )
- : testInfo( _testInfo ),
- totals( _totals ),
- stdOut( _stdOut ),
- stdErr( _stdErr ),
- aborting( _aborting )
- {}
- virtual ~TestCaseStats();
-
-# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS
- TestCaseStats( TestCaseStats const& ) = default;
- TestCaseStats( TestCaseStats && ) = default;
- TestCaseStats& operator = ( TestCaseStats const& ) = default;
- TestCaseStats& operator = ( TestCaseStats && ) = default;
-# endif
-
- TestCaseInfo testInfo;
- Totals totals;
- std::string stdOut;
- std::string stdErr;
- bool aborting;
- };
-
- struct TestGroupStats {
- TestGroupStats( GroupInfo const& _groupInfo,
- Totals const& _totals,
- bool _aborting )
- : groupInfo( _groupInfo ),
- totals( _totals ),
- aborting( _aborting )
- {}
- TestGroupStats( GroupInfo const& _groupInfo )
- : groupInfo( _groupInfo ),
- aborting( false )
- {}
- virtual ~TestGroupStats();
-
-# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS
- TestGroupStats( TestGroupStats const& ) = default;
- TestGroupStats( TestGroupStats && ) = default;
- TestGroupStats& operator = ( TestGroupStats const& ) = default;
- TestGroupStats& operator = ( TestGroupStats && ) = default;
-# endif
-
- GroupInfo groupInfo;
- Totals totals;
- bool aborting;
- };
-
- struct TestRunStats {
- TestRunStats( TestRunInfo const& _runInfo,
- Totals const& _totals,
- bool _aborting )
- : runInfo( _runInfo ),
- totals( _totals ),
- aborting( _aborting )
- {}
- virtual ~TestRunStats();
-
-# ifndef CATCH_CONFIG_CPP11_GENERATED_METHODS
- TestRunStats( TestRunStats const& _other )
- : runInfo( _other.runInfo ),
- totals( _other.totals ),
- aborting( _other.aborting )
- {}
-# else
- TestRunStats( TestRunStats const& ) = default;
- TestRunStats( TestRunStats && ) = default;
- TestRunStats& operator = ( TestRunStats const& ) = default;
- TestRunStats& operator = ( TestRunStats && ) = default;
-# endif
-
- TestRunInfo runInfo;
- Totals totals;
- bool aborting;
- };
-
- class MultipleReporters;
-
- struct IStreamingReporter : IShared {
- virtual ~IStreamingReporter();
-
- // Implementing class must also provide the following static method:
- // static std::string getDescription();
-
- virtual ReporterPreferences getPreferences() const = 0;
-
- virtual void noMatchingTestCases( std::string const& spec ) = 0;
-
- virtual void testRunStarting( TestRunInfo const& testRunInfo ) = 0;
- virtual void testGroupStarting( GroupInfo const& groupInfo ) = 0;
-
- virtual void testCaseStarting( TestCaseInfo const& testInfo ) = 0;
- virtual void sectionStarting( SectionInfo const& sectionInfo ) = 0;
-
- virtual void assertionStarting( AssertionInfo const& assertionInfo ) = 0;
-
- // The return value indicates if the messages buffer should be cleared:
- virtual bool assertionEnded( AssertionStats const& assertionStats ) = 0;
-
- virtual void sectionEnded( SectionStats const& sectionStats ) = 0;
- virtual void testCaseEnded( TestCaseStats const& testCaseStats ) = 0;
- virtual void testGroupEnded( TestGroupStats const& testGroupStats ) = 0;
- virtual void testRunEnded( TestRunStats const& testRunStats ) = 0;
-
- virtual void skipTest( TestCaseInfo const& testInfo ) = 0;
-
- virtual MultipleReporters* tryAsMulti() { return CATCH_NULL; }
- };
-
- struct IReporterFactory : IShared {
- virtual ~IReporterFactory();
- virtual IStreamingReporter* create( ReporterConfig const& config ) const = 0;
- virtual std::string getDescription() const = 0;
- };
-
- struct IReporterRegistry {
- typedef std::map<std::string, Ptr<IReporterFactory> > FactoryMap;
- typedef std::vector<Ptr<IReporterFactory> > Listeners;
-
- virtual ~IReporterRegistry();
- virtual IStreamingReporter* create( std::string const& name, Ptr<IConfig const> const& config ) const = 0;
- virtual FactoryMap const& getFactories() const = 0;
- virtual Listeners const& getListeners() const = 0;
- };
-
- Ptr<IStreamingReporter> addReporter( Ptr<IStreamingReporter> const& existingReporter, Ptr<IStreamingReporter> const& additionalReporter );
-
-}
-
-#include <limits>
-#include <algorithm>
-
-namespace Catch {
-
- inline std::size_t listTests( Config const& config ) {
-
- TestSpec testSpec = config.testSpec();
- if( config.testSpec().hasFilters() )
- Catch::cout() << "Matching test cases:\n";
- else {
- Catch::cout() << "All available test cases:\n";
- testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec();
- }
-
- std::size_t matchedTests = 0;
- TextAttributes nameAttr, tagsAttr;
- nameAttr.setInitialIndent( 2 ).setIndent( 4 );
- tagsAttr.setIndent( 6 );
-
- std::vector<TestCase> matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config );
- for( std::vector<TestCase>::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end();
- it != itEnd;
- ++it ) {
- matchedTests++;
- TestCaseInfo const& testCaseInfo = it->getTestCaseInfo();
- Colour::Code colour = testCaseInfo.isHidden()
- ? Colour::SecondaryText
- : Colour::None;
- Colour colourGuard( colour );
-
- Catch::cout() << Text( testCaseInfo.name, nameAttr ) << std::endl;
- if( !testCaseInfo.tags.empty() )
- Catch::cout() << Text( testCaseInfo.tagsAsString, tagsAttr ) << std::endl;
- }
-
- if( !config.testSpec().hasFilters() )
- Catch::cout() << pluralise( matchedTests, "test case" ) << '\n' << std::endl;
- else
- Catch::cout() << pluralise( matchedTests, "matching test case" ) << '\n' << std::endl;
- return matchedTests;
- }
-
- inline std::size_t listTestsNamesOnly( Config const& config ) {
- TestSpec testSpec = config.testSpec();
- if( !config.testSpec().hasFilters() )
- testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec();
- std::size_t matchedTests = 0;
- std::vector<TestCase> matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config );
- for( std::vector<TestCase>::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end();
- it != itEnd;
- ++it ) {
- matchedTests++;
- TestCaseInfo const& testCaseInfo = it->getTestCaseInfo();
- if( startsWith( testCaseInfo.name, '#' ) )
- Catch::cout() << '"' << testCaseInfo.name << '"' << std::endl;
- else
- Catch::cout() << testCaseInfo.name << std::endl;
- }
- return matchedTests;
- }
-
- struct TagInfo {
- TagInfo() : count ( 0 ) {}
- void add( std::string const& spelling ) {
- ++count;
- spellings.insert( spelling );
- }
- std::string all() const {
- std::string out;
- for( std::set<std::string>::const_iterator it = spellings.begin(), itEnd = spellings.end();
- it != itEnd;
- ++it )
- out += "[" + *it + "]";
- return out;
- }
- std::set<std::string> spellings;
- std::size_t count;
- };
-
- inline std::size_t listTags( Config const& config ) {
- TestSpec testSpec = config.testSpec();
- if( config.testSpec().hasFilters() )
- Catch::cout() << "Tags for matching test cases:\n";
- else {
- Catch::cout() << "All available tags:\n";
- testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec();
- }
-
- std::map<std::string, TagInfo> tagCounts;
-
- std::vector<TestCase> matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config );
- for( std::vector<TestCase>::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end();
- it != itEnd;
- ++it ) {
- for( std::set<std::string>::const_iterator tagIt = it->getTestCaseInfo().tags.begin(),
- tagItEnd = it->getTestCaseInfo().tags.end();
- tagIt != tagItEnd;
- ++tagIt ) {
- std::string tagName = *tagIt;
- std::string lcaseTagName = toLower( tagName );
- std::map<std::string, TagInfo>::iterator countIt = tagCounts.find( lcaseTagName );
- if( countIt == tagCounts.end() )
- countIt = tagCounts.insert( std::make_pair( lcaseTagName, TagInfo() ) ).first;
- countIt->second.add( tagName );
- }
- }
-
- for( std::map<std::string, TagInfo>::const_iterator countIt = tagCounts.begin(),
- countItEnd = tagCounts.end();
- countIt != countItEnd;
- ++countIt ) {
- std::ostringstream oss;
- oss << " " << std::setw(2) << countIt->second.count << " ";
- Text wrapper( countIt->second.all(), TextAttributes()
- .setInitialIndent( 0 )
- .setIndent( oss.str().size() )
- .setWidth( CATCH_CONFIG_CONSOLE_WIDTH-10 ) );
- Catch::cout() << oss.str() << wrapper << '\n';
- }
- Catch::cout() << pluralise( tagCounts.size(), "tag" ) << '\n' << std::endl;
- return tagCounts.size();
- }
-
- inline std::size_t listReporters( Config const& /*config*/ ) {
- Catch::cout() << "Available reporters:\n";
- IReporterRegistry::FactoryMap const& factories = getRegistryHub().getReporterRegistry().getFactories();
- IReporterRegistry::FactoryMap::const_iterator itBegin = factories.begin(), itEnd = factories.end(), it;
- std::size_t maxNameLen = 0;
- for(it = itBegin; it != itEnd; ++it )
- maxNameLen = (std::max)( maxNameLen, it->first.size() );
-
- for(it = itBegin; it != itEnd; ++it ) {
- Text wrapper( it->second->getDescription(), TextAttributes()
- .setInitialIndent( 0 )
- .setIndent( 7+maxNameLen )
- .setWidth( CATCH_CONFIG_CONSOLE_WIDTH - maxNameLen-8 ) );
- Catch::cout() << " "
- << it->first
- << ':'
- << std::string( maxNameLen - it->first.size() + 2, ' ' )
- << wrapper << '\n';
- }
- Catch::cout() << std::endl;
- return factories.size();
- }
-
- inline Option<std::size_t> list( Config const& config ) {
- Option<std::size_t> listedCount;
- if( config.listTests() )
- listedCount = listedCount.valueOr(0) + listTests( config );
- if( config.listTestNamesOnly() )
- listedCount = listedCount.valueOr(0) + listTestsNamesOnly( config );
- if( config.listTags() )
- listedCount = listedCount.valueOr(0) + listTags( config );
- if( config.listReporters() )
- listedCount = listedCount.valueOr(0) + listReporters( config );
- return listedCount;
- }
-
-} // end namespace Catch
-
-// #included from: internal/catch_run_context.hpp
-#define TWOBLUECUBES_CATCH_RUNNER_IMPL_HPP_INCLUDED
-
-// #included from: catch_test_case_tracker.hpp
-#define TWOBLUECUBES_CATCH_TEST_CASE_TRACKER_HPP_INCLUDED
-
-#include <map>
-#include <string>
-#include <assert.h>
-#include <vector>
-#include <iterator>
-#include <stdexcept>
-
-namespace Catch {
-namespace TestCaseTracking {
-
- struct NameAndLocation {
- std::string name;
- SourceLineInfo location;
-
- NameAndLocation( std::string const& _name, SourceLineInfo const& _location )
- : name( _name ),
- location( _location )
- {}
- };
-
- struct ITracker : SharedImpl<> {
- virtual ~ITracker();
-
- // static queries
- virtual NameAndLocation const& nameAndLocation() const = 0;
-
- // dynamic queries
- virtual bool isComplete() const = 0; // Successfully completed or failed
- virtual bool isSuccessfullyCompleted() const = 0;
- virtual bool isOpen() const = 0; // Started but not complete
- virtual bool hasChildren() const = 0;
-
- virtual ITracker& parent() = 0;
-
- // actions
- virtual void close() = 0; // Successfully complete
- virtual void fail() = 0;
- virtual void markAsNeedingAnotherRun() = 0;
-
- virtual void addChild( Ptr<ITracker> const& child ) = 0;
- virtual ITracker* findChild( NameAndLocation const& nameAndLocation ) = 0;
- virtual void openChild() = 0;
-
- // Debug/ checking
- virtual bool isSectionTracker() const = 0;
- virtual bool isIndexTracker() const = 0;
- };
-
- class TrackerContext {
-
- enum RunState {
- NotStarted,
- Executing,
- CompletedCycle
- };
-
- Ptr<ITracker> m_rootTracker;
- ITracker* m_currentTracker;
- RunState m_runState;
-
- public:
-
- static TrackerContext& instance() {
- static TrackerContext s_instance;
- return s_instance;
- }
-
- TrackerContext()
- : m_currentTracker( CATCH_NULL ),
- m_runState( NotStarted )
- {}
-
- ITracker& startRun();
-
- void endRun() {
- m_rootTracker.reset();
- m_currentTracker = CATCH_NULL;
- m_runState = NotStarted;
- }
-
- void startCycle() {
- m_currentTracker = m_rootTracker.get();
- m_runState = Executing;
- }
- void completeCycle() {
- m_runState = CompletedCycle;
- }
-
- bool completedCycle() const {
- return m_runState == CompletedCycle;
- }
- ITracker& currentTracker() {
- return *m_currentTracker;
- }
- void setCurrentTracker( ITracker* tracker ) {
- m_currentTracker = tracker;
- }
- };
-
- class TrackerBase : public ITracker {
- protected:
- enum CycleState {
- NotStarted,
- Executing,
- ExecutingChildren,
- NeedsAnotherRun,
- CompletedSuccessfully,
- Failed
- };
- class TrackerHasName {
- NameAndLocation m_nameAndLocation;
- public:
- TrackerHasName( NameAndLocation const& nameAndLocation ) : m_nameAndLocation( nameAndLocation ) {}
- bool operator ()( Ptr<ITracker> const& tracker ) {
- return
- tracker->nameAndLocation().name == m_nameAndLocation.name &&
- tracker->nameAndLocation().location == m_nameAndLocation.location;
- }
- };
- typedef std::vector<Ptr<ITracker> > Children;
- NameAndLocation m_nameAndLocation;
- TrackerContext& m_ctx;
- ITracker* m_parent;
- Children m_children;
- CycleState m_runState;
- public:
- TrackerBase( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent )
- : m_nameAndLocation( nameAndLocation ),
- m_ctx( ctx ),
- m_parent( parent ),
- m_runState( NotStarted )
- {}
- virtual ~TrackerBase();
-
- virtual NameAndLocation const& nameAndLocation() const CATCH_OVERRIDE {
- return m_nameAndLocation;
- }
- virtual bool isComplete() const CATCH_OVERRIDE {
- return m_runState == CompletedSuccessfully || m_runState == Failed;
- }
- virtual bool isSuccessfullyCompleted() const CATCH_OVERRIDE {
- return m_runState == CompletedSuccessfully;
- }
- virtual bool isOpen() const CATCH_OVERRIDE {
- return m_runState != NotStarted && !isComplete();
- }
- virtual bool hasChildren() const CATCH_OVERRIDE {
- return !m_children.empty();
- }
-
- virtual void addChild( Ptr<ITracker> const& child ) CATCH_OVERRIDE {
- m_children.push_back( child );
- }
-
- virtual ITracker* findChild( NameAndLocation const& nameAndLocation ) CATCH_OVERRIDE {
- Children::const_iterator it = std::find_if( m_children.begin(), m_children.end(), TrackerHasName( nameAndLocation ) );
- return( it != m_children.end() )
- ? it->get()
- : CATCH_NULL;
- }
- virtual ITracker& parent() CATCH_OVERRIDE {
- assert( m_parent ); // Should always be non-null except for root
- return *m_parent;
- }
-
- virtual void openChild() CATCH_OVERRIDE {
- if( m_runState != ExecutingChildren ) {
- m_runState = ExecutingChildren;
- if( m_parent )
- m_parent->openChild();
- }
- }
-
- virtual bool isSectionTracker() const CATCH_OVERRIDE { return false; }
- virtual bool isIndexTracker() const CATCH_OVERRIDE { return false; }
-
- void open() {
- m_runState = Executing;
- moveToThis();
- if( m_parent )
- m_parent->openChild();
- }
-
- virtual void close() CATCH_OVERRIDE {
-
- // Close any still open children (e.g. generators)
- while( &m_ctx.currentTracker() != this )
- m_ctx.currentTracker().close();
-
- switch( m_runState ) {
- case NotStarted:
- case CompletedSuccessfully:
- case Failed:
- throw std::logic_error( "Illogical state" );
-
- case NeedsAnotherRun:
- break;;
-
- case Executing:
- m_runState = CompletedSuccessfully;
- break;
- case ExecutingChildren:
- if( m_children.empty() || m_children.back()->isComplete() )
- m_runState = CompletedSuccessfully;
- break;
-
- default:
- throw std::logic_error( "Unexpected state" );
- }
- moveToParent();
- m_ctx.completeCycle();
- }
- virtual void fail() CATCH_OVERRIDE {
- m_runState = Failed;
- if( m_parent )
- m_parent->markAsNeedingAnotherRun();
- moveToParent();
- m_ctx.completeCycle();
- }
- virtual void markAsNeedingAnotherRun() CATCH_OVERRIDE {
- m_runState = NeedsAnotherRun;
- }
- private:
- void moveToParent() {
- assert( m_parent );
- m_ctx.setCurrentTracker( m_parent );
- }
- void moveToThis() {
- m_ctx.setCurrentTracker( this );
- }
- };
-
- class SectionTracker : public TrackerBase {
- std::vector<std::string> m_filters;
- public:
- SectionTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent )
- : TrackerBase( nameAndLocation, ctx, parent )
- {
- if( parent ) {
- while( !parent->isSectionTracker() )
- parent = &parent->parent();
-
- SectionTracker& parentSection = static_cast<SectionTracker&>( *parent );
- addNextFilters( parentSection.m_filters );
- }
- }
- virtual ~SectionTracker();
-
- virtual bool isSectionTracker() const CATCH_OVERRIDE { return true; }
-
- static SectionTracker& acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation ) {
- SectionTracker* section = CATCH_NULL;
-
- ITracker& currentTracker = ctx.currentTracker();
- if( ITracker* childTracker = currentTracker.findChild( nameAndLocation ) ) {
- assert( childTracker );
- assert( childTracker->isSectionTracker() );
- section = static_cast<SectionTracker*>( childTracker );
- }
- else {
- section = new SectionTracker( nameAndLocation, ctx, &currentTracker );
- currentTracker.addChild( section );
- }
- if( !ctx.completedCycle() )
- section->tryOpen();
- return *section;
- }
-
- void tryOpen() {
- if( !isComplete() && (m_filters.empty() || m_filters[0].empty() || m_filters[0] == m_nameAndLocation.name ) )
- open();
- }
-
- void addInitialFilters( std::vector<std::string> const& filters ) {
- if( !filters.empty() ) {
- m_filters.push_back(""); // Root - should never be consulted
- m_filters.push_back(""); // Test Case - not a section filter
- std::copy( filters.begin(), filters.end(), std::back_inserter( m_filters ) );
- }
- }
- void addNextFilters( std::vector<std::string> const& filters ) {
- if( filters.size() > 1 )
- std::copy( filters.begin()+1, filters.end(), std::back_inserter( m_filters ) );
- }
- };
-
- class IndexTracker : public TrackerBase {
- int m_size;
- int m_index;
- public:
- IndexTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent, int size )
- : TrackerBase( nameAndLocation, ctx, parent ),
- m_size( size ),
- m_index( -1 )
- {}
- virtual ~IndexTracker();
-
- virtual bool isIndexTracker() const CATCH_OVERRIDE { return true; }
-
- static IndexTracker& acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation, int size ) {
- IndexTracker* tracker = CATCH_NULL;
-
- ITracker& currentTracker = ctx.currentTracker();
- if( ITracker* childTracker = currentTracker.findChild( nameAndLocation ) ) {
- assert( childTracker );
- assert( childTracker->isIndexTracker() );
- tracker = static_cast<IndexTracker*>( childTracker );
- }
- else {
- tracker = new IndexTracker( nameAndLocation, ctx, &currentTracker, size );
- currentTracker.addChild( tracker );
- }
-
- if( !ctx.completedCycle() && !tracker->isComplete() ) {
- if( tracker->m_runState != ExecutingChildren && tracker->m_runState != NeedsAnotherRun )
- tracker->moveNext();
- tracker->open();
- }
-
- return *tracker;
- }
-
- int index() const { return m_index; }
-
- void moveNext() {
- m_index++;
- m_children.clear();
- }
-
- virtual void close() CATCH_OVERRIDE {
- TrackerBase::close();
- if( m_runState == CompletedSuccessfully && m_index < m_size-1 )
- m_runState = Executing;
- }
- };
-
- inline ITracker& TrackerContext::startRun() {
- m_rootTracker = new SectionTracker( NameAndLocation( "{root}", CATCH_INTERNAL_LINEINFO ), *this, CATCH_NULL );
- m_currentTracker = CATCH_NULL;
- m_runState = Executing;
- return *m_rootTracker;
- }
-
-} // namespace TestCaseTracking
-
-using TestCaseTracking::ITracker;
-using TestCaseTracking::TrackerContext;
-using TestCaseTracking::SectionTracker;
-using TestCaseTracking::IndexTracker;
-
-} // namespace Catch
-
-// #included from: catch_fatal_condition.hpp
-#define TWOBLUECUBES_CATCH_FATAL_CONDITION_H_INCLUDED
-
-namespace Catch {
-
- // Report the error condition
- inline void reportFatal( std::string const& message ) {
- IContext& context = Catch::getCurrentContext();
- IResultCapture* resultCapture = context.getResultCapture();
- resultCapture->handleFatalErrorCondition( message );
- }
-
-} // namespace Catch
-
-#if defined ( CATCH_PLATFORM_WINDOWS ) /////////////////////////////////////////
-// #included from: catch_windows_h_proxy.h
-
-#define TWOBLUECUBES_CATCH_WINDOWS_H_PROXY_H_INCLUDED
-
-#ifdef CATCH_DEFINES_NOMINMAX
-# define NOMINMAX
-#endif
-#ifdef CATCH_DEFINES_WIN32_LEAN_AND_MEAN
-# define WIN32_LEAN_AND_MEAN
-#endif
-
-#ifdef __AFXDLL
-#include <AfxWin.h>
-#else
-#include <windows.h>
-#endif
-
-#ifdef CATCH_DEFINES_NOMINMAX
-# undef NOMINMAX
-#endif
-#ifdef CATCH_DEFINES_WIN32_LEAN_AND_MEAN
-# undef WIN32_LEAN_AND_MEAN
-#endif
-
-
-# if !defined ( CATCH_CONFIG_WINDOWS_SEH )
-
-namespace Catch {
- struct FatalConditionHandler {
- void reset() {}
- };
-}
-
-# else // CATCH_CONFIG_WINDOWS_SEH is defined
-
-namespace Catch {
-
- struct SignalDefs { DWORD id; const char* name; };
- extern SignalDefs signalDefs[];
- // There is no 1-1 mapping between signals and windows exceptions.
- // Windows can easily distinguish between SO and SigSegV,
- // but SigInt, SigTerm, etc are handled differently.
- SignalDefs signalDefs[] = {
- { EXCEPTION_ILLEGAL_INSTRUCTION, "SIGILL - Illegal instruction signal" },
- { EXCEPTION_STACK_OVERFLOW, "SIGSEGV - Stack overflow" },
- { EXCEPTION_ACCESS_VIOLATION, "SIGSEGV - Segmentation violation signal" },
- { EXCEPTION_INT_DIVIDE_BY_ZERO, "Divide by zero error" },
- };
-
- struct FatalConditionHandler {
-
- static LONG CALLBACK handleVectoredException(PEXCEPTION_POINTERS ExceptionInfo) {
- for (int i = 0; i < sizeof(signalDefs) / sizeof(SignalDefs); ++i) {
- if (ExceptionInfo->ExceptionRecord->ExceptionCode == signalDefs[i].id) {
- reset();
- reportFatal(signalDefs[i].name);
- }
- }
- // If its not an exception we care about, pass it along.
- // This stops us from eating debugger breaks etc.
- return EXCEPTION_CONTINUE_SEARCH;
- }
-
- FatalConditionHandler() {
- isSet = true;
- // 32k seems enough for Catch to handle stack overflow,
- // but the value was found experimentally, so there is no strong guarantee
- guaranteeSize = 32 * 1024;
- exceptionHandlerHandle = CATCH_NULL;
- // Register as first handler in current chain
- exceptionHandlerHandle = AddVectoredExceptionHandler(1, handleVectoredException);
- // Pass in guarantee size to be filled
- SetThreadStackGuarantee(&guaranteeSize);
- }
-
- static void reset() {
- if (isSet) {
- // Unregister handler and restore the old guarantee
- RemoveVectoredExceptionHandler(exceptionHandlerHandle);
- SetThreadStackGuarantee(&guaranteeSize);
- exceptionHandlerHandle = CATCH_NULL;
- isSet = false;
- }
- }
-
- ~FatalConditionHandler() {
- reset();
- }
- private:
- static bool isSet;
- static ULONG guaranteeSize;
- static PVOID exceptionHandlerHandle;
- };
-
- bool FatalConditionHandler::isSet = false;
- ULONG FatalConditionHandler::guaranteeSize = 0;
- PVOID FatalConditionHandler::exceptionHandlerHandle = CATCH_NULL;
-
-} // namespace Catch
-
-# endif // CATCH_CONFIG_WINDOWS_SEH
-
-#else // Not Windows - assumed to be POSIX compatible //////////////////////////
-
-#include <signal.h>
-
-namespace Catch {
-
- struct SignalDefs {
- int id;
- const char* name;
- };
- extern SignalDefs signalDefs[];
- SignalDefs signalDefs[] = {
- { SIGINT, "SIGINT - Terminal interrupt signal" },
- { SIGILL, "SIGILL - Illegal instruction signal" },
- { SIGFPE, "SIGFPE - Floating point error signal" },
- { SIGSEGV, "SIGSEGV - Segmentation violation signal" },
- { SIGTERM, "SIGTERM - Termination request signal" },
- { SIGABRT, "SIGABRT - Abort (abnormal termination) signal" }
- };
-
- struct FatalConditionHandler {
-
- static bool isSet;
- static struct sigaction oldSigActions [sizeof(signalDefs)/sizeof(SignalDefs)];
- static stack_t oldSigStack;
- static char altStackMem[SIGSTKSZ];
-
- static void handleSignal( int sig ) {
- std::string name = "<unknown signal>";
- for (std::size_t i = 0; i < sizeof(signalDefs) / sizeof(SignalDefs); ++i) {
- SignalDefs &def = signalDefs[i];
- if (sig == def.id) {
- name = def.name;
- break;
- }
- }
- reset();
- reportFatal(name);
- raise( sig );
- }
-
- FatalConditionHandler() {
- isSet = true;
- stack_t sigStack;
- sigStack.ss_sp = altStackMem;
- sigStack.ss_size = SIGSTKSZ;
- sigStack.ss_flags = 0;
- sigaltstack(&sigStack, &oldSigStack);
- struct sigaction sa = { 0 };
-
- sa.sa_handler = handleSignal;
- sa.sa_flags = SA_ONSTACK;
- for (std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i) {
- sigaction(signalDefs[i].id, &sa, &oldSigActions[i]);
- }
- }
-
- ~FatalConditionHandler() {
- reset();
- }
- static void reset() {
- if( isSet ) {
- // Set signals back to previous values -- hopefully nobody overwrote them in the meantime
- for( std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i ) {
- sigaction(signalDefs[i].id, &oldSigActions[i], CATCH_NULL);
- }
- // Return the old stack
- sigaltstack(&oldSigStack, CATCH_NULL);
- isSet = false;
- }
- }
- };
-
- bool FatalConditionHandler::isSet = false;
- struct sigaction FatalConditionHandler::oldSigActions[sizeof(signalDefs)/sizeof(SignalDefs)] = {};
- stack_t FatalConditionHandler::oldSigStack = {};
- char FatalConditionHandler::altStackMem[SIGSTKSZ] = {};
-
-} // namespace Catch
-
-#endif // not Windows
-
-#include <set>
-#include <string>
-
-namespace Catch {
-
- class StreamRedirect {
-
- public:
- StreamRedirect( std::ostream& stream, std::string& targetString )
- : m_stream( stream ),
- m_prevBuf( stream.rdbuf() ),
- m_targetString( targetString )
- {
- stream.rdbuf( m_oss.rdbuf() );
- }
-
- ~StreamRedirect() {
- m_targetString += m_oss.str();
- m_stream.rdbuf( m_prevBuf );
- }
-
- private:
- std::ostream& m_stream;
- std::streambuf* m_prevBuf;
- std::ostringstream m_oss;
- std::string& m_targetString;
- };
-
- ///////////////////////////////////////////////////////////////////////////
-
- class RunContext : public IResultCapture, public IRunner {
-
- RunContext( RunContext const& );
- void operator =( RunContext const& );
-
- public:
-
- explicit RunContext( Ptr<IConfig const> const& _config, Ptr<IStreamingReporter> const& reporter )
- : m_runInfo( _config->name() ),
- m_context( getCurrentMutableContext() ),
- m_activeTestCase( CATCH_NULL ),
- m_config( _config ),
- m_reporter( reporter )
- {
- m_context.setRunner( this );
- m_context.setConfig( m_config );
- m_context.setResultCapture( this );
- m_reporter->testRunStarting( m_runInfo );
- }
-
- virtual ~RunContext() {
- m_reporter->testRunEnded( TestRunStats( m_runInfo, m_totals, aborting() ) );
- }
-
- void testGroupStarting( std::string const& testSpec, std::size_t groupIndex, std::size_t groupsCount ) {
- m_reporter->testGroupStarting( GroupInfo( testSpec, groupIndex, groupsCount ) );
- }
- void testGroupEnded( std::string const& testSpec, Totals const& totals, std::size_t groupIndex, std::size_t groupsCount ) {
- m_reporter->testGroupEnded( TestGroupStats( GroupInfo( testSpec, groupIndex, groupsCount ), totals, aborting() ) );
- }
-
- Totals runTest( TestCase const& testCase ) {
- Totals prevTotals = m_totals;
-
- std::string redirectedCout;
- std::string redirectedCerr;
-
- TestCaseInfo testInfo = testCase.getTestCaseInfo();
-
- m_reporter->testCaseStarting( testInfo );
-
- m_activeTestCase = &testCase;
-
- do {
- ITracker& rootTracker = m_trackerContext.startRun();
- assert( rootTracker.isSectionTracker() );
- static_cast<SectionTracker&>( rootTracker ).addInitialFilters( m_config->getSectionsToRun() );
- do {
- m_trackerContext.startCycle();
- m_testCaseTracker = &SectionTracker::acquire( m_trackerContext, TestCaseTracking::NameAndLocation( testInfo.name, testInfo.lineInfo ) );
- runCurrentTest( redirectedCout, redirectedCerr );
- }
- while( !m_testCaseTracker->isSuccessfullyCompleted() && !aborting() );
- }
- // !TBD: deprecated - this will be replaced by indexed trackers
- while( getCurrentContext().advanceGeneratorsForCurrentTest() && !aborting() );
-
- Totals deltaTotals = m_totals.delta( prevTotals );
- if( testInfo.expectedToFail() && deltaTotals.testCases.passed > 0 ) {
- deltaTotals.assertions.failed++;
- deltaTotals.testCases.passed--;
- deltaTotals.testCases.failed++;
- }
- m_totals.testCases += deltaTotals.testCases;
- m_reporter->testCaseEnded( TestCaseStats( testInfo,
- deltaTotals,
- redirectedCout,
- redirectedCerr,
- aborting() ) );
-
- m_activeTestCase = CATCH_NULL;
- m_testCaseTracker = CATCH_NULL;
-
- return deltaTotals;
- }
-
- Ptr<IConfig const> config() const {
- return m_config;
- }
-
- private: // IResultCapture
-
- virtual void assertionEnded( AssertionResult const& result ) {
- if( result.getResultType() == ResultWas::Ok ) {
- m_totals.assertions.passed++;
- }
- else if( !result.isOk() ) {
- m_totals.assertions.failed++;
- }
-
- if( m_reporter->assertionEnded( AssertionStats( result, m_messages, m_totals ) ) )
- m_messages.clear();
-
- // Reset working state
- m_lastAssertionInfo = AssertionInfo( std::string(), m_lastAssertionInfo.lineInfo, "{Unknown expression after the reported line}" , m_lastAssertionInfo.resultDisposition );
- m_lastResult = result;
- }
-
- virtual bool sectionStarted (
- SectionInfo const& sectionInfo,
- Counts& assertions
- )
- {
- ITracker& sectionTracker = SectionTracker::acquire( m_trackerContext, TestCaseTracking::NameAndLocation( sectionInfo.name, sectionInfo.lineInfo ) );
- if( !sectionTracker.isOpen() )
- return false;
- m_activeSections.push_back( &sectionTracker );
-
- m_lastAssertionInfo.lineInfo = sectionInfo.lineInfo;
-
- m_reporter->sectionStarting( sectionInfo );
-
- assertions = m_totals.assertions;
-
- return true;
- }
- bool testForMissingAssertions( Counts& assertions ) {
- if( assertions.total() != 0 )
- return false;
- if( !m_config->warnAboutMissingAssertions() )
- return false;
- if( m_trackerContext.currentTracker().hasChildren() )
- return false;
- m_totals.assertions.failed++;
- assertions.failed++;
- return true;
- }
-
- virtual void sectionEnded( SectionEndInfo const& endInfo ) {
- Counts assertions = m_totals.assertions - endInfo.prevAssertions;
- bool missingAssertions = testForMissingAssertions( assertions );
-
- if( !m_activeSections.empty() ) {
- m_activeSections.back()->close();
- m_activeSections.pop_back();
- }
-
- m_reporter->sectionEnded( SectionStats( endInfo.sectionInfo, assertions, endInfo.durationInSeconds, missingAssertions ) );
- m_messages.clear();
- }
-
- virtual void sectionEndedEarly( SectionEndInfo const& endInfo ) {
- if( m_unfinishedSections.empty() )
- m_activeSections.back()->fail();
- else
- m_activeSections.back()->close();
- m_activeSections.pop_back();
-
- m_unfinishedSections.push_back( endInfo );
- }
-
- virtual void pushScopedMessage( MessageInfo const& message ) {
- m_messages.push_back( message );
- }
-
- virtual void popScopedMessage( MessageInfo const& message ) {
- m_messages.erase( std::remove( m_messages.begin(), m_messages.end(), message ), m_messages.end() );
- }
-
- virtual std::string getCurrentTestName() const {
- return m_activeTestCase
- ? m_activeTestCase->getTestCaseInfo().name
- : std::string();
- }
-
- virtual const AssertionResult* getLastResult() const {
- return &m_lastResult;
- }
-
- virtual void handleFatalErrorCondition( std::string const& message ) {
- ResultBuilder resultBuilder = makeUnexpectedResultBuilder();
- resultBuilder.setResultType( ResultWas::FatalErrorCondition );
- resultBuilder << message;
- resultBuilder.captureExpression();
-
- handleUnfinishedSections();
-
- // Recreate section for test case (as we will lose the one that was in scope)
- TestCaseInfo const& testCaseInfo = m_activeTestCase->getTestCaseInfo();
- SectionInfo testCaseSection( testCaseInfo.lineInfo, testCaseInfo.name, testCaseInfo.description );
-
- Counts assertions;
- assertions.failed = 1;
- SectionStats testCaseSectionStats( testCaseSection, assertions, 0, false );
- m_reporter->sectionEnded( testCaseSectionStats );
-
- TestCaseInfo testInfo = m_activeTestCase->getTestCaseInfo();
-
- Totals deltaTotals;
- deltaTotals.testCases.failed = 1;
- m_reporter->testCaseEnded( TestCaseStats( testInfo,
- deltaTotals,
- std::string(),
- std::string(),
- false ) );
- m_totals.testCases.failed++;
- testGroupEnded( std::string(), m_totals, 1, 1 );
- m_reporter->testRunEnded( TestRunStats( m_runInfo, m_totals, false ) );
- }
-
- public:
- // !TBD We need to do this another way!
- bool aborting() const {
- return m_totals.assertions.failed == static_cast<std::size_t>( m_config->abortAfter() );
- }
-
- private:
-
- void runCurrentTest( std::string& redirectedCout, std::string& redirectedCerr ) {
- TestCaseInfo const& testCaseInfo = m_activeTestCase->getTestCaseInfo();
- SectionInfo testCaseSection( testCaseInfo.lineInfo, testCaseInfo.name, testCaseInfo.description );
- m_reporter->sectionStarting( testCaseSection );
- Counts prevAssertions = m_totals.assertions;
- double duration = 0;
- try {
- m_lastAssertionInfo = AssertionInfo( "TEST_CASE", testCaseInfo.lineInfo, std::string(), ResultDisposition::Normal );
-
- seedRng( *m_config );
-
- Timer timer;
- timer.start();
- if( m_reporter->getPreferences().shouldRedirectStdOut ) {
- StreamRedirect coutRedir( Catch::cout(), redirectedCout );
- StreamRedirect cerrRedir( Catch::cerr(), redirectedCerr );
- invokeActiveTestCase();
- }
- else {
- invokeActiveTestCase();
- }
- duration = timer.getElapsedSeconds();
- }
- catch( TestFailureException& ) {
- // This just means the test was aborted due to failure
- }
- catch(...) {
- makeUnexpectedResultBuilder().useActiveException();
- }
- m_testCaseTracker->close();
- handleUnfinishedSections();
- m_messages.clear();
-
- Counts assertions = m_totals.assertions - prevAssertions;
- bool missingAssertions = testForMissingAssertions( assertions );
-
- if( testCaseInfo.okToFail() ) {
- std::swap( assertions.failedButOk, assertions.failed );
- m_totals.assertions.failed -= assertions.failedButOk;
- m_totals.assertions.failedButOk += assertions.failedButOk;
- }
-
- SectionStats testCaseSectionStats( testCaseSection, assertions, duration, missingAssertions );
- m_reporter->sectionEnded( testCaseSectionStats );
- }
-
- void invokeActiveTestCase() {
- FatalConditionHandler fatalConditionHandler; // Handle signals
- m_activeTestCase->invoke();
- fatalConditionHandler.reset();
- }
-
- private:
-
- ResultBuilder makeUnexpectedResultBuilder() const {
- return ResultBuilder( m_lastAssertionInfo.macroName.c_str(),
- m_lastAssertionInfo.lineInfo,
- m_lastAssertionInfo.capturedExpression.c_str(),
- m_lastAssertionInfo.resultDisposition );
- }
-
- void handleUnfinishedSections() {
- // If sections ended prematurely due to an exception we stored their
- // infos here so we can tear them down outside the unwind process.
- for( std::vector<SectionEndInfo>::const_reverse_iterator it = m_unfinishedSections.rbegin(),
- itEnd = m_unfinishedSections.rend();
- it != itEnd;
- ++it )
- sectionEnded( *it );
- m_unfinishedSections.clear();
- }
-
- TestRunInfo m_runInfo;
- IMutableContext& m_context;
- TestCase const* m_activeTestCase;
- ITracker* m_testCaseTracker;
- ITracker* m_currentSectionTracker;
- AssertionResult m_lastResult;
-
- Ptr<IConfig const> m_config;
- Totals m_totals;
- Ptr<IStreamingReporter> m_reporter;
- std::vector<MessageInfo> m_messages;
- AssertionInfo m_lastAssertionInfo;
- std::vector<SectionEndInfo> m_unfinishedSections;
- std::vector<ITracker*> m_activeSections;
- TrackerContext m_trackerContext;
- };
-
- IResultCapture& getResultCapture() {
- if( IResultCapture* capture = getCurrentContext().getResultCapture() )
- return *capture;
- else
- throw std::logic_error( "No result capture instance" );
- }
-
-} // end namespace Catch
-
-// #included from: internal/catch_version.h
-#define TWOBLUECUBES_CATCH_VERSION_H_INCLUDED
-
-namespace Catch {
-
- // Versioning information
- struct Version {
- Version( unsigned int _majorVersion,
- unsigned int _minorVersion,
- unsigned int _patchNumber,
- std::string const& _branchName,
- unsigned int _buildNumber );
-
- unsigned int const majorVersion;
- unsigned int const minorVersion;
- unsigned int const patchNumber;
-
- // buildNumber is only used if branchName is not null
- std::string const branchName;
- unsigned int const buildNumber;
-
- friend std::ostream& operator << ( std::ostream& os, Version const& version );
-
- private:
- void operator=( Version const& );
- };
-
- extern Version libraryVersion;
-}
-
-#include <fstream>
-#include <stdlib.h>
-#include <limits>
-
-namespace Catch {
-
- Ptr<IStreamingReporter> createReporter( std::string const& reporterName, Ptr<Config> const& config ) {
- Ptr<IStreamingReporter> reporter = getRegistryHub().getReporterRegistry().create( reporterName, config.get() );
- if( !reporter ) {
- std::ostringstream oss;
- oss << "No reporter registered with name: '" << reporterName << "'";
- throw std::domain_error( oss.str() );
- }
- return reporter;
- }
-
- Ptr<IStreamingReporter> makeReporter( Ptr<Config> const& config ) {
- std::vector<std::string> reporters = config->getReporterNames();
- if( reporters.empty() )
- reporters.push_back( "console" );
-
- Ptr<IStreamingReporter> reporter;
- for( std::vector<std::string>::const_iterator it = reporters.begin(), itEnd = reporters.end();
- it != itEnd;
- ++it )
- reporter = addReporter( reporter, createReporter( *it, config ) );
- return reporter;
- }
- Ptr<IStreamingReporter> addListeners( Ptr<IConfig const> const& config, Ptr<IStreamingReporter> reporters ) {
- IReporterRegistry::Listeners listeners = getRegistryHub().getReporterRegistry().getListeners();
- for( IReporterRegistry::Listeners::const_iterator it = listeners.begin(), itEnd = listeners.end();
- it != itEnd;
- ++it )
- reporters = addReporter(reporters, (*it)->create( ReporterConfig( config ) ) );
- return reporters;
- }
-
- Totals runTests( Ptr<Config> const& config ) {
-
- Ptr<IConfig const> iconfig = config.get();
-
- Ptr<IStreamingReporter> reporter = makeReporter( config );
- reporter = addListeners( iconfig, reporter );
-
- RunContext context( iconfig, reporter );
-
- Totals totals;
-
- context.testGroupStarting( config->name(), 1, 1 );
-
- TestSpec testSpec = config->testSpec();
- if( !testSpec.hasFilters() )
- testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "~[.]" ).testSpec(); // All not hidden tests
-
- std::vector<TestCase> const& allTestCases = getAllTestCasesSorted( *iconfig );
- for( std::vector<TestCase>::const_iterator it = allTestCases.begin(), itEnd = allTestCases.end();
- it != itEnd;
- ++it ) {
- if( !context.aborting() && matchTest( *it, testSpec, *iconfig ) )
- totals += context.runTest( *it );
- else
- reporter->skipTest( *it );
- }
-
- context.testGroupEnded( iconfig->name(), totals, 1, 1 );
- return totals;
- }
-
- void applyFilenamesAsTags( IConfig const& config ) {
- std::vector<TestCase> const& tests = getAllTestCasesSorted( config );
- for(std::size_t i = 0; i < tests.size(); ++i ) {
- TestCase& test = const_cast<TestCase&>( tests[i] );
- std::set<std::string> tags = test.tags;
-
- std::string filename = test.lineInfo.file;
- std::string::size_type lastSlash = filename.find_last_of( "\\/" );
- if( lastSlash != std::string::npos )
- filename = filename.substr( lastSlash+1 );
-
- std::string::size_type lastDot = filename.find_last_of( "." );
- if( lastDot != std::string::npos )
- filename = filename.substr( 0, lastDot );
-
- tags.insert( "#" + filename );
- setTags( test, tags );
- }
- }
-
- class Session : NonCopyable {
- static bool alreadyInstantiated;
-
- public:
-
- struct OnUnusedOptions { enum DoWhat { Ignore, Fail }; };
-
- Session()
- : m_cli( makeCommandLineParser() ) {
- if( alreadyInstantiated ) {
- std::string msg = "Only one instance of Catch::Session can ever be used";
- Catch::cerr() << msg << std::endl;
- throw std::logic_error( msg );
- }
- alreadyInstantiated = true;
- }
- ~Session() {
- Catch::cleanUp();
- }
-
- void showHelp( std::string const& processName ) {
- Catch::cout() << "\nCatch v" << libraryVersion << "\n";
-
- m_cli.usage( Catch::cout(), processName );
- Catch::cout() << "For more detail usage please see the project docs\n" << std::endl;
- }
-
- int applyCommandLine( int argc, char const* const* const argv, OnUnusedOptions::DoWhat unusedOptionBehaviour = OnUnusedOptions::Fail ) {
- try {
- m_cli.setThrowOnUnrecognisedTokens( unusedOptionBehaviour == OnUnusedOptions::Fail );
- m_unusedTokens = m_cli.parseInto( Clara::argsToVector( argc, argv ), m_configData );
- if( m_configData.showHelp )
- showHelp( m_configData.processName );
- m_config.reset();
- }
- catch( std::exception& ex ) {
- {
- Colour colourGuard( Colour::Red );
- Catch::cerr()
- << "\nError(s) in input:\n"
- << Text( ex.what(), TextAttributes().setIndent(2) )
- << "\n\n";
- }
- m_cli.usage( Catch::cout(), m_configData.processName );
- return (std::numeric_limits<int>::max)();
- }
- return 0;
- }
-
- void useConfigData( ConfigData const& _configData ) {
- m_configData = _configData;
- m_config.reset();
- }
-
- int run( int argc, char const* const* const argv ) {
-
- int returnCode = applyCommandLine( argc, argv );
- if( returnCode == 0 )
- returnCode = run();
- return returnCode;
- }
-
- int run() {
- if( m_configData.showHelp )
- return 0;
-
- try
- {
- config(); // Force config to be constructed
-
- seedRng( *m_config );
-
- if( m_configData.filenamesAsTags )
- applyFilenamesAsTags( *m_config );
-
- // Handle list request
- if( Option<std::size_t> listed = list( config() ) )
- return static_cast<int>( *listed );
-
- return static_cast<int>( runTests( m_config ).assertions.failed );
- }
- catch( std::exception& ex ) {
- Catch::cerr() << ex.what() << std::endl;
- return (std::numeric_limits<int>::max)();
- }
- }
-
- Clara::CommandLine<ConfigData> const& cli() const {
- return m_cli;
- }
- std::vector<Clara::Parser::Token> const& unusedTokens() const {
- return m_unusedTokens;
- }
- ConfigData& configData() {
- return m_configData;
- }
- Config& config() {
- if( !m_config )
- m_config = new Config( m_configData );
- return *m_config;
- }
- private:
- Clara::CommandLine<ConfigData> m_cli;
- std::vector<Clara::Parser::Token> m_unusedTokens;
- ConfigData m_configData;
- Ptr<Config> m_config;
- };
-
- bool Session::alreadyInstantiated = false;
-
-} // end namespace Catch
-
-// #included from: catch_registry_hub.hpp
-#define TWOBLUECUBES_CATCH_REGISTRY_HUB_HPP_INCLUDED
-
-// #included from: catch_test_case_registry_impl.hpp
-#define TWOBLUECUBES_CATCH_TEST_CASE_REGISTRY_IMPL_HPP_INCLUDED
-
-#include <vector>
-#include <set>
-#include <sstream>
-#include <algorithm>
-
-namespace Catch {
-
- struct RandomNumberGenerator {
- typedef std::ptrdiff_t result_type;
-
- result_type operator()( result_type n ) const { return std::rand() % n; }
-
-#ifdef CATCH_CONFIG_CPP11_SHUFFLE
- static constexpr result_type min() { return 0; }
- static constexpr result_type max() { return 1000000; }
- result_type operator()() const { return std::rand() % max(); }
-#endif
- template<typename V>
- static void shuffle( V& vector ) {
- RandomNumberGenerator rng;
-#ifdef CATCH_CONFIG_CPP11_SHUFFLE
- std::shuffle( vector.begin(), vector.end(), rng );
-#else
- std::random_shuffle( vector.begin(), vector.end(), rng );
-#endif
- }
- };
-
- inline std::vector<TestCase> sortTests( IConfig const& config, std::vector<TestCase> const& unsortedTestCases ) {
-
- std::vector<TestCase> sorted = unsortedTestCases;
-
- switch( config.runOrder() ) {
- case RunTests::InLexicographicalOrder:
- std::sort( sorted.begin(), sorted.end() );
- break;
- case RunTests::InRandomOrder:
- {
- seedRng( config );
- RandomNumberGenerator::shuffle( sorted );
- }
- break;
- case RunTests::InDeclarationOrder:
- // already in declaration order
- break;
- }
- return sorted;
- }
- bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config ) {
- return testSpec.matches( testCase ) && ( config.allowThrows() || !testCase.throws() );
- }
-
- void enforceNoDuplicateTestCases( std::vector<TestCase> const& functions ) {
- std::set<TestCase> seenFunctions;
- for( std::vector<TestCase>::const_iterator it = functions.begin(), itEnd = functions.end();
- it != itEnd;
- ++it ) {
- std::pair<std::set<TestCase>::const_iterator, bool> prev = seenFunctions.insert( *it );
- if( !prev.second ) {
- std::ostringstream ss;
-
- ss << Colour( Colour::Red )
- << "error: TEST_CASE( \"" << it->name << "\" ) already defined.\n"
- << "\tFirst seen at " << prev.first->getTestCaseInfo().lineInfo << '\n'
- << "\tRedefined at " << it->getTestCaseInfo().lineInfo << std::endl;
-
- throw std::runtime_error(ss.str());
- }
- }
- }
-
- std::vector<TestCase> filterTests( std::vector<TestCase> const& testCases, TestSpec const& testSpec, IConfig const& config ) {
- std::vector<TestCase> filtered;
- filtered.reserve( testCases.size() );
- for( std::vector<TestCase>::const_iterator it = testCases.begin(), itEnd = testCases.end();
- it != itEnd;
- ++it )
- if( matchTest( *it, testSpec, config ) )
- filtered.push_back( *it );
- return filtered;
- }
- std::vector<TestCase> const& getAllTestCasesSorted( IConfig const& config ) {
- return getRegistryHub().getTestCaseRegistry().getAllTestsSorted( config );
- }
-
- class TestRegistry : public ITestCaseRegistry {
- public:
- TestRegistry()
- : m_currentSortOrder( RunTests::InDeclarationOrder ),
- m_unnamedCount( 0 )
- {}
- virtual ~TestRegistry();
-
- virtual void registerTest( TestCase const& testCase ) {
- std::string name = testCase.getTestCaseInfo().name;
- if( name.empty() ) {
- std::ostringstream oss;
- oss << "Anonymous test case " << ++m_unnamedCount;
- return registerTest( testCase.withName( oss.str() ) );
- }
- m_functions.push_back( testCase );
- }
-
- virtual std::vector<TestCase> const& getAllTests() const {
- return m_functions;
- }
- virtual std::vector<TestCase> const& getAllTestsSorted( IConfig const& config ) const {
- if( m_sortedFunctions.empty() )
- enforceNoDuplicateTestCases( m_functions );
-
- if( m_currentSortOrder != config.runOrder() || m_sortedFunctions.empty() ) {
- m_sortedFunctions = sortTests( config, m_functions );
- m_currentSortOrder = config.runOrder();
- }
- return m_sortedFunctions;
- }
-
- private:
- std::vector<TestCase> m_functions;
- mutable RunTests::InWhatOrder m_currentSortOrder;
- mutable std::vector<TestCase> m_sortedFunctions;
- size_t m_unnamedCount;
- std::ios_base::Init m_ostreamInit; // Forces cout/ cerr to be initialised
- };
-
- ///////////////////////////////////////////////////////////////////////////
-
- class FreeFunctionTestCase : public SharedImpl<ITestCase> {
- public:
-
- FreeFunctionTestCase( TestFunction fun ) : m_fun( fun ) {}
-
- virtual void invoke() const {
- m_fun();
- }
-
- private:
- virtual ~FreeFunctionTestCase();
-
- TestFunction m_fun;
- };
-
- inline std::string extractClassName( std::string const& classOrQualifiedMethodName ) {
- std::string className = classOrQualifiedMethodName;
- if( startsWith( className, '&' ) )
- {
- std::size_t lastColons = className.rfind( "::" );
- std::size_t penultimateColons = className.rfind( "::", lastColons-1 );
- if( penultimateColons == std::string::npos )
- penultimateColons = 1;
- className = className.substr( penultimateColons, lastColons-penultimateColons );
- }
- return className;
- }
-
- void registerTestCase
- ( ITestCase* testCase,
- char const* classOrQualifiedMethodName,
- NameAndDesc const& nameAndDesc,
- SourceLineInfo const& lineInfo ) {
-
- getMutableRegistryHub().registerTest
- ( makeTestCase
- ( testCase,
- extractClassName( classOrQualifiedMethodName ),
- nameAndDesc.name,
- nameAndDesc.description,
- lineInfo ) );
- }
- void registerTestCaseFunction
- ( TestFunction function,
- SourceLineInfo const& lineInfo,
- NameAndDesc const& nameAndDesc ) {
- registerTestCase( new FreeFunctionTestCase( function ), "", nameAndDesc, lineInfo );
- }
-
- ///////////////////////////////////////////////////////////////////////////
-
- AutoReg::AutoReg
- ( TestFunction function,
- SourceLineInfo const& lineInfo,
- NameAndDesc const& nameAndDesc ) {
- registerTestCaseFunction( function, lineInfo, nameAndDesc );
- }
-
- AutoReg::~AutoReg() {}
-
-} // end namespace Catch
-
-// #included from: catch_reporter_registry.hpp
-#define TWOBLUECUBES_CATCH_REPORTER_REGISTRY_HPP_INCLUDED
-
-#include <map>
-
-namespace Catch {
-
- class ReporterRegistry : public IReporterRegistry {
-
- public:
-
- virtual ~ReporterRegistry() CATCH_OVERRIDE {}
-
- virtual IStreamingReporter* create( std::string const& name, Ptr<IConfig const> const& config ) const CATCH_OVERRIDE {
- FactoryMap::const_iterator it = m_factories.find( name );
- if( it == m_factories.end() )
- return CATCH_NULL;
- return it->second->create( ReporterConfig( config ) );
- }
-
- void registerReporter( std::string const& name, Ptr<IReporterFactory> const& factory ) {
- m_factories.insert( std::make_pair( name, factory ) );
- }
- void registerListener( Ptr<IReporterFactory> const& factory ) {
- m_listeners.push_back( factory );
- }
-
- virtual FactoryMap const& getFactories() const CATCH_OVERRIDE {
- return m_factories;
- }
- virtual Listeners const& getListeners() const CATCH_OVERRIDE {
- return m_listeners;
- }
-
- private:
- FactoryMap m_factories;
- Listeners m_listeners;
- };
-}
-
-// #included from: catch_exception_translator_registry.hpp
-#define TWOBLUECUBES_CATCH_EXCEPTION_TRANSLATOR_REGISTRY_HPP_INCLUDED
-
-#ifdef __OBJC__
-#import "Foundation/Foundation.h"
-#endif
-
-namespace Catch {
-
- class ExceptionTranslatorRegistry : public IExceptionTranslatorRegistry {
- public:
- ~ExceptionTranslatorRegistry() {
- deleteAll( m_translators );
- }
-
- virtual void registerTranslator( const IExceptionTranslator* translator ) {
- m_translators.push_back( translator );
- }
-
- virtual std::string translateActiveException() const {
- try {
-#ifdef __OBJC__
- // In Objective-C try objective-c exceptions first
- @try {
- return tryTranslators();
- }
- @catch (NSException *exception) {
- return Catch::toString( [exception description] );
- }
-#else
- return tryTranslators();
-#endif
- }
- catch( TestFailureException& ) {
- throw;
- }
- catch( std::exception& ex ) {
- return ex.what();
- }
- catch( std::string& msg ) {
- return msg;
- }
- catch( const char* msg ) {
- return msg;
- }
- catch(...) {
- return "Unknown exception";
- }
- }
-
- std::string tryTranslators() const {
- if( m_translators.empty() )
- throw;
- else
- return m_translators[0]->translate( m_translators.begin()+1, m_translators.end() );
- }
-
- private:
- std::vector<const IExceptionTranslator*> m_translators;
- };
-}
-
-namespace Catch {
-
- namespace {
-
- class RegistryHub : public IRegistryHub, public IMutableRegistryHub {
-
- RegistryHub( RegistryHub const& );
- void operator=( RegistryHub const& );
-
- public: // IRegistryHub
- RegistryHub() {
- }
- virtual IReporterRegistry const& getReporterRegistry() const CATCH_OVERRIDE {
- return m_reporterRegistry;
- }
- virtual ITestCaseRegistry const& getTestCaseRegistry() const CATCH_OVERRIDE {
- return m_testCaseRegistry;
- }
- virtual IExceptionTranslatorRegistry& getExceptionTranslatorRegistry() CATCH_OVERRIDE {
- return m_exceptionTranslatorRegistry;
- }
-
- public: // IMutableRegistryHub
- virtual void registerReporter( std::string const& name, Ptr<IReporterFactory> const& factory ) CATCH_OVERRIDE {
- m_reporterRegistry.registerReporter( name, factory );
- }
- virtual void registerListener( Ptr<IReporterFactory> const& factory ) CATCH_OVERRIDE {
- m_reporterRegistry.registerListener( factory );
- }
- virtual void registerTest( TestCase const& testInfo ) CATCH_OVERRIDE {
- m_testCaseRegistry.registerTest( testInfo );
- }
- virtual void registerTranslator( const IExceptionTranslator* translator ) CATCH_OVERRIDE {
- m_exceptionTranslatorRegistry.registerTranslator( translator );
- }
-
- private:
- TestRegistry m_testCaseRegistry;
- ReporterRegistry m_reporterRegistry;
- ExceptionTranslatorRegistry m_exceptionTranslatorRegistry;
- };
-
- // Single, global, instance
- inline RegistryHub*& getTheRegistryHub() {
- static RegistryHub* theRegistryHub = CATCH_NULL;
- if( !theRegistryHub )
- theRegistryHub = new RegistryHub();
- return theRegistryHub;
- }
- }
-
- IRegistryHub& getRegistryHub() {
- return *getTheRegistryHub();
- }
- IMutableRegistryHub& getMutableRegistryHub() {
- return *getTheRegistryHub();
- }
- void cleanUp() {
- delete getTheRegistryHub();
- getTheRegistryHub() = CATCH_NULL;
- cleanUpContext();
- }
- std::string translateActiveException() {
- return getRegistryHub().getExceptionTranslatorRegistry().translateActiveException();
- }
-
-} // end namespace Catch
-
-// #included from: catch_notimplemented_exception.hpp
-#define TWOBLUECUBES_CATCH_NOTIMPLEMENTED_EXCEPTION_HPP_INCLUDED
-
-#include <sstream>
-
-namespace Catch {
-
- NotImplementedException::NotImplementedException( SourceLineInfo const& lineInfo )
- : m_lineInfo( lineInfo ) {
- std::ostringstream oss;
- oss << lineInfo << ": function ";
- oss << "not implemented";
- m_what = oss.str();
- }
-
- const char* NotImplementedException::what() const CATCH_NOEXCEPT {
- return m_what.c_str();
- }
-
-} // end namespace Catch
-
-// #included from: catch_context_impl.hpp
-#define TWOBLUECUBES_CATCH_CONTEXT_IMPL_HPP_INCLUDED
-
-// #included from: catch_stream.hpp
-#define TWOBLUECUBES_CATCH_STREAM_HPP_INCLUDED
-
-#include <stdexcept>
-#include <cstdio>
-#include <iostream>
-
-namespace Catch {
-
- template<typename WriterF, size_t bufferSize=256>
- class StreamBufImpl : public StreamBufBase {
- char data[bufferSize];
- WriterF m_writer;
-
- public:
- StreamBufImpl() {
- setp( data, data + sizeof(data) );
- }
-
- ~StreamBufImpl() CATCH_NOEXCEPT {
- sync();
- }
-
- private:
- int overflow( int c ) {
- sync();
-
- if( c != EOF ) {
- if( pbase() == epptr() )
- m_writer( std::string( 1, static_cast<char>( c ) ) );
- else
- sputc( static_cast<char>( c ) );
- }
- return 0;
- }
-
- int sync() {
- if( pbase() != pptr() ) {
- m_writer( std::string( pbase(), static_cast<std::string::size_type>( pptr() - pbase() ) ) );
- setp( pbase(), epptr() );
- }
- return 0;
- }
- };
-
- ///////////////////////////////////////////////////////////////////////////
-
- FileStream::FileStream( std::string const& filename ) {
- m_ofs.open( filename.c_str() );
- if( m_ofs.fail() ) {
- std::ostringstream oss;
- oss << "Unable to open file: '" << filename << '\'';
- throw std::domain_error( oss.str() );
- }
- }
-
- std::ostream& FileStream::stream() const {
- return m_ofs;
- }
-
- struct OutputDebugWriter {
-
- void operator()( std::string const&str ) {
- writeToDebugConsole( str );
- }
- };
-
- DebugOutStream::DebugOutStream()
- : m_streamBuf( new StreamBufImpl<OutputDebugWriter>() ),
- m_os( m_streamBuf.get() )
- {}
-
- std::ostream& DebugOutStream::stream() const {
- return m_os;
- }
-
- // Store the streambuf from cout up-front because
- // cout may get redirected when running tests
- CoutStream::CoutStream()
- : m_os( Catch::cout().rdbuf() )
- {}
-
- std::ostream& CoutStream::stream() const {
- return m_os;
- }
-
-#ifndef CATCH_CONFIG_NOSTDOUT // If you #define this you must implement these functions
- std::ostream& cout() {
- return std::cout;
- }
- std::ostream& cerr() {
- return std::cerr;
- }
-#endif
-}
-
-namespace Catch {
-
- class Context : public IMutableContext {
-
- Context() : m_config( CATCH_NULL ), m_runner( CATCH_NULL ), m_resultCapture( CATCH_NULL ) {}
- Context( Context const& );
- void operator=( Context const& );
-
- public:
- virtual ~Context() {
- deleteAllValues( m_generatorsByTestName );
- }
-
- public: // IContext
- virtual IResultCapture* getResultCapture() {
- return m_resultCapture;
- }
- virtual IRunner* getRunner() {
- return m_runner;
- }
- virtual size_t getGeneratorIndex( std::string const& fileInfo, size_t totalSize ) {
- return getGeneratorsForCurrentTest()
- .getGeneratorInfo( fileInfo, totalSize )
- .getCurrentIndex();
- }
- virtual bool advanceGeneratorsForCurrentTest() {
- IGeneratorsForTest* generators = findGeneratorsForCurrentTest();
- return generators && generators->moveNext();
- }
-
- virtual Ptr<IConfig const> getConfig() const {
- return m_config;
- }
-
- public: // IMutableContext
- virtual void setResultCapture( IResultCapture* resultCapture ) {
- m_resultCapture = resultCapture;
- }
- virtual void setRunner( IRunner* runner ) {
- m_runner = runner;
- }
- virtual void setConfig( Ptr<IConfig const> const& config ) {
- m_config = config;
- }
-
- friend IMutableContext& getCurrentMutableContext();
-
- private:
- IGeneratorsForTest* findGeneratorsForCurrentTest() {
- std::string testName = getResultCapture()->getCurrentTestName();
-
- std::map<std::string, IGeneratorsForTest*>::const_iterator it =
- m_generatorsByTestName.find( testName );
- return it != m_generatorsByTestName.end()
- ? it->second
- : CATCH_NULL;
- }
-
- IGeneratorsForTest& getGeneratorsForCurrentTest() {
- IGeneratorsForTest* generators = findGeneratorsForCurrentTest();
- if( !generators ) {
- std::string testName = getResultCapture()->getCurrentTestName();
- generators = createGeneratorsForTest();
- m_generatorsByTestName.insert( std::make_pair( testName, generators ) );
- }
- return *generators;
- }
-
- private:
- Ptr<IConfig const> m_config;
- IRunner* m_runner;
- IResultCapture* m_resultCapture;
- std::map<std::string, IGeneratorsForTest*> m_generatorsByTestName;
- };
-
- namespace {
- Context* currentContext = CATCH_NULL;
- }
- IMutableContext& getCurrentMutableContext() {
- if( !currentContext )
- currentContext = new Context();
- return *currentContext;
- }
- IContext& getCurrentContext() {
- return getCurrentMutableContext();
- }
-
- void cleanUpContext() {
- delete currentContext;
- currentContext = CATCH_NULL;
- }
-}
-
-// #included from: catch_console_colour_impl.hpp
-#define TWOBLUECUBES_CATCH_CONSOLE_COLOUR_IMPL_HPP_INCLUDED
-
-namespace Catch {
- namespace {
-
- struct IColourImpl {
- virtual ~IColourImpl() {}
- virtual void use( Colour::Code _colourCode ) = 0;
- };
-
- struct NoColourImpl : IColourImpl {
- void use( Colour::Code ) {}
-
- static IColourImpl* instance() {
- static NoColourImpl s_instance;
- return &s_instance;
- }
- };
-
- } // anon namespace
-} // namespace Catch
-
-#if !defined( CATCH_CONFIG_COLOUR_NONE ) && !defined( CATCH_CONFIG_COLOUR_WINDOWS ) && !defined( CATCH_CONFIG_COLOUR_ANSI )
-# ifdef CATCH_PLATFORM_WINDOWS
-# define CATCH_CONFIG_COLOUR_WINDOWS
-# else
-# define CATCH_CONFIG_COLOUR_ANSI
-# endif
-#endif
-
-#if defined ( CATCH_CONFIG_COLOUR_WINDOWS ) /////////////////////////////////////////
-
-namespace Catch {
-namespace {
-
- class Win32ColourImpl : public IColourImpl {
- public:
- Win32ColourImpl() : stdoutHandle( GetStdHandle(STD_OUTPUT_HANDLE) )
- {
- CONSOLE_SCREEN_BUFFER_INFO csbiInfo;
- GetConsoleScreenBufferInfo( stdoutHandle, &csbiInfo );
- originalForegroundAttributes = csbiInfo.wAttributes & ~( BACKGROUND_GREEN | BACKGROUND_RED | BACKGROUND_BLUE | BACKGROUND_INTENSITY );
- originalBackgroundAttributes = csbiInfo.wAttributes & ~( FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_INTENSITY );
- }
-
- virtual void use( Colour::Code _colourCode ) {
- switch( _colourCode ) {
- case Colour::None: return setTextAttribute( originalForegroundAttributes );
- case Colour::White: return setTextAttribute( FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE );
- case Colour::Red: return setTextAttribute( FOREGROUND_RED );
- case Colour::Green: return setTextAttribute( FOREGROUND_GREEN );
- case Colour::Blue: return setTextAttribute( FOREGROUND_BLUE );
- case Colour::Cyan: return setTextAttribute( FOREGROUND_BLUE | FOREGROUND_GREEN );
- case Colour::Yellow: return setTextAttribute( FOREGROUND_RED | FOREGROUND_GREEN );
- case Colour::Grey: return setTextAttribute( 0 );
-
- case Colour::LightGrey: return setTextAttribute( FOREGROUND_INTENSITY );
- case Colour::BrightRed: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_RED );
- case Colour::BrightGreen: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN );
- case Colour::BrightWhite: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE );
-
- case Colour::Bright: throw std::logic_error( "not a colour" );
- }
- }
-
- private:
- void setTextAttribute( WORD _textAttribute ) {
- SetConsoleTextAttribute( stdoutHandle, _textAttribute | originalBackgroundAttributes );
- }
- HANDLE stdoutHandle;
- WORD originalForegroundAttributes;
- WORD originalBackgroundAttributes;
- };
-
- IColourImpl* platformColourInstance() {
- static Win32ColourImpl s_instance;
-
- Ptr<IConfig const> config = getCurrentContext().getConfig();
- UseColour::YesOrNo colourMode = config
- ? config->useColour()
- : UseColour::Auto;
- if( colourMode == UseColour::Auto )
- colourMode = !isDebuggerActive()
- ? UseColour::Yes
- : UseColour::No;
- return colourMode == UseColour::Yes
- ? &s_instance
- : NoColourImpl::instance();
- }
-
-} // end anon namespace
-} // end namespace Catch
-
-#elif defined( CATCH_CONFIG_COLOUR_ANSI ) //////////////////////////////////////
-
-#include <unistd.h>
-
-namespace Catch {
-namespace {
-
- // use POSIX/ ANSI console terminal codes
- // Thanks to Adam Strzelecki for original contribution
- // (http://github.com/nanoant)
- // https://github.com/philsquared/Catch/pull/131
- class PosixColourImpl : public IColourImpl {
- public:
- virtual void use( Colour::Code _colourCode ) {
- switch( _colourCode ) {
- case Colour::None:
- case Colour::White: return setColour( "[0m" );
- case Colour::Red: return setColour( "[0;31m" );
- case Colour::Green: return setColour( "[0;32m" );
- case Colour::Blue: return setColour( "[0;34m" );
- case Colour::Cyan: return setColour( "[0;36m" );
- case Colour::Yellow: return setColour( "[0;33m" );
- case Colour::Grey: return setColour( "[1;30m" );
-
- case Colour::LightGrey: return setColour( "[0;37m" );
- case Colour::BrightRed: return setColour( "[1;31m" );
- case Colour::BrightGreen: return setColour( "[1;32m" );
- case Colour::BrightWhite: return setColour( "[1;37m" );
-
- case Colour::Bright: throw std::logic_error( "not a colour" );
- }
- }
- static IColourImpl* instance() {
- static PosixColourImpl s_instance;
- return &s_instance;
- }
-
- private:
- void setColour( const char* _escapeCode ) {
- Catch::cout() << '\033' << _escapeCode;
- }
- };
-
- IColourImpl* platformColourInstance() {
- Ptr<IConfig const> config = getCurrentContext().getConfig();
- UseColour::YesOrNo colourMode = config
- ? config->useColour()
- : UseColour::Auto;
- if( colourMode == UseColour::Auto )
- colourMode = (!isDebuggerActive() && isatty(STDOUT_FILENO) )
- ? UseColour::Yes
- : UseColour::No;
- return colourMode == UseColour::Yes
- ? PosixColourImpl::instance()
- : NoColourImpl::instance();
- }
-
-} // end anon namespace
-} // end namespace Catch
-
-#else // not Windows or ANSI ///////////////////////////////////////////////
-
-namespace Catch {
-
- static IColourImpl* platformColourInstance() { return NoColourImpl::instance(); }
-
-} // end namespace Catch
-
-#endif // Windows/ ANSI/ None
-
-namespace Catch {
-
- Colour::Colour( Code _colourCode ) : m_moved( false ) { use( _colourCode ); }
- Colour::Colour( Colour const& _other ) : m_moved( false ) { const_cast<Colour&>( _other ).m_moved = true; }
- Colour::~Colour(){ if( !m_moved ) use( None ); }
-
- void Colour::use( Code _colourCode ) {
- static IColourImpl* impl = platformColourInstance();
- impl->use( _colourCode );
- }
-
-} // end namespace Catch
-
-// #included from: catch_generators_impl.hpp
-#define TWOBLUECUBES_CATCH_GENERATORS_IMPL_HPP_INCLUDED
-
-#include <vector>
-#include <string>
-#include <map>
-
-namespace Catch {
-
- struct GeneratorInfo : IGeneratorInfo {
-
- GeneratorInfo( std::size_t size )
- : m_size( size ),
- m_currentIndex( 0 )
- {}
-
- bool moveNext() {
- if( ++m_currentIndex == m_size ) {
- m_currentIndex = 0;
- return false;
- }
- return true;
- }
-
- std::size_t getCurrentIndex() const {
- return m_currentIndex;
- }
-
- std::size_t m_size;
- std::size_t m_currentIndex;
- };
-
- ///////////////////////////////////////////////////////////////////////////
-
- class GeneratorsForTest : public IGeneratorsForTest {
-
- public:
- ~GeneratorsForTest() {
- deleteAll( m_generatorsInOrder );
- }
-
- IGeneratorInfo& getGeneratorInfo( std::string const& fileInfo, std::size_t size ) {
- std::map<std::string, IGeneratorInfo*>::const_iterator it = m_generatorsByName.find( fileInfo );
- if( it == m_generatorsByName.end() ) {
- IGeneratorInfo* info = new GeneratorInfo( size );
- m_generatorsByName.insert( std::make_pair( fileInfo, info ) );
- m_generatorsInOrder.push_back( info );
- return *info;
- }
- return *it->second;
- }
-
- bool moveNext() {
- std::vector<IGeneratorInfo*>::const_iterator it = m_generatorsInOrder.begin();
- std::vector<IGeneratorInfo*>::const_iterator itEnd = m_generatorsInOrder.end();
- for(; it != itEnd; ++it ) {
- if( (*it)->moveNext() )
- return true;
- }
- return false;
- }
-
- private:
- std::map<std::string, IGeneratorInfo*> m_generatorsByName;
- std::vector<IGeneratorInfo*> m_generatorsInOrder;
- };
-
- IGeneratorsForTest* createGeneratorsForTest()
- {
- return new GeneratorsForTest();
- }
-
-} // end namespace Catch
-
-// #included from: catch_assertionresult.hpp
-#define TWOBLUECUBES_CATCH_ASSERTIONRESULT_HPP_INCLUDED
-
-namespace Catch {
-
- AssertionInfo::AssertionInfo( std::string const& _macroName,
- SourceLineInfo const& _lineInfo,
- std::string const& _capturedExpression,
- ResultDisposition::Flags _resultDisposition )
- : macroName( _macroName ),
- lineInfo( _lineInfo ),
- capturedExpression( _capturedExpression ),
- resultDisposition( _resultDisposition )
- {}
-
- AssertionResult::AssertionResult() {}
-
- AssertionResult::AssertionResult( AssertionInfo const& info, AssertionResultData const& data )
- : m_info( info ),
- m_resultData( data )
- {}
-
- AssertionResult::~AssertionResult() {}
-
- // Result was a success
- bool AssertionResult::succeeded() const {
- return Catch::isOk( m_resultData.resultType );
- }
-
- // Result was a success, or failure is suppressed
- bool AssertionResult::isOk() const {
- return Catch::isOk( m_resultData.resultType ) || shouldSuppressFailure( m_info.resultDisposition );
- }
-
- ResultWas::OfType AssertionResult::getResultType() const {
- return m_resultData.resultType;
- }
-
- bool AssertionResult::hasExpression() const {
- return !m_info.capturedExpression.empty();
- }
-
- bool AssertionResult::hasMessage() const {
- return !m_resultData.message.empty();
- }
-
- std::string AssertionResult::getExpression() const {
- if( isFalseTest( m_info.resultDisposition ) )
- return '!' + m_info.capturedExpression;
- else
- return m_info.capturedExpression;
- }
- std::string AssertionResult::getExpressionInMacro() const {
- if( m_info.macroName.empty() )
- return m_info.capturedExpression;
- else
- return m_info.macroName + "( " + m_info.capturedExpression + " )";
- }
-
- bool AssertionResult::hasExpandedExpression() const {
- return hasExpression() && getExpandedExpression() != getExpression();
- }
-
- std::string AssertionResult::getExpandedExpression() const {
- return m_resultData.reconstructExpression();
- }
-
- std::string AssertionResult::getMessage() const {
- return m_resultData.message;
- }
- SourceLineInfo AssertionResult::getSourceInfo() const {
- return m_info.lineInfo;
- }
-
- std::string AssertionResult::getTestMacroName() const {
- return m_info.macroName;
- }
-
- void AssertionResult::discardDecomposedExpression() const {
- m_resultData.decomposedExpression = CATCH_NULL;
- }
-
- void AssertionResult::expandDecomposedExpression() const {
- m_resultData.reconstructExpression();
- }
-
-} // end namespace Catch
-
-// #included from: catch_test_case_info.hpp
-#define TWOBLUECUBES_CATCH_TEST_CASE_INFO_HPP_INCLUDED
-
-#include <cctype>
-
-namespace Catch {
-
- inline TestCaseInfo::SpecialProperties parseSpecialTag( std::string const& tag ) {
- if( startsWith( tag, '.' ) ||
- tag == "hide" ||
- tag == "!hide" )
- return TestCaseInfo::IsHidden;
- else if( tag == "!throws" )
- return TestCaseInfo::Throws;
- else if( tag == "!shouldfail" )
- return TestCaseInfo::ShouldFail;
- else if( tag == "!mayfail" )
- return TestCaseInfo::MayFail;
- else if( tag == "!nonportable" )
- return TestCaseInfo::NonPortable;
- else
- return TestCaseInfo::None;
- }
- inline bool isReservedTag( std::string const& tag ) {
- return parseSpecialTag( tag ) == TestCaseInfo::None && tag.size() > 0 && !std::isalnum( tag[0] );
- }
- inline void enforceNotReservedTag( std::string const& tag, SourceLineInfo const& _lineInfo ) {
- if( isReservedTag( tag ) ) {
- {
- Colour colourGuard( Colour::Red );
- Catch::cerr()
- << "Tag name [" << tag << "] not allowed.\n"
- << "Tag names starting with non alpha-numeric characters are reserved\n";
- }
- {
- Colour colourGuard( Colour::FileName );
- Catch::cerr() << _lineInfo << std::endl;
- }
- exit(1);
- }
- }
-
- TestCase makeTestCase( ITestCase* _testCase,
- std::string const& _className,
- std::string const& _name,
- std::string const& _descOrTags,
- SourceLineInfo const& _lineInfo )
- {
- bool isHidden( startsWith( _name, "./" ) ); // Legacy support
-
- // Parse out tags
- std::set<std::string> tags;
- std::string desc, tag;
- bool inTag = false;
- for( std::size_t i = 0; i < _descOrTags.size(); ++i ) {
- char c = _descOrTags[i];
- if( !inTag ) {
- if( c == '[' )
- inTag = true;
- else
- desc += c;
- }
- else {
- if( c == ']' ) {
- TestCaseInfo::SpecialProperties prop = parseSpecialTag( tag );
- if( prop == TestCaseInfo::IsHidden )
- isHidden = true;
- else if( prop == TestCaseInfo::None )
- enforceNotReservedTag( tag, _lineInfo );
-
- tags.insert( tag );
- tag.clear();
- inTag = false;
- }
- else
- tag += c;
- }
- }
- if( isHidden ) {
- tags.insert( "hide" );
- tags.insert( "." );
- }
-
- TestCaseInfo info( _name, _className, desc, tags, _lineInfo );
- return TestCase( _testCase, info );
- }
-
- void setTags( TestCaseInfo& testCaseInfo, std::set<std::string> const& tags )
- {
- testCaseInfo.tags = tags;
- testCaseInfo.lcaseTags.clear();
-
- std::ostringstream oss;
- for( std::set<std::string>::const_iterator it = tags.begin(), itEnd = tags.end(); it != itEnd; ++it ) {
- oss << '[' << *it << ']';
- std::string lcaseTag = toLower( *it );
- testCaseInfo.properties = static_cast<TestCaseInfo::SpecialProperties>( testCaseInfo.properties | parseSpecialTag( lcaseTag ) );
- testCaseInfo.lcaseTags.insert( lcaseTag );
- }
- testCaseInfo.tagsAsString = oss.str();
- }
-
- TestCaseInfo::TestCaseInfo( std::string const& _name,
- std::string const& _className,
- std::string const& _description,
- std::set<std::string> const& _tags,
- SourceLineInfo const& _lineInfo )
- : name( _name ),
- className( _className ),
- description( _description ),
- lineInfo( _lineInfo ),
- properties( None )
- {
- setTags( *this, _tags );
- }
-
- TestCaseInfo::TestCaseInfo( TestCaseInfo const& other )
- : name( other.name ),
- className( other.className ),
- description( other.description ),
- tags( other.tags ),
- lcaseTags( other.lcaseTags ),
- tagsAsString( other.tagsAsString ),
- lineInfo( other.lineInfo ),
- properties( other.properties )
- {}
-
- bool TestCaseInfo::isHidden() const {
- return ( properties & IsHidden ) != 0;
- }
- bool TestCaseInfo::throws() const {
- return ( properties & Throws ) != 0;
- }
- bool TestCaseInfo::okToFail() const {
- return ( properties & (ShouldFail | MayFail ) ) != 0;
- }
- bool TestCaseInfo::expectedToFail() const {
- return ( properties & (ShouldFail ) ) != 0;
- }
-
- TestCase::TestCase( ITestCase* testCase, TestCaseInfo const& info ) : TestCaseInfo( info ), test( testCase ) {}
-
- TestCase::TestCase( TestCase const& other )
- : TestCaseInfo( other ),
- test( other.test )
- {}
-
- TestCase TestCase::withName( std::string const& _newName ) const {
- TestCase other( *this );
- other.name = _newName;
- return other;
- }
-
- void TestCase::swap( TestCase& other ) {
- test.swap( other.test );
- name.swap( other.name );
- className.swap( other.className );
- description.swap( other.description );
- tags.swap( other.tags );
- lcaseTags.swap( other.lcaseTags );
- tagsAsString.swap( other.tagsAsString );
- std::swap( TestCaseInfo::properties, static_cast<TestCaseInfo&>( other ).properties );
- std::swap( lineInfo, other.lineInfo );
- }
-
- void TestCase::invoke() const {
- test->invoke();
- }
-
- bool TestCase::operator == ( TestCase const& other ) const {
- return test.get() == other.test.get() &&
- name == other.name &&
- className == other.className;
- }
-
- bool TestCase::operator < ( TestCase const& other ) const {
- return name < other.name;
- }
- TestCase& TestCase::operator = ( TestCase const& other ) {
- TestCase temp( other );
- swap( temp );
- return *this;
- }
-
- TestCaseInfo const& TestCase::getTestCaseInfo() const
- {
- return *this;
- }
-
-} // end namespace Catch
-
-// #included from: catch_version.hpp
-#define TWOBLUECUBES_CATCH_VERSION_HPP_INCLUDED
-
-namespace Catch {
-
- Version::Version
- ( unsigned int _majorVersion,
- unsigned int _minorVersion,
- unsigned int _patchNumber,
- std::string const& _branchName,
- unsigned int _buildNumber )
- : majorVersion( _majorVersion ),
- minorVersion( _minorVersion ),
- patchNumber( _patchNumber ),
- branchName( _branchName ),
- buildNumber( _buildNumber )
- {}
-
- std::ostream& operator << ( std::ostream& os, Version const& version ) {
- os << version.majorVersion << '.'
- << version.minorVersion << '.'
- << version.patchNumber;
-
- if( !version.branchName.empty() ) {
- os << '-' << version.branchName
- << '.' << version.buildNumber;
- }
- return os;
- }
-
- Version libraryVersion( 1, 7, 2, "", 0 );
-
-}
-
-// #included from: catch_message.hpp
-#define TWOBLUECUBES_CATCH_MESSAGE_HPP_INCLUDED
-
-namespace Catch {
-
- MessageInfo::MessageInfo( std::string const& _macroName,
- SourceLineInfo const& _lineInfo,
- ResultWas::OfType _type )
- : macroName( _macroName ),
- lineInfo( _lineInfo ),
- type( _type ),
- sequence( ++globalCount )
- {}
-
- // This may need protecting if threading support is added
- unsigned int MessageInfo::globalCount = 0;
-
- ////////////////////////////////////////////////////////////////////////////
-
- ScopedMessage::ScopedMessage( MessageBuilder const& builder )
- : m_info( builder.m_info )
- {
- m_info.message = builder.m_stream.str();
- getResultCapture().pushScopedMessage( m_info );
- }
- ScopedMessage::ScopedMessage( ScopedMessage const& other )
- : m_info( other.m_info )
- {}
-
- ScopedMessage::~ScopedMessage() {
- getResultCapture().popScopedMessage( m_info );
- }
-
-} // end namespace Catch
-
-// #included from: catch_legacy_reporter_adapter.hpp
-#define TWOBLUECUBES_CATCH_LEGACY_REPORTER_ADAPTER_HPP_INCLUDED
-
-// #included from: catch_legacy_reporter_adapter.h
-#define TWOBLUECUBES_CATCH_LEGACY_REPORTER_ADAPTER_H_INCLUDED
-
-namespace Catch
-{
- // Deprecated
- struct IReporter : IShared {
- virtual ~IReporter();
-
- virtual bool shouldRedirectStdout() const = 0;
-
- virtual void StartTesting() = 0;
- virtual void EndTesting( Totals const& totals ) = 0;
- virtual void StartGroup( std::string const& groupName ) = 0;
- virtual void EndGroup( std::string const& groupName, Totals const& totals ) = 0;
- virtual void StartTestCase( TestCaseInfo const& testInfo ) = 0;
- virtual void EndTestCase( TestCaseInfo const& testInfo, Totals const& totals, std::string const& stdOut, std::string const& stdErr ) = 0;
- virtual void StartSection( std::string const& sectionName, std::string const& description ) = 0;
- virtual void EndSection( std::string const& sectionName, Counts const& assertions ) = 0;
- virtual void NoAssertionsInSection( std::string const& sectionName ) = 0;
- virtual void NoAssertionsInTestCase( std::string const& testName ) = 0;
- virtual void Aborted() = 0;
- virtual void Result( AssertionResult const& result ) = 0;
- };
-
- class LegacyReporterAdapter : public SharedImpl<IStreamingReporter>
- {
- public:
- LegacyReporterAdapter( Ptr<IReporter> const& legacyReporter );
- virtual ~LegacyReporterAdapter();
-
- virtual ReporterPreferences getPreferences() const;
- virtual void noMatchingTestCases( std::string const& );
- virtual void testRunStarting( TestRunInfo const& );
- virtual void testGroupStarting( GroupInfo const& groupInfo );
- virtual void testCaseStarting( TestCaseInfo const& testInfo );
- virtual void sectionStarting( SectionInfo const& sectionInfo );
- virtual void assertionStarting( AssertionInfo const& );
- virtual bool assertionEnded( AssertionStats const& assertionStats );
- virtual void sectionEnded( SectionStats const& sectionStats );
- virtual void testCaseEnded( TestCaseStats const& testCaseStats );
- virtual void testGroupEnded( TestGroupStats const& testGroupStats );
- virtual void testRunEnded( TestRunStats const& testRunStats );
- virtual void skipTest( TestCaseInfo const& );
-
- private:
- Ptr<IReporter> m_legacyReporter;
- };
-}
-
-namespace Catch
-{
- LegacyReporterAdapter::LegacyReporterAdapter( Ptr<IReporter> const& legacyReporter )
- : m_legacyReporter( legacyReporter )
- {}
- LegacyReporterAdapter::~LegacyReporterAdapter() {}
-
- ReporterPreferences LegacyReporterAdapter::getPreferences() const {
- ReporterPreferences prefs;
- prefs.shouldRedirectStdOut = m_legacyReporter->shouldRedirectStdout();
- return prefs;
- }
-
- void LegacyReporterAdapter::noMatchingTestCases( std::string const& ) {}
- void LegacyReporterAdapter::testRunStarting( TestRunInfo const& ) {
- m_legacyReporter->StartTesting();
- }
- void LegacyReporterAdapter::testGroupStarting( GroupInfo const& groupInfo ) {
- m_legacyReporter->StartGroup( groupInfo.name );
- }
- void LegacyReporterAdapter::testCaseStarting( TestCaseInfo const& testInfo ) {
- m_legacyReporter->StartTestCase( testInfo );
- }
- void LegacyReporterAdapter::sectionStarting( SectionInfo const& sectionInfo ) {
- m_legacyReporter->StartSection( sectionInfo.name, sectionInfo.description );
- }
- void LegacyReporterAdapter::assertionStarting( AssertionInfo const& ) {
- // Not on legacy interface
- }
-
- bool LegacyReporterAdapter::assertionEnded( AssertionStats const& assertionStats ) {
- if( assertionStats.assertionResult.getResultType() != ResultWas::Ok ) {
- for( std::vector<MessageInfo>::const_iterator it = assertionStats.infoMessages.begin(), itEnd = assertionStats.infoMessages.end();
- it != itEnd;
- ++it ) {
- if( it->type == ResultWas::Info ) {
- ResultBuilder rb( it->macroName.c_str(), it->lineInfo, "", ResultDisposition::Normal );
- rb << it->message;
- rb.setResultType( ResultWas::Info );
- AssertionResult result = rb.build();
- m_legacyReporter->Result( result );
- }
- }
- }
- m_legacyReporter->Result( assertionStats.assertionResult );
- return true;
- }
- void LegacyReporterAdapter::sectionEnded( SectionStats const& sectionStats ) {
- if( sectionStats.missingAssertions )
- m_legacyReporter->NoAssertionsInSection( sectionStats.sectionInfo.name );
- m_legacyReporter->EndSection( sectionStats.sectionInfo.name, sectionStats.assertions );
- }
- void LegacyReporterAdapter::testCaseEnded( TestCaseStats const& testCaseStats ) {
- m_legacyReporter->EndTestCase
- ( testCaseStats.testInfo,
- testCaseStats.totals,
- testCaseStats.stdOut,
- testCaseStats.stdErr );
- }
- void LegacyReporterAdapter::testGroupEnded( TestGroupStats const& testGroupStats ) {
- if( testGroupStats.aborting )
- m_legacyReporter->Aborted();
- m_legacyReporter->EndGroup( testGroupStats.groupInfo.name, testGroupStats.totals );
- }
- void LegacyReporterAdapter::testRunEnded( TestRunStats const& testRunStats ) {
- m_legacyReporter->EndTesting( testRunStats.totals );
- }
- void LegacyReporterAdapter::skipTest( TestCaseInfo const& ) {
- }
-}
-
-// #included from: catch_timer.hpp
-
-#ifdef __clang__
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wc++11-long-long"
-#endif
-
-#ifdef CATCH_PLATFORM_WINDOWS
-#else
-#include <sys/time.h>
-#endif
-
-namespace Catch {
-
- namespace {
-#ifdef CATCH_PLATFORM_WINDOWS
- uint64_t getCurrentTicks() {
- static uint64_t hz=0, hzo=0;
- if (!hz) {
- QueryPerformanceFrequency( reinterpret_cast<LARGE_INTEGER*>( &hz ) );
- QueryPerformanceCounter( reinterpret_cast<LARGE_INTEGER*>( &hzo ) );
- }
- uint64_t t;
- QueryPerformanceCounter( reinterpret_cast<LARGE_INTEGER*>( &t ) );
- return ((t-hzo)*1000000)/hz;
- }
-#else
- uint64_t getCurrentTicks() {
- timeval t;
- gettimeofday(&t,CATCH_NULL);
- return static_cast<uint64_t>( t.tv_sec ) * 1000000ull + static_cast<uint64_t>( t.tv_usec );
- }
-#endif
- }
-
- void Timer::start() {
- m_ticks = getCurrentTicks();
- }
- unsigned int Timer::getElapsedMicroseconds() const {
- return static_cast<unsigned int>(getCurrentTicks() - m_ticks);
- }
- unsigned int Timer::getElapsedMilliseconds() const {
- return static_cast<unsigned int>(getElapsedMicroseconds()/1000);
- }
- double Timer::getElapsedSeconds() const {
- return getElapsedMicroseconds()/1000000.0;
- }
-
-} // namespace Catch
-
-#ifdef __clang__
-#pragma clang diagnostic pop
-#endif
-// #included from: catch_common.hpp
-#define TWOBLUECUBES_CATCH_COMMON_HPP_INCLUDED
-
-#include <cstring>
-#include <cctype>
-
-namespace Catch {
-
- bool startsWith( std::string const& s, std::string const& prefix ) {
- return s.size() >= prefix.size() && std::equal(prefix.begin(), prefix.end(), s.begin());
- }
- bool startsWith( std::string const& s, char prefix ) {
- return !s.empty() && s[0] == prefix;
- }
- bool endsWith( std::string const& s, std::string const& suffix ) {
- return s.size() >= suffix.size() && std::equal(suffix.rbegin(), suffix.rend(), s.rbegin());
- }
- bool endsWith( std::string const& s, char suffix ) {
- return !s.empty() && s[s.size()-1] == suffix;
- }
- bool contains( std::string const& s, std::string const& infix ) {
- return s.find( infix ) != std::string::npos;
- }
- char toLowerCh(char c) {
- return static_cast<char>( std::tolower( c ) );
- }
- void toLowerInPlace( std::string& s ) {
- std::transform( s.begin(), s.end(), s.begin(), toLowerCh );
- }
- std::string toLower( std::string const& s ) {
- std::string lc = s;
- toLowerInPlace( lc );
- return lc;
- }
- std::string trim( std::string const& str ) {
- static char const* whitespaceChars = "\n\r\t ";
- std::string::size_type start = str.find_first_not_of( whitespaceChars );
- std::string::size_type end = str.find_last_not_of( whitespaceChars );
-
- return start != std::string::npos ? str.substr( start, 1+end-start ) : std::string();
- }
-
- bool replaceInPlace( std::string& str, std::string const& replaceThis, std::string const& withThis ) {
- bool replaced = false;
- std::size_t i = str.find( replaceThis );
- while( i != std::string::npos ) {
- replaced = true;
- str = str.substr( 0, i ) + withThis + str.substr( i+replaceThis.size() );
- if( i < str.size()-withThis.size() )
- i = str.find( replaceThis, i+withThis.size() );
- else
- i = std::string::npos;
- }
- return replaced;
- }
-
- pluralise::pluralise( std::size_t count, std::string const& label )
- : m_count( count ),
- m_label( label )
- {}
-
- std::ostream& operator << ( std::ostream& os, pluralise const& pluraliser ) {
- os << pluraliser.m_count << ' ' << pluraliser.m_label;
- if( pluraliser.m_count != 1 )
- os << 's';
- return os;
- }
-
- SourceLineInfo::SourceLineInfo() : file(""), line( 0 ){}
- SourceLineInfo::SourceLineInfo( char const* _file, std::size_t _line )
- : file( _file ),
- line( _line )
- {}
- bool SourceLineInfo::empty() const {
- return file[0] == '\0';
- }
- bool SourceLineInfo::operator == ( SourceLineInfo const& other ) const {
- return line == other.line && (file == other.file || std::strcmp(file, other.file) == 0);
- }
- bool SourceLineInfo::operator < ( SourceLineInfo const& other ) const {
- return line < other.line || ( line == other.line && (std::strcmp(file, other.file) < 0));
- }
-
- void seedRng( IConfig const& config ) {
- if( config.rngSeed() != 0 )
- std::srand( config.rngSeed() );
- }
- unsigned int rngSeed() {
- return getCurrentContext().getConfig()->rngSeed();
- }
-
- std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ) {
-#ifndef __GNUG__
- os << info.file << '(' << info.line << ')';
-#else
- os << info.file << ':' << info.line;
-#endif
- return os;
- }
-
- void throwLogicError( std::string const& message, SourceLineInfo const& locationInfo ) {
- std::ostringstream oss;
- oss << locationInfo << ": Internal Catch error: '" << message << '\'';
- if( alwaysTrue() )
- throw std::logic_error( oss.str() );
- }
-}
-
-// #included from: catch_section.hpp
-#define TWOBLUECUBES_CATCH_SECTION_HPP_INCLUDED
-
-namespace Catch {
-
- SectionInfo::SectionInfo
- ( SourceLineInfo const& _lineInfo,
- std::string const& _name,
- std::string const& _description )
- : name( _name ),
- description( _description ),
- lineInfo( _lineInfo )
- {}
-
- Section::Section( SectionInfo const& info )
- : m_info( info ),
- m_sectionIncluded( getResultCapture().sectionStarted( m_info, m_assertions ) )
- {
- m_timer.start();
- }
-
- Section::~Section() {
- if( m_sectionIncluded ) {
- SectionEndInfo endInfo( m_info, m_assertions, m_timer.getElapsedSeconds() );
- if( std::uncaught_exception() )
- getResultCapture().sectionEndedEarly( endInfo );
- else
- getResultCapture().sectionEnded( endInfo );
- }
- }
-
- // This indicates whether the section should be executed or not
- Section::operator bool() const {
- return m_sectionIncluded;
- }
-
-} // end namespace Catch
-
-// #included from: catch_debugger.hpp
-#define TWOBLUECUBES_CATCH_DEBUGGER_HPP_INCLUDED
-
-#ifdef CATCH_PLATFORM_MAC
-
- #include <assert.h>
- #include <stdbool.h>
- #include <sys/types.h>
- #include <unistd.h>
- #include <sys/sysctl.h>
-
- namespace Catch{
-
- // The following function is taken directly from the following technical note:
- // http://developer.apple.com/library/mac/#qa/qa2004/qa1361.html
-
- // Returns true if the current process is being debugged (either
- // running under the debugger or has a debugger attached post facto).
- bool isDebuggerActive(){
-
- int mib[4];
- struct kinfo_proc info;
- size_t size;
-
- // Initialize the flags so that, if sysctl fails for some bizarre
- // reason, we get a predictable result.
-
- info.kp_proc.p_flag = 0;
-
- // Initialize mib, which tells sysctl the info we want, in this case
- // we're looking for information about a specific process ID.
-
- mib[0] = CTL_KERN;
- mib[1] = KERN_PROC;
- mib[2] = KERN_PROC_PID;
- mib[3] = getpid();
-
- // Call sysctl.
-
- size = sizeof(info);
- if( sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, CATCH_NULL, 0) != 0 ) {
- Catch::cerr() << "\n** Call to sysctl failed - unable to determine if debugger is active **\n" << std::endl;
- return false;
- }
-
- // We're being debugged if the P_TRACED flag is set.
-
- return ( (info.kp_proc.p_flag & P_TRACED) != 0 );
- }
- } // namespace Catch
-
-#elif defined(CATCH_PLATFORM_LINUX)
- #include <fstream>
- #include <string>
-
- namespace Catch{
- // The standard POSIX way of detecting a debugger is to attempt to
- // ptrace() the process, but this needs to be done from a child and not
- // this process itself to still allow attaching to this process later
- // if wanted, so is rather heavy. Under Linux we have the PID of the
- // "debugger" (which doesn't need to be gdb, of course, it could also
- // be strace, for example) in /proc/$PID/status, so just get it from
- // there instead.
- bool isDebuggerActive(){
- std::ifstream in("/proc/self/status");
- for( std::string line; std::getline(in, line); ) {
- static const int PREFIX_LEN = 11;
- if( line.compare(0, PREFIX_LEN, "TracerPid:\t") == 0 ) {
- // We're traced if the PID is not 0 and no other PID starts
- // with 0 digit, so it's enough to check for just a single
- // character.
- return line.length() > PREFIX_LEN && line[PREFIX_LEN] != '0';
- }
- }
-
- return false;
- }
- } // namespace Catch
-#elif defined(_MSC_VER)
- extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent();
- namespace Catch {
- bool isDebuggerActive() {
- return IsDebuggerPresent() != 0;
- }
- }
-#elif defined(__MINGW32__)
- extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent();
- namespace Catch {
- bool isDebuggerActive() {
- return IsDebuggerPresent() != 0;
- }
- }
-#else
- namespace Catch {
- inline bool isDebuggerActive() { return false; }
- }
-#endif // Platform
-
-#ifdef CATCH_PLATFORM_WINDOWS
-
- namespace Catch {
- void writeToDebugConsole( std::string const& text ) {
- ::OutputDebugStringA( text.c_str() );
- }
- }
-#else
- namespace Catch {
- void writeToDebugConsole( std::string const& text ) {
- // !TBD: Need a version for Mac/ XCode and other IDEs
- Catch::cout() << text;
- }
- }
-#endif // Platform
-
-// #included from: catch_tostring.hpp
-#define TWOBLUECUBES_CATCH_TOSTRING_HPP_INCLUDED
-
-namespace Catch {
-
-namespace Detail {
-
- const std::string unprintableString = "{?}";
-
- namespace {
- const int hexThreshold = 255;
-
- struct Endianness {
- enum Arch { Big, Little };
-
- static Arch which() {
- union _{
- int asInt;
- char asChar[sizeof (int)];
- } u;
-
- u.asInt = 1;
- return ( u.asChar[sizeof(int)-1] == 1 ) ? Big : Little;
- }
- };
- }
-
- std::string rawMemoryToString( const void *object, std::size_t size )
- {
- // Reverse order for little endian architectures
- int i = 0, end = static_cast<int>( size ), inc = 1;
- if( Endianness::which() == Endianness::Little ) {
- i = end-1;
- end = inc = -1;
- }
-
- unsigned char const *bytes = static_cast<unsigned char const *>(object);
- std::ostringstream os;
- os << "0x" << std::setfill('0') << std::hex;
- for( ; i != end; i += inc )
- os << std::setw(2) << static_cast<unsigned>(bytes[i]);
- return os.str();
- }
-}
-
-std::string toString( std::string const& value ) {
- std::string s = value;
- if( getCurrentContext().getConfig()->showInvisibles() ) {
- for(size_t i = 0; i < s.size(); ++i ) {
- std::string subs;
- switch( s[i] ) {
- case '\n': subs = "\\n"; break;
- case '\t': subs = "\\t"; break;
- default: break;
- }
- if( !subs.empty() ) {
- s = s.substr( 0, i ) + subs + s.substr( i+1 );
- ++i;
- }
- }
- }
- return '"' + s + '"';
-}
-std::string toString( std::wstring const& value ) {
-
- std::string s;
- s.reserve( value.size() );
- for(size_t i = 0; i < value.size(); ++i )
- s += value[i] <= 0xff ? static_cast<char>( value[i] ) : '?';
- return Catch::toString( s );
-}
-
-std::string toString( const char* const value ) {
- return value ? Catch::toString( std::string( value ) ) : std::string( "{null string}" );
-}
-
-std::string toString( char* const value ) {
- return Catch::toString( static_cast<const char*>( value ) );
-}
-
-std::string toString( const wchar_t* const value )
-{
- return value ? Catch::toString( std::wstring(value) ) : std::string( "{null string}" );
-}
-
-std::string toString( wchar_t* const value )
-{
- return Catch::toString( static_cast<const wchar_t*>( value ) );
-}
-
-std::string toString( int value ) {
- std::ostringstream oss;
- oss << value;
- if( value > Detail::hexThreshold )
- oss << " (0x" << std::hex << value << ')';
- return oss.str();
-}
-
-std::string toString( unsigned long value ) {
- std::ostringstream oss;
- oss << value;
- if( value > Detail::hexThreshold )
- oss << " (0x" << std::hex << value << ')';
- return oss.str();
-}
-
-std::string toString( unsigned int value ) {
- return Catch::toString( static_cast<unsigned long>( value ) );
-}
-
-template<typename T>
-std::string fpToString( T value, int precision ) {
- std::ostringstream oss;
- oss << std::setprecision( precision )
- << std::fixed
- << value;
- std::string d = oss.str();
- std::size_t i = d.find_last_not_of( '0' );
- if( i != std::string::npos && i != d.size()-1 ) {
- if( d[i] == '.' )
- i++;
- d = d.substr( 0, i+1 );
- }
- return d;
-}
-
-std::string toString( const double value ) {
- return fpToString( value, 10 );
-}
-std::string toString( const float value ) {
- return fpToString( value, 5 ) + 'f';
-}
-
-std::string toString( bool value ) {
- return value ? "true" : "false";
-}
-
-std::string toString( char value ) {
- if ( value == '\r' )
- return "'\\r'";
- if ( value == '\f' )
- return "'\\f'";
- if ( value == '\n' )
- return "'\\n'";
- if ( value == '\t' )
- return "'\\t'";
- if ( '\0' <= value && value < ' ' )
- return toString( static_cast<unsigned int>( value ) );
- char chstr[] = "' '";
- chstr[1] = value;
- return chstr;
-}
-
-std::string toString( signed char value ) {
- return toString( static_cast<char>( value ) );
-}
-
-std::string toString( unsigned char value ) {
- return toString( static_cast<char>( value ) );
-}
-
-#ifdef CATCH_CONFIG_CPP11_LONG_LONG
-std::string toString( long long value ) {
- std::ostringstream oss;
- oss << value;
- if( value > Detail::hexThreshold )
- oss << " (0x" << std::hex << value << ')';
- return oss.str();
-}
-std::string toString( unsigned long long value ) {
- std::ostringstream oss;
- oss << value;
- if( value > Detail::hexThreshold )
- oss << " (0x" << std::hex << value << ')';
- return oss.str();
-}
-#endif
-
-#ifdef CATCH_CONFIG_CPP11_NULLPTR
-std::string toString( std::nullptr_t ) {
- return "nullptr";
-}
-#endif
-
-#ifdef __OBJC__
- std::string toString( NSString const * const& nsstring ) {
- if( !nsstring )
- return "nil";
- return "@" + toString([nsstring UTF8String]);
- }
- std::string toString( NSString * CATCH_ARC_STRONG const& nsstring ) {
- if( !nsstring )
- return "nil";
- return "@" + toString([nsstring UTF8String]);
- }
- std::string toString( NSObject* const& nsObject ) {
- return toString( [nsObject description] );
- }
-#endif
-
-} // end namespace Catch
-
-// #included from: catch_result_builder.hpp
-#define TWOBLUECUBES_CATCH_RESULT_BUILDER_HPP_INCLUDED
-
-namespace Catch {
-
- std::string capturedExpressionWithSecondArgument( std::string const& capturedExpression, std::string const& secondArg ) {
- return secondArg.empty() || secondArg == "\"\""
- ? capturedExpression
- : capturedExpression + ", " + secondArg;
- }
- ResultBuilder::ResultBuilder( char const* macroName,
- SourceLineInfo const& lineInfo,
- char const* capturedExpression,
- ResultDisposition::Flags resultDisposition,
- char const* secondArg )
- : m_assertionInfo( macroName, lineInfo, capturedExpressionWithSecondArgument( capturedExpression, secondArg ), resultDisposition ),
- m_shouldDebugBreak( false ),
- m_shouldThrow( false )
- {}
-
- ResultBuilder& ResultBuilder::setResultType( ResultWas::OfType result ) {
- m_data.resultType = result;
- return *this;
- }
- ResultBuilder& ResultBuilder::setResultType( bool result ) {
- m_data.resultType = result ? ResultWas::Ok : ResultWas::ExpressionFailed;
- return *this;
- }
-
- void ResultBuilder::endExpression( DecomposedExpression const& expr ) {
- AssertionResult result = build( expr );
- handleResult( result );
- }
-
- void ResultBuilder::useActiveException( ResultDisposition::Flags resultDisposition ) {
- m_assertionInfo.resultDisposition = resultDisposition;
- m_stream.oss << Catch::translateActiveException();
- captureResult( ResultWas::ThrewException );
- }
-
- void ResultBuilder::captureResult( ResultWas::OfType resultType ) {
- setResultType( resultType );
- captureExpression();
- }
-
- void ResultBuilder::captureExpectedException( std::string const& expectedMessage ) {
- if( expectedMessage.empty() )
- captureExpectedException( Matchers::Impl::Generic::AllOf<std::string>() );
- else
- captureExpectedException( Matchers::Equals( expectedMessage ) );
- }
-
- void ResultBuilder::captureExpectedException( Matchers::Impl::Matcher<std::string> const& matcher ) {
-
- assert( !isFalseTest( m_assertionInfo.resultDisposition ) );
- AssertionResultData data = m_data;
- data.resultType = ResultWas::Ok;
- data.reconstructedExpression = m_assertionInfo.capturedExpression;
-
- std::string actualMessage = Catch::translateActiveException();
- if( !matcher.match( actualMessage ) ) {
- data.resultType = ResultWas::ExpressionFailed;
- data.reconstructedExpression = actualMessage;
- }
- AssertionResult result( m_assertionInfo, data );
- handleResult( result );
- }
-
- void ResultBuilder::captureExpression() {
- AssertionResult result = build();
- handleResult( result );
- }
-
- void ResultBuilder::handleResult( AssertionResult const& result )
- {
- getResultCapture().assertionEnded( result );
-
- if( !result.isOk() ) {
- if( getCurrentContext().getConfig()->shouldDebugBreak() )
- m_shouldDebugBreak = true;
- if( getCurrentContext().getRunner()->aborting() || (m_assertionInfo.resultDisposition & ResultDisposition::Normal) )
- m_shouldThrow = true;
- }
- }
-
- void ResultBuilder::react() {
- if( m_shouldThrow )
- throw Catch::TestFailureException();
- }
-
- bool ResultBuilder::shouldDebugBreak() const { return m_shouldDebugBreak; }
- bool ResultBuilder::allowThrows() const { return getCurrentContext().getConfig()->allowThrows(); }
-
- AssertionResult ResultBuilder::build() const
- {
- return build( *this );
- }
-
- // CAVEAT: The returned AssertionResult stores a pointer to the argument expr,
- // a temporary DecomposedExpression, which in turn holds references to
- // operands, possibly temporary as well.
- // It should immediately be passed to handleResult; if the expression
- // needs to be reported, its string expansion must be composed before
- // the temporaries are destroyed.
- AssertionResult ResultBuilder::build( DecomposedExpression const& expr ) const
- {
- assert( m_data.resultType != ResultWas::Unknown );
- AssertionResultData data = m_data;
-
- // Flip bool results if FalseTest flag is set
- if( isFalseTest( m_assertionInfo.resultDisposition ) ) {
- data.negate( expr.isBinaryExpression() );
- }
-
- data.message = m_stream.oss.str();
- data.decomposedExpression = &expr; // for lazy reconstruction
- return AssertionResult( m_assertionInfo, data );
- }
-
- void ResultBuilder::reconstructExpression( std::string& dest ) const {
- dest = m_assertionInfo.capturedExpression;
- }
-
-} // end namespace Catch
-
-// #included from: catch_tag_alias_registry.hpp
-#define TWOBLUECUBES_CATCH_TAG_ALIAS_REGISTRY_HPP_INCLUDED
-
-// #included from: catch_tag_alias_registry.h
-#define TWOBLUECUBES_CATCH_TAG_ALIAS_REGISTRY_H_INCLUDED
-
-#include <map>
-
-namespace Catch {
-
- class TagAliasRegistry : public ITagAliasRegistry {
- public:
- virtual ~TagAliasRegistry();
- virtual Option<TagAlias> find( std::string const& alias ) const;
- virtual std::string expandAliases( std::string const& unexpandedTestSpec ) const;
- void add( char const* alias, char const* tag, SourceLineInfo const& lineInfo );
- static TagAliasRegistry& get();
-
- private:
- std::map<std::string, TagAlias> m_registry;
- };
-
-} // end namespace Catch
-
-namespace Catch {
-
- TagAliasRegistry::~TagAliasRegistry() {}
-
- Option<TagAlias> TagAliasRegistry::find( std::string const& alias ) const {
- std::map<std::string, TagAlias>::const_iterator it = m_registry.find( alias );
- if( it != m_registry.end() )
- return it->second;
- else
- return Option<TagAlias>();
- }
-
- std::string TagAliasRegistry::expandAliases( std::string const& unexpandedTestSpec ) const {
- std::string expandedTestSpec = unexpandedTestSpec;
- for( std::map<std::string, TagAlias>::const_iterator it = m_registry.begin(), itEnd = m_registry.end();
- it != itEnd;
- ++it ) {
- std::size_t pos = expandedTestSpec.find( it->first );
- if( pos != std::string::npos ) {
- expandedTestSpec = expandedTestSpec.substr( 0, pos ) +
- it->second.tag +
- expandedTestSpec.substr( pos + it->first.size() );
- }
- }
- return expandedTestSpec;
- }
-
- void TagAliasRegistry::add( char const* alias, char const* tag, SourceLineInfo const& lineInfo ) {
-
- if( !startsWith( alias, "[@" ) || !endsWith( alias, ']' ) ) {
- std::ostringstream oss;
- oss << "error: tag alias, \"" << alias << "\" is not of the form [@alias name].\n" << lineInfo;
- throw std::domain_error( oss.str().c_str() );
- }
- if( !m_registry.insert( std::make_pair( alias, TagAlias( tag, lineInfo ) ) ).second ) {
- std::ostringstream oss;
- oss << "error: tag alias, \"" << alias << "\" already registered.\n"
- << "\tFirst seen at " << find(alias)->lineInfo << '\n'
- << "\tRedefined at " << lineInfo;
- throw std::domain_error( oss.str().c_str() );
- }
- }
-
- TagAliasRegistry& TagAliasRegistry::get() {
- static TagAliasRegistry instance;
- return instance;
-
- }
-
- ITagAliasRegistry::~ITagAliasRegistry() {}
- ITagAliasRegistry const& ITagAliasRegistry::get() { return TagAliasRegistry::get(); }
-
- RegistrarForTagAliases::RegistrarForTagAliases( char const* alias, char const* tag, SourceLineInfo const& lineInfo ) {
- try {
- TagAliasRegistry::get().add( alias, tag, lineInfo );
- }
- catch( std::exception& ex ) {
- Colour colourGuard( Colour::Red );
- Catch::cerr() << ex.what() << std::endl;
- exit(1);
- }
- }
-
-} // end namespace Catch
-
-// #included from: ../reporters/catch_reporter_multi.hpp
-#define TWOBLUECUBES_CATCH_REPORTER_MULTI_HPP_INCLUDED
-
-namespace Catch {
-
-class MultipleReporters : public SharedImpl<IStreamingReporter> {
- typedef std::vector<Ptr<IStreamingReporter> > Reporters;
- Reporters m_reporters;
-
-public:
- void add( Ptr<IStreamingReporter> const& reporter ) {
- m_reporters.push_back( reporter );
- }
-
-public: // IStreamingReporter
-
- virtual ReporterPreferences getPreferences() const CATCH_OVERRIDE {
- return m_reporters[0]->getPreferences();
- }
-
- virtual void noMatchingTestCases( std::string const& spec ) CATCH_OVERRIDE {
- for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end();
- it != itEnd;
- ++it )
- (*it)->noMatchingTestCases( spec );
- }
-
- virtual void testRunStarting( TestRunInfo const& testRunInfo ) CATCH_OVERRIDE {
- for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end();
- it != itEnd;
- ++it )
- (*it)->testRunStarting( testRunInfo );
- }
-
- virtual void testGroupStarting( GroupInfo const& groupInfo ) CATCH_OVERRIDE {
- for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end();
- it != itEnd;
- ++it )
- (*it)->testGroupStarting( groupInfo );
- }
-
- virtual void testCaseStarting( TestCaseInfo const& testInfo ) CATCH_OVERRIDE {
- for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end();
- it != itEnd;
- ++it )
- (*it)->testCaseStarting( testInfo );
- }
-
- virtual void sectionStarting( SectionInfo const& sectionInfo ) CATCH_OVERRIDE {
- for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end();
- it != itEnd;
- ++it )
- (*it)->sectionStarting( sectionInfo );
- }
-
- virtual void assertionStarting( AssertionInfo const& assertionInfo ) CATCH_OVERRIDE {
- for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end();
- it != itEnd;
- ++it )
- (*it)->assertionStarting( assertionInfo );
- }
-
- // The return value indicates if the messages buffer should be cleared:
- virtual bool assertionEnded( AssertionStats const& assertionStats ) CATCH_OVERRIDE {
- bool clearBuffer = false;
- for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end();
- it != itEnd;
- ++it )
- clearBuffer |= (*it)->assertionEnded( assertionStats );
- return clearBuffer;
- }
-
- virtual void sectionEnded( SectionStats const& sectionStats ) CATCH_OVERRIDE {
- for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end();
- it != itEnd;
- ++it )
- (*it)->sectionEnded( sectionStats );
- }
-
- virtual void testCaseEnded( TestCaseStats const& testCaseStats ) CATCH_OVERRIDE {
- for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end();
- it != itEnd;
- ++it )
- (*it)->testCaseEnded( testCaseStats );
- }
-
- virtual void testGroupEnded( TestGroupStats const& testGroupStats ) CATCH_OVERRIDE {
- for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end();
- it != itEnd;
- ++it )
- (*it)->testGroupEnded( testGroupStats );
- }
-
- virtual void testRunEnded( TestRunStats const& testRunStats ) CATCH_OVERRIDE {
- for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end();
- it != itEnd;
- ++it )
- (*it)->testRunEnded( testRunStats );
- }
-
- virtual void skipTest( TestCaseInfo const& testInfo ) CATCH_OVERRIDE {
- for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end();
- it != itEnd;
- ++it )
- (*it)->skipTest( testInfo );
- }
-
- virtual MultipleReporters* tryAsMulti() CATCH_OVERRIDE {
- return this;
- }
-
-};
-
-Ptr<IStreamingReporter> addReporter( Ptr<IStreamingReporter> const& existingReporter, Ptr<IStreamingReporter> const& additionalReporter ) {
- Ptr<IStreamingReporter> resultingReporter;
-
- if( existingReporter ) {
- MultipleReporters* multi = existingReporter->tryAsMulti();
- if( !multi ) {
- multi = new MultipleReporters;
- resultingReporter = Ptr<IStreamingReporter>( multi );
- if( existingReporter )
- multi->add( existingReporter );
- }
- else
- resultingReporter = existingReporter;
- multi->add( additionalReporter );
- }
- else
- resultingReporter = additionalReporter;
-
- return resultingReporter;
-}
-
-} // end namespace Catch
-
-// #included from: ../reporters/catch_reporter_xml.hpp
-#define TWOBLUECUBES_CATCH_REPORTER_XML_HPP_INCLUDED
-
-// #included from: catch_reporter_bases.hpp
-#define TWOBLUECUBES_CATCH_REPORTER_BASES_HPP_INCLUDED
-
-#include <cstring>
-
-namespace Catch {
-
- struct StreamingReporterBase : SharedImpl<IStreamingReporter> {
-
- StreamingReporterBase( ReporterConfig const& _config )
- : m_config( _config.fullConfig() ),
- stream( _config.stream() )
- {
- m_reporterPrefs.shouldRedirectStdOut = false;
- }
-
- virtual ReporterPreferences getPreferences() const CATCH_OVERRIDE {
- return m_reporterPrefs;
- }
-
- virtual ~StreamingReporterBase() CATCH_OVERRIDE;
-
- virtual void noMatchingTestCases( std::string const& ) CATCH_OVERRIDE {}
-
- virtual void testRunStarting( TestRunInfo const& _testRunInfo ) CATCH_OVERRIDE {
- currentTestRunInfo = _testRunInfo;
- }
- virtual void testGroupStarting( GroupInfo const& _groupInfo ) CATCH_OVERRIDE {
- currentGroupInfo = _groupInfo;
- }
-
- virtual void testCaseStarting( TestCaseInfo const& _testInfo ) CATCH_OVERRIDE {
- currentTestCaseInfo = _testInfo;
- }
- virtual void sectionStarting( SectionInfo const& _sectionInfo ) CATCH_OVERRIDE {
- m_sectionStack.push_back( _sectionInfo );
- }
-
- virtual void sectionEnded( SectionStats const& /* _sectionStats */ ) CATCH_OVERRIDE {
- m_sectionStack.pop_back();
- }
- virtual void testCaseEnded( TestCaseStats const& /* _testCaseStats */ ) CATCH_OVERRIDE {
- currentTestCaseInfo.reset();
- }
- virtual void testGroupEnded( TestGroupStats const& /* _testGroupStats */ ) CATCH_OVERRIDE {
- currentGroupInfo.reset();
- }
- virtual void testRunEnded( TestRunStats const& /* _testRunStats */ ) CATCH_OVERRIDE {
- currentTestCaseInfo.reset();
- currentGroupInfo.reset();
- currentTestRunInfo.reset();
- }
-
- virtual void skipTest( TestCaseInfo const& ) CATCH_OVERRIDE {
- // Don't do anything with this by default.
- // It can optionally be overridden in the derived class.
- }
-
- Ptr<IConfig const> m_config;
- std::ostream& stream;
-
- LazyStat<TestRunInfo> currentTestRunInfo;
- LazyStat<GroupInfo> currentGroupInfo;
- LazyStat<TestCaseInfo> currentTestCaseInfo;
-
- std::vector<SectionInfo> m_sectionStack;
- ReporterPreferences m_reporterPrefs;
- };
-
- struct CumulativeReporterBase : SharedImpl<IStreamingReporter> {
- template<typename T, typename ChildNodeT>
- struct Node : SharedImpl<> {
- explicit Node( T const& _value ) : value( _value ) {}
- virtual ~Node() {}
-
- typedef std::vector<Ptr<ChildNodeT> > ChildNodes;
- T value;
- ChildNodes children;
- };
- struct SectionNode : SharedImpl<> {
- explicit SectionNode( SectionStats const& _stats ) : stats( _stats ) {}
- virtual ~SectionNode();
-
- bool operator == ( SectionNode const& other ) const {
- return stats.sectionInfo.lineInfo == other.stats.sectionInfo.lineInfo;
- }
- bool operator == ( Ptr<SectionNode> const& other ) const {
- return operator==( *other );
- }
-
- SectionStats stats;
- typedef std::vector<Ptr<SectionNode> > ChildSections;
- typedef std::vector<AssertionStats> Assertions;
- ChildSections childSections;
- Assertions assertions;
- std::string stdOut;
- std::string stdErr;
- };
-
- struct BySectionInfo {
- BySectionInfo( SectionInfo const& other ) : m_other( other ) {}
- BySectionInfo( BySectionInfo const& other ) : m_other( other.m_other ) {}
- bool operator() ( Ptr<SectionNode> const& node ) const {
- return node->stats.sectionInfo.lineInfo == m_other.lineInfo;
- }
- private:
- void operator=( BySectionInfo const& );
- SectionInfo const& m_other;
- };
-
- typedef Node<TestCaseStats, SectionNode> TestCaseNode;
- typedef Node<TestGroupStats, TestCaseNode> TestGroupNode;
- typedef Node<TestRunStats, TestGroupNode> TestRunNode;
-
- CumulativeReporterBase( ReporterConfig const& _config )
- : m_config( _config.fullConfig() ),
- stream( _config.stream() )
- {
- m_reporterPrefs.shouldRedirectStdOut = false;
- }
- ~CumulativeReporterBase();
-
- virtual ReporterPreferences getPreferences() const CATCH_OVERRIDE {
- return m_reporterPrefs;
- }
-
- virtual void testRunStarting( TestRunInfo const& ) CATCH_OVERRIDE {}
- virtual void testGroupStarting( GroupInfo const& ) CATCH_OVERRIDE {}
-
- virtual void testCaseStarting( TestCaseInfo const& ) CATCH_OVERRIDE {}
-
- virtual void sectionStarting( SectionInfo const& sectionInfo ) CATCH_OVERRIDE {
- SectionStats incompleteStats( sectionInfo, Counts(), 0, false );
- Ptr<SectionNode> node;
- if( m_sectionStack.empty() ) {
- if( !m_rootSection )
- m_rootSection = new SectionNode( incompleteStats );
- node = m_rootSection;
- }
- else {
- SectionNode& parentNode = *m_sectionStack.back();
- SectionNode::ChildSections::const_iterator it =
- std::find_if( parentNode.childSections.begin(),
- parentNode.childSections.end(),
- BySectionInfo( sectionInfo ) );
- if( it == parentNode.childSections.end() ) {
- node = new SectionNode( incompleteStats );
- parentNode.childSections.push_back( node );
- }
- else
- node = *it;
- }
- m_sectionStack.push_back( node );
- m_deepestSection = node;
- }
-
- virtual void assertionStarting( AssertionInfo const& ) CATCH_OVERRIDE {}
-
- virtual bool assertionEnded( AssertionStats const& assertionStats ) CATCH_OVERRIDE {
- assert( !m_sectionStack.empty() );
- SectionNode& sectionNode = *m_sectionStack.back();
- sectionNode.assertions.push_back( assertionStats );
- // AssertionResult holds a pointer to a temporary DecomposedExpression,
- // which getExpandedExpression() calls to build the expression string.
- // Our section stack copy of the assertionResult will likely outlive the
- // temporary, so it must be expanded or discarded now to avoid calling
- // a destroyed object later.
- prepareExpandedExpression( sectionNode.assertions.back().assertionResult );
- return true;
- }
- virtual void sectionEnded( SectionStats const& sectionStats ) CATCH_OVERRIDE {
- assert( !m_sectionStack.empty() );
- SectionNode& node = *m_sectionStack.back();
- node.stats = sectionStats;
- m_sectionStack.pop_back();
- }
- virtual void testCaseEnded( TestCaseStats const& testCaseStats ) CATCH_OVERRIDE {
- Ptr<TestCaseNode> node = new TestCaseNode( testCaseStats );
- assert( m_sectionStack.size() == 0 );
- node->children.push_back( m_rootSection );
- m_testCases.push_back( node );
- m_rootSection.reset();
-
- assert( m_deepestSection );
- m_deepestSection->stdOut = testCaseStats.stdOut;
- m_deepestSection->stdErr = testCaseStats.stdErr;
- }
- virtual void testGroupEnded( TestGroupStats const& testGroupStats ) CATCH_OVERRIDE {
- Ptr<TestGroupNode> node = new TestGroupNode( testGroupStats );
- node->children.swap( m_testCases );
- m_testGroups.push_back( node );
- }
- virtual void testRunEnded( TestRunStats const& testRunStats ) CATCH_OVERRIDE {
- Ptr<TestRunNode> node = new TestRunNode( testRunStats );
- node->children.swap( m_testGroups );
- m_testRuns.push_back( node );
- testRunEndedCumulative();
- }
- virtual void testRunEndedCumulative() = 0;
-
- virtual void skipTest( TestCaseInfo const& ) CATCH_OVERRIDE {}
-
- virtual void prepareExpandedExpression( AssertionResult& result ) const {
- if( result.isOk() )
- result.discardDecomposedExpression();
- else
- result.expandDecomposedExpression();
- }
-
- Ptr<IConfig const> m_config;
- std::ostream& stream;
- std::vector<AssertionStats> m_assertions;
- std::vector<std::vector<Ptr<SectionNode> > > m_sections;
- std::vector<Ptr<TestCaseNode> > m_testCases;
- std::vector<Ptr<TestGroupNode> > m_testGroups;
-
- std::vector<Ptr<TestRunNode> > m_testRuns;
-
- Ptr<SectionNode> m_rootSection;
- Ptr<SectionNode> m_deepestSection;
- std::vector<Ptr<SectionNode> > m_sectionStack;
- ReporterPreferences m_reporterPrefs;
-
- };
-
- template<char C>
- char const* getLineOfChars() {
- static char line[CATCH_CONFIG_CONSOLE_WIDTH] = {0};
- if( !*line ) {
- std::memset( line, C, CATCH_CONFIG_CONSOLE_WIDTH-1 );
- line[CATCH_CONFIG_CONSOLE_WIDTH-1] = 0;
- }
- return line;
- }
-
- struct TestEventListenerBase : StreamingReporterBase {
- TestEventListenerBase( ReporterConfig const& _config )
- : StreamingReporterBase( _config )
- {}
-
- virtual void assertionStarting( AssertionInfo const& ) CATCH_OVERRIDE {}
- virtual bool assertionEnded( AssertionStats const& ) CATCH_OVERRIDE {
- return false;
- }
- };
-
-} // end namespace Catch
-
-// #included from: ../internal/catch_reporter_registrars.hpp
-#define TWOBLUECUBES_CATCH_REPORTER_REGISTRARS_HPP_INCLUDED
-
-namespace Catch {
-
- template<typename T>
- class LegacyReporterRegistrar {
-
- class ReporterFactory : public IReporterFactory {
- virtual IStreamingReporter* create( ReporterConfig const& config ) const {
- return new LegacyReporterAdapter( new T( config ) );
- }
-
- virtual std::string getDescription() const {
- return T::getDescription();
- }
- };
-
- public:
-
- LegacyReporterRegistrar( std::string const& name ) {
- getMutableRegistryHub().registerReporter( name, new ReporterFactory() );
- }
- };
-
- template<typename T>
- class ReporterRegistrar {
-
- class ReporterFactory : public SharedImpl<IReporterFactory> {
-
- // *** Please Note ***:
- // - If you end up here looking at a compiler error because it's trying to register
- // your custom reporter class be aware that the native reporter interface has changed
- // to IStreamingReporter. The "legacy" interface, IReporter, is still supported via
- // an adapter. Just use REGISTER_LEGACY_REPORTER to take advantage of the adapter.
- // However please consider updating to the new interface as the old one is now
- // deprecated and will probably be removed quite soon!
- // Please contact me via github if you have any questions at all about this.
- // In fact, ideally, please contact me anyway to let me know you've hit this - as I have
- // no idea who is actually using custom reporters at all (possibly no-one!).
- // The new interface is designed to minimise exposure to interface changes in the future.
- virtual IStreamingReporter* create( ReporterConfig const& config ) const {
- return new T( config );
- }
-
- virtual std::string getDescription() const {
- return T::getDescription();
- }
- };
-
- public:
-
- ReporterRegistrar( std::string const& name ) {
- getMutableRegistryHub().registerReporter( name, new ReporterFactory() );
- }
- };
-
- template<typename T>
- class ListenerRegistrar {
-
- class ListenerFactory : public SharedImpl<IReporterFactory> {
-
- virtual IStreamingReporter* create( ReporterConfig const& config ) const {
- return new T( config );
- }
- virtual std::string getDescription() const {
- return std::string();
- }
- };
-
- public:
-
- ListenerRegistrar() {
- getMutableRegistryHub().registerListener( new ListenerFactory() );
- }
- };
-}
-
-#define INTERNAL_CATCH_REGISTER_LEGACY_REPORTER( name, reporterType ) \
- namespace{ Catch::LegacyReporterRegistrar<reporterType> catch_internal_RegistrarFor##reporterType( name ); }
-
-#define INTERNAL_CATCH_REGISTER_REPORTER( name, reporterType ) \
- namespace{ Catch::ReporterRegistrar<reporterType> catch_internal_RegistrarFor##reporterType( name ); }
-
-#define INTERNAL_CATCH_REGISTER_LISTENER( listenerType ) \
- namespace{ Catch::ListenerRegistrar<listenerType> catch_internal_RegistrarFor##listenerType; }
-
-// #included from: ../internal/catch_xmlwriter.hpp
-#define TWOBLUECUBES_CATCH_XMLWRITER_HPP_INCLUDED
-
-#include <sstream>
-#include <string>
-#include <vector>
-#include <iomanip>
-
-namespace Catch {
-
- class XmlEncode {
- public:
- enum ForWhat { ForTextNodes, ForAttributes };
-
- XmlEncode( std::string const& str, ForWhat forWhat = ForTextNodes )
- : m_str( str ),
- m_forWhat( forWhat )
- {}
-
- void encodeTo( std::ostream& os ) const {
-
- // Apostrophe escaping not necessary if we always use " to write attributes
- // (see: http://www.w3.org/TR/xml/#syntax)
-
- for( std::size_t i = 0; i < m_str.size(); ++ i ) {
- char c = m_str[i];
- switch( c ) {
- case '<': os << "&lt;"; break;
- case '&': os << "&amp;"; break;
-
- case '>':
- // See: http://www.w3.org/TR/xml/#syntax
- if( i > 2 && m_str[i-1] == ']' && m_str[i-2] == ']' )
- os << "&gt;";
- else
- os << c;
- break;
-
- case '\"':
- if( m_forWhat == ForAttributes )
- os << "&quot;";
- else
- os << c;
- break;
-
- default:
- // Escape control chars - based on contribution by @espenalb in PR #465 and
- // by @mrpi PR #588
- if ( ( c >= 0 && c < '\x09' ) || ( c > '\x0D' && c < '\x20') || c=='\x7F' ) {
- // see http://stackoverflow.com/questions/404107/why-are-control-characters-illegal-in-xml-1-0
- os << "\\x" << std::uppercase << std::hex << std::setfill('0') << std::setw(2)
- << static_cast<int>( c );
- }
- else
- os << c;
- }
- }
- }
-
- friend std::ostream& operator << ( std::ostream& os, XmlEncode const& xmlEncode ) {
- xmlEncode.encodeTo( os );
- return os;
- }
-
- private:
- std::string m_str;
- ForWhat m_forWhat;
- };
-
- class XmlWriter {
- public:
-
- class ScopedElement {
- public:
- ScopedElement( XmlWriter* writer )
- : m_writer( writer )
- {}
-
- ScopedElement( ScopedElement const& other )
- : m_writer( other.m_writer ){
- other.m_writer = CATCH_NULL;
- }
-
- ~ScopedElement() {
- if( m_writer )
- m_writer->endElement();
- }
-
- ScopedElement& writeText( std::string const& text, bool indent = true ) {
- m_writer->writeText( text, indent );
- return *this;
- }
-
- template<typename T>
- ScopedElement& writeAttribute( std::string const& name, T const& attribute ) {
- m_writer->writeAttribute( name, attribute );
- return *this;
- }
-
- private:
- mutable XmlWriter* m_writer;
- };
-
- XmlWriter()
- : m_tagIsOpen( false ),
- m_needsNewline( false ),
- m_os( Catch::cout() )
- {
- writeDeclaration();
- }
-
- XmlWriter( std::ostream& os )
- : m_tagIsOpen( false ),
- m_needsNewline( false ),
- m_os( os )
- {
- writeDeclaration();
- }
-
- ~XmlWriter() {
- while( !m_tags.empty() )
- endElement();
- }
-
- XmlWriter& startElement( std::string const& name ) {
- ensureTagClosed();
- newlineIfNecessary();
- m_os << m_indent << '<' << name;
- m_tags.push_back( name );
- m_indent += " ";
- m_tagIsOpen = true;
- return *this;
- }
-
- ScopedElement scopedElement( std::string const& name ) {
- ScopedElement scoped( this );
- startElement( name );
- return scoped;
- }
-
- XmlWriter& endElement() {
- newlineIfNecessary();
- m_indent = m_indent.substr( 0, m_indent.size()-2 );
- if( m_tagIsOpen ) {
- m_os << "/>";
- m_tagIsOpen = false;
- }
- else {
- m_os << m_indent << "</" << m_tags.back() << ">";
- }
- m_os << std::endl;
- m_tags.pop_back();
- return *this;
- }
-
- XmlWriter& writeAttribute( std::string const& name, std::string const& attribute ) {
- if( !name.empty() && !attribute.empty() )
- m_os << ' ' << name << "=\"" << XmlEncode( attribute, XmlEncode::ForAttributes ) << '"';
- return *this;
- }
-
- XmlWriter& writeAttribute( std::string const& name, bool attribute ) {
- m_os << ' ' << name << "=\"" << ( attribute ? "true" : "false" ) << '"';
- return *this;
- }
-
- template<typename T>
- XmlWriter& writeAttribute( std::string const& name, T const& attribute ) {
- std::ostringstream oss;
- oss << attribute;
- return writeAttribute( name, oss.str() );
- }
-
- XmlWriter& writeText( std::string const& text, bool indent = true ) {
- if( !text.empty() ){
- bool tagWasOpen = m_tagIsOpen;
- ensureTagClosed();
- if( tagWasOpen && indent )
- m_os << m_indent;
- m_os << XmlEncode( text );
- m_needsNewline = true;
- }
- return *this;
- }
-
- XmlWriter& writeComment( std::string const& text ) {
- ensureTagClosed();
- m_os << m_indent << "<!--" << text << "-->";
- m_needsNewline = true;
- return *this;
- }
-
- void writeStylesheetRef( std::string const& url ) {
- m_os << "<?xml-stylesheet type=\"text/xsl\" href=\"" << url << "\"?>\n";
- }
-
- XmlWriter& writeBlankLine() {
- ensureTagClosed();
- m_os << '\n';
- return *this;
- }
-
- void ensureTagClosed() {
- if( m_tagIsOpen ) {
- m_os << ">" << std::endl;
- m_tagIsOpen = false;
- }
- }
-
- private:
- XmlWriter( XmlWriter const& );
- void operator=( XmlWriter const& );
-
- void writeDeclaration() {
- m_os << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
- }
-
- void newlineIfNecessary() {
- if( m_needsNewline ) {
- m_os << std::endl;
- m_needsNewline = false;
- }
- }
-
- bool m_tagIsOpen;
- bool m_needsNewline;
- std::vector<std::string> m_tags;
- std::string m_indent;
- std::ostream& m_os;
- };
-
-}
-// #included from: catch_reenable_warnings.h
-
-#define TWOBLUECUBES_CATCH_REENABLE_WARNINGS_H_INCLUDED
-
-#ifdef __clang__
-# ifdef __ICC // icpc defines the __clang__ macro
-# pragma warning(pop)
-# else
-# pragma clang diagnostic pop
-# endif
-#elif defined __GNUC__
-# pragma GCC diagnostic pop
-#endif
-
-
-namespace Catch {
- class XmlReporter : public StreamingReporterBase {
- public:
- XmlReporter( ReporterConfig const& _config )
- : StreamingReporterBase( _config ),
- m_xml(_config.stream()),
- m_sectionDepth( 0 )
- {
- m_reporterPrefs.shouldRedirectStdOut = true;
- }
-
- virtual ~XmlReporter() CATCH_OVERRIDE;
-
- static std::string getDescription() {
- return "Reports test results as an XML document";
- }
-
- virtual std::string getStylesheetRef() const {
- return std::string();
- }
-
- public: // StreamingReporterBase
-
- virtual void noMatchingTestCases( std::string const& s ) CATCH_OVERRIDE {
- StreamingReporterBase::noMatchingTestCases( s );
- }
-
- virtual void testRunStarting( TestRunInfo const& testInfo ) CATCH_OVERRIDE {
- StreamingReporterBase::testRunStarting( testInfo );
- std::string stylesheetRef = getStylesheetRef();
- if( !stylesheetRef.empty() )
- m_xml.writeStylesheetRef( stylesheetRef );
- m_xml.startElement( "Catch" );
- if( !m_config->name().empty() )
- m_xml.writeAttribute( "name", m_config->name() );
- }
-
- virtual void testGroupStarting( GroupInfo const& groupInfo ) CATCH_OVERRIDE {
- StreamingReporterBase::testGroupStarting( groupInfo );
- m_xml.startElement( "Group" )
- .writeAttribute( "name", groupInfo.name );
- }
-
- virtual void testCaseStarting( TestCaseInfo const& testInfo ) CATCH_OVERRIDE {
- StreamingReporterBase::testCaseStarting(testInfo);
- m_xml.startElement( "TestCase" )
- .writeAttribute( "name", trim( testInfo.name ) )
- .writeAttribute( "description", testInfo.description )
- .writeAttribute( "tags", testInfo.tagsAsString );
-
- if ( m_config->showDurations() == ShowDurations::Always )
- m_testCaseTimer.start();
- m_xml.ensureTagClosed();
- }
-
- virtual void sectionStarting( SectionInfo const& sectionInfo ) CATCH_OVERRIDE {
- StreamingReporterBase::sectionStarting( sectionInfo );
- if( m_sectionDepth++ > 0 ) {
- m_xml.startElement( "Section" )
- .writeAttribute( "name", trim( sectionInfo.name ) )
- .writeAttribute( "description", sectionInfo.description );
- m_xml.ensureTagClosed();
- }
- }
-
- virtual void assertionStarting( AssertionInfo const& ) CATCH_OVERRIDE { }
-
- virtual bool assertionEnded( AssertionStats const& assertionStats ) CATCH_OVERRIDE {
- const AssertionResult& assertionResult = assertionStats.assertionResult;
-
- // Print any info messages in <Info> tags.
- if( assertionStats.assertionResult.getResultType() != ResultWas::Ok ) {
- for( std::vector<MessageInfo>::const_iterator it = assertionStats.infoMessages.begin(), itEnd = assertionStats.infoMessages.end();
- it != itEnd;
- ++it ) {
- if( it->type == ResultWas::Info ) {
- m_xml.scopedElement( "Info" )
- .writeText( it->message );
- } else if ( it->type == ResultWas::Warning ) {
- m_xml.scopedElement( "Warning" )
- .writeText( it->message );
- }
- }
- }
-
- // Drop out if result was successful but we're not printing them.
- if( !m_config->includeSuccessfulResults() && isOk(assertionResult.getResultType()) )
- return true;
-
- // Print the expression if there is one.
- if( assertionResult.hasExpression() ) {
- m_xml.startElement( "Expression" )
- .writeAttribute( "success", assertionResult.succeeded() )
- .writeAttribute( "type", assertionResult.getTestMacroName() )
- .writeAttribute( "filename", assertionResult.getSourceInfo().file )
- .writeAttribute( "line", assertionResult.getSourceInfo().line );
-
- m_xml.scopedElement( "Original" )
- .writeText( assertionResult.getExpression() );
- m_xml.scopedElement( "Expanded" )
- .writeText( assertionResult.getExpandedExpression() );
- }
-
- // And... Print a result applicable to each result type.
- switch( assertionResult.getResultType() ) {
- case ResultWas::ThrewException:
- m_xml.scopedElement( "Exception" )
- .writeAttribute( "filename", assertionResult.getSourceInfo().file )
- .writeAttribute( "line", assertionResult.getSourceInfo().line )
- .writeText( assertionResult.getMessage() );
- break;
- case ResultWas::FatalErrorCondition:
- m_xml.scopedElement( "FatalErrorCondition" )
- .writeAttribute( "filename", assertionResult.getSourceInfo().file )
- .writeAttribute( "line", assertionResult.getSourceInfo().line )
- .writeText( assertionResult.getMessage() );
- break;
- case ResultWas::Info:
- m_xml.scopedElement( "Info" )
- .writeText( assertionResult.getMessage() );
- break;
- case ResultWas::Warning:
- // Warning will already have been written
- break;
- case ResultWas::ExplicitFailure:
- m_xml.scopedElement( "Failure" )
- .writeText( assertionResult.getMessage() );
- break;
- default:
- break;
- }
-
- if( assertionResult.hasExpression() )
- m_xml.endElement();
-
- return true;
- }
-
- virtual void sectionEnded( SectionStats const& sectionStats ) CATCH_OVERRIDE {
- StreamingReporterBase::sectionEnded( sectionStats );
- if( --m_sectionDepth > 0 ) {
- XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResults" );
- e.writeAttribute( "successes", sectionStats.assertions.passed );
- e.writeAttribute( "failures", sectionStats.assertions.failed );
- e.writeAttribute( "expectedFailures", sectionStats.assertions.failedButOk );
-
- if ( m_config->showDurations() == ShowDurations::Always )
- e.writeAttribute( "durationInSeconds", sectionStats.durationInSeconds );
-
- m_xml.endElement();
- }
- }
-
- virtual void testCaseEnded( TestCaseStats const& testCaseStats ) CATCH_OVERRIDE {
- StreamingReporterBase::testCaseEnded( testCaseStats );
- XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResult" );
- e.writeAttribute( "success", testCaseStats.totals.assertions.allOk() );
-
- if ( m_config->showDurations() == ShowDurations::Always )
- e.writeAttribute( "durationInSeconds", m_testCaseTimer.getElapsedSeconds() );
-
- if( !testCaseStats.stdOut.empty() )
- m_xml.scopedElement( "StdOut" ).writeText( trim( testCaseStats.stdOut ), false );
- if( !testCaseStats.stdErr.empty() )
- m_xml.scopedElement( "StdErr" ).writeText( trim( testCaseStats.stdErr ), false );
-
- m_xml.endElement();
- }
-
- virtual void testGroupEnded( TestGroupStats const& testGroupStats ) CATCH_OVERRIDE {
- StreamingReporterBase::testGroupEnded( testGroupStats );
- // TODO: Check testGroupStats.aborting and act accordingly.
- m_xml.scopedElement( "OverallResults" )
- .writeAttribute( "successes", testGroupStats.totals.assertions.passed )
- .writeAttribute( "failures", testGroupStats.totals.assertions.failed )
- .writeAttribute( "expectedFailures", testGroupStats.totals.assertions.failedButOk );
- m_xml.endElement();
- }
-
- virtual void testRunEnded( TestRunStats const& testRunStats ) CATCH_OVERRIDE {
- StreamingReporterBase::testRunEnded( testRunStats );
- m_xml.scopedElement( "OverallResults" )
- .writeAttribute( "successes", testRunStats.totals.assertions.passed )
- .writeAttribute( "failures", testRunStats.totals.assertions.failed )
- .writeAttribute( "expectedFailures", testRunStats.totals.assertions.failedButOk );
- m_xml.endElement();
- }
-
- private:
- Timer m_testCaseTimer;
- XmlWriter m_xml;
- int m_sectionDepth;
- };
-
- INTERNAL_CATCH_REGISTER_REPORTER( "xml", XmlReporter )
-
-} // end namespace Catch
-
-// #included from: ../reporters/catch_reporter_junit.hpp
-#define TWOBLUECUBES_CATCH_REPORTER_JUNIT_HPP_INCLUDED
-
-#include <assert.h>
-
-namespace Catch {
-
- namespace {
- std::string getCurrentTimestamp() {
- // Beware, this is not reentrant because of backward compatibility issues
- // Also, UTC only, again because of backward compatibility (%z is C++11)
- time_t rawtime;
- std::time(&rawtime);
- const size_t timeStampSize = sizeof("2017-01-16T17:06:45Z");
-
-#ifdef _MSC_VER
- std::tm timeInfo = {};
- gmtime_s(&timeInfo, &rawtime);
-#else
- std::tm* timeInfo;
- timeInfo = std::gmtime(&rawtime);
-#endif
-
- char timeStamp[timeStampSize];
- const char * const fmt = "%Y-%m-%dT%H:%M:%SZ";
-
-#ifdef _MSC_VER
- std::strftime(timeStamp, timeStampSize, fmt, &timeInfo);
-#else
- std::strftime(timeStamp, timeStampSize, fmt, timeInfo);
-#endif
- return std::string(timeStamp);
- }
-
- }
-
- class JunitReporter : public CumulativeReporterBase {
- public:
- JunitReporter( ReporterConfig const& _config )
- : CumulativeReporterBase( _config ),
- xml( _config.stream() )
- {
- m_reporterPrefs.shouldRedirectStdOut = true;
- }
-
- virtual ~JunitReporter() CATCH_OVERRIDE;
-
- static std::string getDescription() {
- return "Reports test results in an XML format that looks like Ant's junitreport target";
- }
-
- virtual void noMatchingTestCases( std::string const& /*spec*/ ) CATCH_OVERRIDE {}
-
- virtual void testRunStarting( TestRunInfo const& runInfo ) CATCH_OVERRIDE {
- CumulativeReporterBase::testRunStarting( runInfo );
- xml.startElement( "testsuites" );
- }
-
- virtual void testGroupStarting( GroupInfo const& groupInfo ) CATCH_OVERRIDE {
- suiteTimer.start();
- stdOutForSuite.str("");
- stdErrForSuite.str("");
- unexpectedExceptions = 0;
- CumulativeReporterBase::testGroupStarting( groupInfo );
- }
-
- virtual bool assertionEnded( AssertionStats const& assertionStats ) CATCH_OVERRIDE {
- if( assertionStats.assertionResult.getResultType() == ResultWas::ThrewException )
- unexpectedExceptions++;
- return CumulativeReporterBase::assertionEnded( assertionStats );
- }
-
- virtual void testCaseEnded( TestCaseStats const& testCaseStats ) CATCH_OVERRIDE {
- stdOutForSuite << testCaseStats.stdOut;
- stdErrForSuite << testCaseStats.stdErr;
- CumulativeReporterBase::testCaseEnded( testCaseStats );
- }
-
- virtual void testGroupEnded( TestGroupStats const& testGroupStats ) CATCH_OVERRIDE {
- double suiteTime = suiteTimer.getElapsedSeconds();
- CumulativeReporterBase::testGroupEnded( testGroupStats );
- writeGroup( *m_testGroups.back(), suiteTime );
- }
-
- virtual void testRunEndedCumulative() CATCH_OVERRIDE {
- xml.endElement();
- }
-
- void writeGroup( TestGroupNode const& groupNode, double suiteTime ) {
- XmlWriter::ScopedElement e = xml.scopedElement( "testsuite" );
- TestGroupStats const& stats = groupNode.value;
- xml.writeAttribute( "name", stats.groupInfo.name );
- xml.writeAttribute( "errors", unexpectedExceptions );
- xml.writeAttribute( "failures", stats.totals.assertions.failed-unexpectedExceptions );
- xml.writeAttribute( "tests", stats.totals.assertions.total() );
- xml.writeAttribute( "hostname", "tbd" ); // !TBD
- if( m_config->showDurations() == ShowDurations::Never )
- xml.writeAttribute( "time", "" );
- else
- xml.writeAttribute( "time", suiteTime );
- xml.writeAttribute( "timestamp", getCurrentTimestamp() );
-
- // Write test cases
- for( TestGroupNode::ChildNodes::const_iterator
- it = groupNode.children.begin(), itEnd = groupNode.children.end();
- it != itEnd;
- ++it )
- writeTestCase( **it );
-
- xml.scopedElement( "system-out" ).writeText( trim( stdOutForSuite.str() ), false );
- xml.scopedElement( "system-err" ).writeText( trim( stdErrForSuite.str() ), false );
- }
-
- void writeTestCase( TestCaseNode const& testCaseNode ) {
- TestCaseStats const& stats = testCaseNode.value;
-
- // All test cases have exactly one section - which represents the
- // test case itself. That section may have 0-n nested sections
- assert( testCaseNode.children.size() == 1 );
- SectionNode const& rootSection = *testCaseNode.children.front();
-
- std::string className = stats.testInfo.className;
-
- if( className.empty() ) {
- if( rootSection.childSections.empty() )
- className = "global";
- }
- writeSection( className, "", rootSection );
- }
-
- void writeSection( std::string const& className,
- std::string const& rootName,
- SectionNode const& sectionNode ) {
- std::string name = trim( sectionNode.stats.sectionInfo.name );
- if( !rootName.empty() )
- name = rootName + '/' + name;
-
- if( !sectionNode.assertions.empty() ||
- !sectionNode.stdOut.empty() ||
- !sectionNode.stdErr.empty() ) {
- XmlWriter::ScopedElement e = xml.scopedElement( "testcase" );
- if( className.empty() ) {
- xml.writeAttribute( "classname", name );
- xml.writeAttribute( "name", "root" );
- }
- else {
- xml.writeAttribute( "classname", className );
- xml.writeAttribute( "name", name );
- }
- xml.writeAttribute( "time", Catch::toString( sectionNode.stats.durationInSeconds ) );
-
- writeAssertions( sectionNode );
-
- if( !sectionNode.stdOut.empty() )
- xml.scopedElement( "system-out" ).writeText( trim( sectionNode.stdOut ), false );
- if( !sectionNode.stdErr.empty() )
- xml.scopedElement( "system-err" ).writeText( trim( sectionNode.stdErr ), false );
- }
- for( SectionNode::ChildSections::const_iterator
- it = sectionNode.childSections.begin(),
- itEnd = sectionNode.childSections.end();
- it != itEnd;
- ++it )
- if( className.empty() )
- writeSection( name, "", **it );
- else
- writeSection( className, name, **it );
- }
-
- void writeAssertions( SectionNode const& sectionNode ) {
- for( SectionNode::Assertions::const_iterator
- it = sectionNode.assertions.begin(), itEnd = sectionNode.assertions.end();
- it != itEnd;
- ++it )
- writeAssertion( *it );
- }
- void writeAssertion( AssertionStats const& stats ) {
- AssertionResult const& result = stats.assertionResult;
- if( !result.isOk() ) {
- std::string elementName;
- switch( result.getResultType() ) {
- case ResultWas::ThrewException:
- case ResultWas::FatalErrorCondition:
- elementName = "error";
- break;
- case ResultWas::ExplicitFailure:
- elementName = "failure";
- break;
- case ResultWas::ExpressionFailed:
- elementName = "failure";
- break;
- case ResultWas::DidntThrowException:
- elementName = "failure";
- break;
-
- // We should never see these here:
- case ResultWas::Info:
- case ResultWas::Warning:
- case ResultWas::Ok:
- case ResultWas::Unknown:
- case ResultWas::FailureBit:
- case ResultWas::Exception:
- elementName = "internalError";
- break;
- }
-
- XmlWriter::ScopedElement e = xml.scopedElement( elementName );
-
- xml.writeAttribute( "message", result.getExpandedExpression() );
- xml.writeAttribute( "type", result.getTestMacroName() );
-
- std::ostringstream oss;
- if( !result.getMessage().empty() )
- oss << result.getMessage() << '\n';
- for( std::vector<MessageInfo>::const_iterator
- it = stats.infoMessages.begin(),
- itEnd = stats.infoMessages.end();
- it != itEnd;
- ++it )
- if( it->type == ResultWas::Info )
- oss << it->message << '\n';
-
- oss << "at " << result.getSourceInfo();
- xml.writeText( oss.str(), false );
- }
- }
-
- XmlWriter xml;
- Timer suiteTimer;
- std::ostringstream stdOutForSuite;
- std::ostringstream stdErrForSuite;
- unsigned int unexpectedExceptions;
- };
-
- INTERNAL_CATCH_REGISTER_REPORTER( "junit", JunitReporter )
-
-} // end namespace Catch
-
-// #included from: ../reporters/catch_reporter_console.hpp
-#define TWOBLUECUBES_CATCH_REPORTER_CONSOLE_HPP_INCLUDED
-
-namespace Catch {
-
- struct ConsoleReporter : StreamingReporterBase {
- ConsoleReporter( ReporterConfig const& _config )
- : StreamingReporterBase( _config ),
- m_headerPrinted( false )
- {}
-
- virtual ~ConsoleReporter() CATCH_OVERRIDE;
- static std::string getDescription() {
- return "Reports test results as plain lines of text";
- }
-
- virtual void noMatchingTestCases( std::string const& spec ) CATCH_OVERRIDE {
- stream << "No test cases matched '" << spec << '\'' << std::endl;
- }
-
- virtual void assertionStarting( AssertionInfo const& ) CATCH_OVERRIDE {
- }
-
- virtual bool assertionEnded( AssertionStats const& _assertionStats ) CATCH_OVERRIDE {
- AssertionResult const& result = _assertionStats.assertionResult;
-
- bool printInfoMessages = true;
-
- // Drop out if result was successful and we're not printing those
- if( !m_config->includeSuccessfulResults() && result.isOk() ) {
- if( result.getResultType() != ResultWas::Warning )
- return false;
- printInfoMessages = false;
- }
-
- lazyPrint();
-
- AssertionPrinter printer( stream, _assertionStats, printInfoMessages );
- printer.print();
- stream << std::endl;
- return true;
- }
-
- virtual void sectionStarting( SectionInfo const& _sectionInfo ) CATCH_OVERRIDE {
- m_headerPrinted = false;
- StreamingReporterBase::sectionStarting( _sectionInfo );
- }
- virtual void sectionEnded( SectionStats const& _sectionStats ) CATCH_OVERRIDE {
- if( _sectionStats.missingAssertions ) {
- lazyPrint();
- Colour colour( Colour::ResultError );
- if( m_sectionStack.size() > 1 )
- stream << "\nNo assertions in section";
- else
- stream << "\nNo assertions in test case";
- stream << " '" << _sectionStats.sectionInfo.name << "'\n" << std::endl;
- }
- if( m_headerPrinted ) {
- if( m_config->showDurations() == ShowDurations::Always )
- stream << "Completed in " << _sectionStats.durationInSeconds << 's' << std::endl;
- m_headerPrinted = false;
- }
- else {
- if( m_config->showDurations() == ShowDurations::Always )
- stream << _sectionStats.sectionInfo.name << " completed in " << _sectionStats.durationInSeconds << 's' << std::endl;
- }
- StreamingReporterBase::sectionEnded( _sectionStats );
- }
-
- virtual void testCaseEnded( TestCaseStats const& _testCaseStats ) CATCH_OVERRIDE {
- StreamingReporterBase::testCaseEnded( _testCaseStats );
- m_headerPrinted = false;
- }
- virtual void testGroupEnded( TestGroupStats const& _testGroupStats ) CATCH_OVERRIDE {
- if( currentGroupInfo.used ) {
- printSummaryDivider();
- stream << "Summary for group '" << _testGroupStats.groupInfo.name << "':\n";
- printTotals( _testGroupStats.totals );
- stream << '\n' << std::endl;
- }
- StreamingReporterBase::testGroupEnded( _testGroupStats );
- }
- virtual void testRunEnded( TestRunStats const& _testRunStats ) CATCH_OVERRIDE {
- printTotalsDivider( _testRunStats.totals );
- printTotals( _testRunStats.totals );
- stream << std::endl;
- StreamingReporterBase::testRunEnded( _testRunStats );
- }
-
- private:
-
- class AssertionPrinter {
- void operator= ( AssertionPrinter const& );
- public:
- AssertionPrinter( std::ostream& _stream, AssertionStats const& _stats, bool _printInfoMessages )
- : stream( _stream ),
- stats( _stats ),
- result( _stats.assertionResult ),
- colour( Colour::None ),
- message( result.getMessage() ),
- messages( _stats.infoMessages ),
- printInfoMessages( _printInfoMessages )
- {
- switch( result.getResultType() ) {
- case ResultWas::Ok:
- colour = Colour::Success;
- passOrFail = "PASSED";
- //if( result.hasMessage() )
- if( _stats.infoMessages.size() == 1 )
- messageLabel = "with message";
- if( _stats.infoMessages.size() > 1 )
- messageLabel = "with messages";
- break;
- case ResultWas::ExpressionFailed:
- if( result.isOk() ) {
- colour = Colour::Success;
- passOrFail = "FAILED - but was ok";
- }
- else {
- colour = Colour::Error;
- passOrFail = "FAILED";
- }
- if( _stats.infoMessages.size() == 1 )
- messageLabel = "with message";
- if( _stats.infoMessages.size() > 1 )
- messageLabel = "with messages";
- break;
- case ResultWas::ThrewException:
- colour = Colour::Error;
- passOrFail = "FAILED";
- messageLabel = "due to unexpected exception with message";
- break;
- case ResultWas::FatalErrorCondition:
- colour = Colour::Error;
- passOrFail = "FAILED";
- messageLabel = "due to a fatal error condition";
- break;
- case ResultWas::DidntThrowException:
- colour = Colour::Error;
- passOrFail = "FAILED";
- messageLabel = "because no exception was thrown where one was expected";
- break;
- case ResultWas::Info:
- messageLabel = "info";
- break;
- case ResultWas::Warning:
- messageLabel = "warning";
- break;
- case ResultWas::ExplicitFailure:
- passOrFail = "FAILED";
- colour = Colour::Error;
- if( _stats.infoMessages.size() == 1 )
- messageLabel = "explicitly with message";
- if( _stats.infoMessages.size() > 1 )
- messageLabel = "explicitly with messages";
- break;
- // These cases are here to prevent compiler warnings
- case ResultWas::Unknown:
- case ResultWas::FailureBit:
- case ResultWas::Exception:
- passOrFail = "** internal error **";
- colour = Colour::Error;
- break;
- }
- }
-
- void print() const {
- printSourceInfo();
- if( stats.totals.assertions.total() > 0 ) {
- if( result.isOk() )
- stream << '\n';
- printResultType();
- printOriginalExpression();
- printReconstructedExpression();
- }
- else {
- stream << '\n';
- }
- printMessage();
- }
-
- private:
- void printResultType() const {
- if( !passOrFail.empty() ) {
- Colour colourGuard( colour );
- stream << passOrFail << ":\n";
- }
- }
- void printOriginalExpression() const {
- if( result.hasExpression() ) {
- Colour colourGuard( Colour::OriginalExpression );
- stream << " ";
- stream << result.getExpressionInMacro();
- stream << '\n';
- }
- }
- void printReconstructedExpression() const {
- if( result.hasExpandedExpression() ) {
- stream << "with expansion:\n";
- Colour colourGuard( Colour::ReconstructedExpression );
- stream << Text( result.getExpandedExpression(), TextAttributes().setIndent(2) ) << '\n';
- }
- }
- void printMessage() const {
- if( !messageLabel.empty() )
- stream << messageLabel << ':' << '\n';
- for( std::vector<MessageInfo>::const_iterator it = messages.begin(), itEnd = messages.end();
- it != itEnd;
- ++it ) {
- // If this assertion is a warning ignore any INFO messages
- if( printInfoMessages || it->type != ResultWas::Info )
- stream << Text( it->message, TextAttributes().setIndent(2) ) << '\n';
- }
- }
- void printSourceInfo() const {
- Colour colourGuard( Colour::FileName );
- stream << result.getSourceInfo() << ": ";
- }
-
- std::ostream& stream;
- AssertionStats const& stats;
- AssertionResult const& result;
- Colour::Code colour;
- std::string passOrFail;
- std::string messageLabel;
- std::string message;
- std::vector<MessageInfo> messages;
- bool printInfoMessages;
- };
-
- void lazyPrint() {
-
- if( !currentTestRunInfo.used )
- lazyPrintRunInfo();
- if( !currentGroupInfo.used )
- lazyPrintGroupInfo();
-
- if( !m_headerPrinted ) {
- printTestCaseAndSectionHeader();
- m_headerPrinted = true;
- }
- }
- void lazyPrintRunInfo() {
- stream << '\n' << getLineOfChars<'~'>() << '\n';
- Colour colour( Colour::SecondaryText );
- stream << currentTestRunInfo->name
- << " is a Catch v" << libraryVersion << " host application.\n"
- << "Run with -? for options\n\n";
-
- if( m_config->rngSeed() != 0 )
- stream << "Randomness seeded to: " << m_config->rngSeed() << "\n\n";
-
- currentTestRunInfo.used = true;
- }
- void lazyPrintGroupInfo() {
- if( !currentGroupInfo->name.empty() && currentGroupInfo->groupsCounts > 1 ) {
- printClosedHeader( "Group: " + currentGroupInfo->name );
- currentGroupInfo.used = true;
- }
- }
- void printTestCaseAndSectionHeader() {
- assert( !m_sectionStack.empty() );
- printOpenHeader( currentTestCaseInfo->name );
-
- if( m_sectionStack.size() > 1 ) {
- Colour colourGuard( Colour::Headers );
-
- std::vector<SectionInfo>::const_iterator
- it = m_sectionStack.begin()+1, // Skip first section (test case)
- itEnd = m_sectionStack.end();
- for( ; it != itEnd; ++it )
- printHeaderString( it->name, 2 );
- }
-
- SourceLineInfo lineInfo = m_sectionStack.back().lineInfo;
-
- if( !lineInfo.empty() ){
- stream << getLineOfChars<'-'>() << '\n';
- Colour colourGuard( Colour::FileName );
- stream << lineInfo << '\n';
- }
- stream << getLineOfChars<'.'>() << '\n' << std::endl;
- }
-
- void printClosedHeader( std::string const& _name ) {
- printOpenHeader( _name );
- stream << getLineOfChars<'.'>() << '\n';
- }
- void printOpenHeader( std::string const& _name ) {
- stream << getLineOfChars<'-'>() << '\n';
- {
- Colour colourGuard( Colour::Headers );
- printHeaderString( _name );
- }
- }
-
- // if string has a : in first line will set indent to follow it on
- // subsequent lines
- void printHeaderString( std::string const& _string, std::size_t indent = 0 ) {
- std::size_t i = _string.find( ": " );
- if( i != std::string::npos )
- i+=2;
- else
- i = 0;
- stream << Text( _string, TextAttributes()
- .setIndent( indent+i)
- .setInitialIndent( indent ) ) << '\n';
- }
-
- struct SummaryColumn {
-
- SummaryColumn( std::string const& _label, Colour::Code _colour )
- : label( _label ),
- colour( _colour )
- {}
- SummaryColumn addRow( std::size_t count ) {
- std::ostringstream oss;
- oss << count;
- std::string row = oss.str();
- for( std::vector<std::string>::iterator it = rows.begin(); it != rows.end(); ++it ) {
- while( it->size() < row.size() )
- *it = ' ' + *it;
- while( it->size() > row.size() )
- row = ' ' + row;
- }
- rows.push_back( row );
- return *this;
- }
-
- std::string label;
- Colour::Code colour;
- std::vector<std::string> rows;
-
- };
-
- void printTotals( Totals const& totals ) {
- if( totals.testCases.total() == 0 ) {
- stream << Colour( Colour::Warning ) << "No tests ran\n";
- }
- else if( totals.assertions.total() > 0 && totals.testCases.allPassed() ) {
- stream << Colour( Colour::ResultSuccess ) << "All tests passed";
- stream << " ("
- << pluralise( totals.assertions.passed, "assertion" ) << " in "
- << pluralise( totals.testCases.passed, "test case" ) << ')'
- << '\n';
- }
- else {
-
- std::vector<SummaryColumn> columns;
- columns.push_back( SummaryColumn( "", Colour::None )
- .addRow( totals.testCases.total() )
- .addRow( totals.assertions.total() ) );
- columns.push_back( SummaryColumn( "passed", Colour::Success )
- .addRow( totals.testCases.passed )
- .addRow( totals.assertions.passed ) );
- columns.push_back( SummaryColumn( "failed", Colour::ResultError )
- .addRow( totals.testCases.failed )
- .addRow( totals.assertions.failed ) );
- columns.push_back( SummaryColumn( "failed as expected", Colour::ResultExpectedFailure )
- .addRow( totals.testCases.failedButOk )
- .addRow( totals.assertions.failedButOk ) );
-
- printSummaryRow( "test cases", columns, 0 );
- printSummaryRow( "assertions", columns, 1 );
- }
- }
- void printSummaryRow( std::string const& label, std::vector<SummaryColumn> const& cols, std::size_t row ) {
- for( std::vector<SummaryColumn>::const_iterator it = cols.begin(); it != cols.end(); ++it ) {
- std::string value = it->rows[row];
- if( it->label.empty() ) {
- stream << label << ": ";
- if( value != "0" )
- stream << value;
- else
- stream << Colour( Colour::Warning ) << "- none -";
- }
- else if( value != "0" ) {
- stream << Colour( Colour::LightGrey ) << " | ";
- stream << Colour( it->colour )
- << value << ' ' << it->label;
- }
- }
- stream << '\n';
- }
-
- static std::size_t makeRatio( std::size_t number, std::size_t total ) {
- std::size_t ratio = total > 0 ? CATCH_CONFIG_CONSOLE_WIDTH * number/ total : 0;
- return ( ratio == 0 && number > 0 ) ? 1 : ratio;
- }
- static std::size_t& findMax( std::size_t& i, std::size_t& j, std::size_t& k ) {
- if( i > j && i > k )
- return i;
- else if( j > k )
- return j;
- else
- return k;
- }
-
- void printTotalsDivider( Totals const& totals ) {
- if( totals.testCases.total() > 0 ) {
- std::size_t failedRatio = makeRatio( totals.testCases.failed, totals.testCases.total() );
- std::size_t failedButOkRatio = makeRatio( totals.testCases.failedButOk, totals.testCases.total() );
- std::size_t passedRatio = makeRatio( totals.testCases.passed, totals.testCases.total() );
- while( failedRatio + failedButOkRatio + passedRatio < CATCH_CONFIG_CONSOLE_WIDTH-1 )
- findMax( failedRatio, failedButOkRatio, passedRatio )++;
- while( failedRatio + failedButOkRatio + passedRatio > CATCH_CONFIG_CONSOLE_WIDTH-1 )
- findMax( failedRatio, failedButOkRatio, passedRatio )--;
-
- stream << Colour( Colour::Error ) << std::string( failedRatio, '=' );
- stream << Colour( Colour::ResultExpectedFailure ) << std::string( failedButOkRatio, '=' );
- if( totals.testCases.allPassed() )
- stream << Colour( Colour::ResultSuccess ) << std::string( passedRatio, '=' );
- else
- stream << Colour( Colour::Success ) << std::string( passedRatio, '=' );
- }
- else {
- stream << Colour( Colour::Warning ) << std::string( CATCH_CONFIG_CONSOLE_WIDTH-1, '=' );
- }
- stream << '\n';
- }
- void printSummaryDivider() {
- stream << getLineOfChars<'-'>() << '\n';
- }
-
- private:
- bool m_headerPrinted;
- };
-
- INTERNAL_CATCH_REGISTER_REPORTER( "console", ConsoleReporter )
-
-} // end namespace Catch
-
-// #included from: ../reporters/catch_reporter_compact.hpp
-#define TWOBLUECUBES_CATCH_REPORTER_COMPACT_HPP_INCLUDED
-
-namespace Catch {
-
- struct CompactReporter : StreamingReporterBase {
-
- CompactReporter( ReporterConfig const& _config )
- : StreamingReporterBase( _config )
- {}
-
- virtual ~CompactReporter();
-
- static std::string getDescription() {
- return "Reports test results on a single line, suitable for IDEs";
- }
-
- virtual ReporterPreferences getPreferences() const {
- ReporterPreferences prefs;
- prefs.shouldRedirectStdOut = false;
- return prefs;
- }
-
- virtual void noMatchingTestCases( std::string const& spec ) {
- stream << "No test cases matched '" << spec << '\'' << std::endl;
- }
-
- virtual void assertionStarting( AssertionInfo const& ) {
- }
-
- virtual bool assertionEnded( AssertionStats const& _assertionStats ) {
- AssertionResult const& result = _assertionStats.assertionResult;
-
- bool printInfoMessages = true;
-
- // Drop out if result was successful and we're not printing those
- if( !m_config->includeSuccessfulResults() && result.isOk() ) {
- if( result.getResultType() != ResultWas::Warning )
- return false;
- printInfoMessages = false;
- }
-
- AssertionPrinter printer( stream, _assertionStats, printInfoMessages );
- printer.print();
-
- stream << std::endl;
- return true;
- }
-
- virtual void testRunEnded( TestRunStats const& _testRunStats ) {
- printTotals( _testRunStats.totals );
- stream << '\n' << std::endl;
- StreamingReporterBase::testRunEnded( _testRunStats );
- }
-
- private:
- class AssertionPrinter {
- void operator= ( AssertionPrinter const& );
- public:
- AssertionPrinter( std::ostream& _stream, AssertionStats const& _stats, bool _printInfoMessages )
- : stream( _stream )
- , stats( _stats )
- , result( _stats.assertionResult )
- , messages( _stats.infoMessages )
- , itMessage( _stats.infoMessages.begin() )
- , printInfoMessages( _printInfoMessages )
- {}
-
- void print() {
- printSourceInfo();
-
- itMessage = messages.begin();
-
- switch( result.getResultType() ) {
- case ResultWas::Ok:
- printResultType( Colour::ResultSuccess, passedString() );
- printOriginalExpression();
- printReconstructedExpression();
- if ( ! result.hasExpression() )
- printRemainingMessages( Colour::None );
- else
- printRemainingMessages();
- break;
- case ResultWas::ExpressionFailed:
- if( result.isOk() )
- printResultType( Colour::ResultSuccess, failedString() + std::string( " - but was ok" ) );
- else
- printResultType( Colour::Error, failedString() );
- printOriginalExpression();
- printReconstructedExpression();
- printRemainingMessages();
- break;
- case ResultWas::ThrewException:
- printResultType( Colour::Error, failedString() );
- printIssue( "unexpected exception with message:" );
- printMessage();
- printExpressionWas();
- printRemainingMessages();
- break;
- case ResultWas::FatalErrorCondition:
- printResultType( Colour::Error, failedString() );
- printIssue( "fatal error condition with message:" );
- printMessage();
- printExpressionWas();
- printRemainingMessages();
- break;
- case ResultWas::DidntThrowException:
- printResultType( Colour::Error, failedString() );
- printIssue( "expected exception, got none" );
- printExpressionWas();
- printRemainingMessages();
- break;
- case ResultWas::Info:
- printResultType( Colour::None, "info" );
- printMessage();
- printRemainingMessages();
- break;
- case ResultWas::Warning:
- printResultType( Colour::None, "warning" );
- printMessage();
- printRemainingMessages();
- break;
- case ResultWas::ExplicitFailure:
- printResultType( Colour::Error, failedString() );
- printIssue( "explicitly" );
- printRemainingMessages( Colour::None );
- break;
- // These cases are here to prevent compiler warnings
- case ResultWas::Unknown:
- case ResultWas::FailureBit:
- case ResultWas::Exception:
- printResultType( Colour::Error, "** internal error **" );
- break;
- }
- }
-
- private:
- // Colour::LightGrey
-
- static Colour::Code dimColour() { return Colour::FileName; }
-
-#ifdef CATCH_PLATFORM_MAC
- static const char* failedString() { return "FAILED"; }
- static const char* passedString() { return "PASSED"; }
-#else
- static const char* failedString() { return "failed"; }
- static const char* passedString() { return "passed"; }
-#endif
-
- void printSourceInfo() const {
- Colour colourGuard( Colour::FileName );
- stream << result.getSourceInfo() << ':';
- }
-
- void printResultType( Colour::Code colour, std::string passOrFail ) const {
- if( !passOrFail.empty() ) {
- {
- Colour colourGuard( colour );
- stream << ' ' << passOrFail;
- }
- stream << ':';
- }
- }
-
- void printIssue( std::string issue ) const {
- stream << ' ' << issue;
- }
-
- void printExpressionWas() {
- if( result.hasExpression() ) {
- stream << ';';
- {
- Colour colour( dimColour() );
- stream << " expression was:";
- }
- printOriginalExpression();
- }
- }
-
- void printOriginalExpression() const {
- if( result.hasExpression() ) {
- stream << ' ' << result.getExpression();
- }
- }
-
- void printReconstructedExpression() const {
- if( result.hasExpandedExpression() ) {
- {
- Colour colour( dimColour() );
- stream << " for: ";
- }
- stream << result.getExpandedExpression();
- }
- }
-
- void printMessage() {
- if ( itMessage != messages.end() ) {
- stream << " '" << itMessage->message << '\'';
- ++itMessage;
- }
- }
-
- void printRemainingMessages( Colour::Code colour = dimColour() ) {
- if ( itMessage == messages.end() )
- return;
-
- // using messages.end() directly yields compilation error:
- std::vector<MessageInfo>::const_iterator itEnd = messages.end();
- const std::size_t N = static_cast<std::size_t>( std::distance( itMessage, itEnd ) );
-
- {
- Colour colourGuard( colour );
- stream << " with " << pluralise( N, "message" ) << ':';
- }
-
- for(; itMessage != itEnd; ) {
- // If this assertion is a warning ignore any INFO messages
- if( printInfoMessages || itMessage->type != ResultWas::Info ) {
- stream << " '" << itMessage->message << '\'';
- if ( ++itMessage != itEnd ) {
- Colour colourGuard( dimColour() );
- stream << " and";
- }
- }
- }
- }
-
- private:
- std::ostream& stream;
- AssertionStats const& stats;
- AssertionResult const& result;
- std::vector<MessageInfo> messages;
- std::vector<MessageInfo>::const_iterator itMessage;
- bool printInfoMessages;
- };
-
- // Colour, message variants:
- // - white: No tests ran.
- // - red: Failed [both/all] N test cases, failed [both/all] M assertions.
- // - white: Passed [both/all] N test cases (no assertions).
- // - red: Failed N tests cases, failed M assertions.
- // - green: Passed [both/all] N tests cases with M assertions.
-
- std::string bothOrAll( std::size_t count ) const {
- return count == 1 ? std::string() : count == 2 ? "both " : "all " ;
- }
-
- void printTotals( const Totals& totals ) const {
- if( totals.testCases.total() == 0 ) {
- stream << "No tests ran.";
- }
- else if( totals.testCases.failed == totals.testCases.total() ) {
- Colour colour( Colour::ResultError );
- const std::string qualify_assertions_failed =
- totals.assertions.failed == totals.assertions.total() ?
- bothOrAll( totals.assertions.failed ) : std::string();
- stream <<
- "Failed " << bothOrAll( totals.testCases.failed )
- << pluralise( totals.testCases.failed, "test case" ) << ", "
- "failed " << qualify_assertions_failed <<
- pluralise( totals.assertions.failed, "assertion" ) << '.';
- }
- else if( totals.assertions.total() == 0 ) {
- stream <<
- "Passed " << bothOrAll( totals.testCases.total() )
- << pluralise( totals.testCases.total(), "test case" )
- << " (no assertions).";
- }
- else if( totals.assertions.failed ) {
- Colour colour( Colour::ResultError );
- stream <<
- "Failed " << pluralise( totals.testCases.failed, "test case" ) << ", "
- "failed " << pluralise( totals.assertions.failed, "assertion" ) << '.';
- }
- else {
- Colour colour( Colour::ResultSuccess );
- stream <<
- "Passed " << bothOrAll( totals.testCases.passed )
- << pluralise( totals.testCases.passed, "test case" ) <<
- " with " << pluralise( totals.assertions.passed, "assertion" ) << '.';
- }
- }
- };
-
- INTERNAL_CATCH_REGISTER_REPORTER( "compact", CompactReporter )
-
-} // end namespace Catch
-
-namespace Catch {
- // These are all here to avoid warnings about not having any out of line
- // virtual methods
- NonCopyable::~NonCopyable() {}
- IShared::~IShared() {}
- IStream::~IStream() CATCH_NOEXCEPT {}
- FileStream::~FileStream() CATCH_NOEXCEPT {}
- CoutStream::~CoutStream() CATCH_NOEXCEPT {}
- DebugOutStream::~DebugOutStream() CATCH_NOEXCEPT {}
- StreamBufBase::~StreamBufBase() CATCH_NOEXCEPT {}
- IContext::~IContext() {}
- IResultCapture::~IResultCapture() {}
- ITestCase::~ITestCase() {}
- ITestCaseRegistry::~ITestCaseRegistry() {}
- IRegistryHub::~IRegistryHub() {}
- IMutableRegistryHub::~IMutableRegistryHub() {}
- IExceptionTranslator::~IExceptionTranslator() {}
- IExceptionTranslatorRegistry::~IExceptionTranslatorRegistry() {}
- IReporter::~IReporter() {}
- IReporterFactory::~IReporterFactory() {}
- IReporterRegistry::~IReporterRegistry() {}
- IStreamingReporter::~IStreamingReporter() {}
- AssertionStats::~AssertionStats() {}
- SectionStats::~SectionStats() {}
- TestCaseStats::~TestCaseStats() {}
- TestGroupStats::~TestGroupStats() {}
- TestRunStats::~TestRunStats() {}
- CumulativeReporterBase::SectionNode::~SectionNode() {}
- CumulativeReporterBase::~CumulativeReporterBase() {}
-
- StreamingReporterBase::~StreamingReporterBase() {}
- ConsoleReporter::~ConsoleReporter() {}
- CompactReporter::~CompactReporter() {}
- IRunner::~IRunner() {}
- IMutableContext::~IMutableContext() {}
- IConfig::~IConfig() {}
- XmlReporter::~XmlReporter() {}
- JunitReporter::~JunitReporter() {}
- TestRegistry::~TestRegistry() {}
- FreeFunctionTestCase::~FreeFunctionTestCase() {}
- IGeneratorInfo::~IGeneratorInfo() {}
- IGeneratorsForTest::~IGeneratorsForTest() {}
- WildcardPattern::~WildcardPattern() {}
- TestSpec::Pattern::~Pattern() {}
- TestSpec::NamePattern::~NamePattern() {}
- TestSpec::TagPattern::~TagPattern() {}
- TestSpec::ExcludedPattern::~ExcludedPattern() {}
-
- Matchers::Impl::StdString::Equals::~Equals() {}
- Matchers::Impl::StdString::Contains::~Contains() {}
- Matchers::Impl::StdString::StartsWith::~StartsWith() {}
- Matchers::Impl::StdString::EndsWith::~EndsWith() {}
-
- void Config::dummy() {}
-
- namespace TestCaseTracking {
- ITracker::~ITracker() {}
- TrackerBase::~TrackerBase() {}
- SectionTracker::~SectionTracker() {}
- IndexTracker::~IndexTracker() {}
- }
-}
-
-#ifdef __clang__
-#pragma clang diagnostic pop
-#endif
-
-#endif
-
-#ifdef CATCH_CONFIG_MAIN
-// #included from: internal/catch_default_main.hpp
-#define TWOBLUECUBES_CATCH_DEFAULT_MAIN_HPP_INCLUDED
-
-#ifndef __OBJC__
-
-// Standard C/C++ main entry point
-int main (int argc, char * argv[]) {
- int result = Catch::Session().run( argc, argv );
- return ( result < 0xff ? result : 0xff );
-}
-
-#else // __OBJC__
-
-// Objective-C entry point
-int main (int argc, char * const argv[]) {
-#if !CATCH_ARC_ENABLED
- NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
-#endif
-
- Catch::registerTestMethods();
- int result = Catch::Session().run( argc, (char* const*)argv );
-
-#if !CATCH_ARC_ENABLED
- [pool drain];
-#endif
-
- return ( result < 0xff ? result : 0xff );
-}
-
-#endif // __OBJC__
-
-#endif
-
-#ifdef CLARA_CONFIG_MAIN_NOT_DEFINED
-# undef CLARA_CONFIG_MAIN
-#endif
-
-//////
-
-// If this config identifier is defined then all CATCH macros are prefixed with CATCH_
-#ifdef CATCH_CONFIG_PREFIX_ALL
-
-#define CATCH_REQUIRE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal, "CATCH_REQUIRE" )
-#define CATCH_REQUIRE_FALSE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, "CATCH_REQUIRE_FALSE" )
-
-#define CATCH_REQUIRE_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::Normal, "", "CATCH_REQUIRE_THROWS" )
-#define CATCH_REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::Normal, "CATCH_REQUIRE_THROWS_AS" )
-#define CATCH_REQUIRE_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::Normal, matcher, "CATCH_REQUIRE_THROWS_WITH" )
-#define CATCH_REQUIRE_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::Normal, "CATCH_REQUIRE_NOTHROW" )
-
-#define CATCH_CHECK( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK" )
-#define CATCH_CHECK_FALSE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, "CATCH_CHECK_FALSE" )
-#define CATCH_CHECKED_IF( expr ) INTERNAL_CATCH_IF( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECKED_IF" )
-#define CATCH_CHECKED_ELSE( expr ) INTERNAL_CATCH_ELSE( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECKED_ELSE" )
-#define CATCH_CHECK_NOFAIL( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, "CATCH_CHECK_NOFAIL" )
-
-#define CATCH_CHECK_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::ContinueOnFailure, "", "CATCH_CHECK_THROWS" )
-#define CATCH_CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_THROWS_AS" )
-#define CATCH_CHECK_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::ContinueOnFailure, matcher, "CATCH_CHECK_THROWS_WITH" )
-#define CATCH_CHECK_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_NOTHROW" )
-
-#define CATCH_CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_THAT" )
-#define CATCH_REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, Catch::ResultDisposition::Normal, "CATCH_REQUIRE_THAT" )
-
-#define CATCH_INFO( msg ) INTERNAL_CATCH_INFO( msg, "CATCH_INFO" )
-#define CATCH_WARN( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, "CATCH_WARN", msg )
-#define CATCH_SCOPED_INFO( msg ) INTERNAL_CATCH_INFO( msg, "CATCH_INFO" )
-#define CATCH_CAPTURE( msg ) INTERNAL_CATCH_INFO( #msg " := " << msg, "CATCH_CAPTURE" )
-#define CATCH_SCOPED_CAPTURE( msg ) INTERNAL_CATCH_INFO( #msg " := " << msg, "CATCH_CAPTURE" )
-
-#ifdef CATCH_CONFIG_VARIADIC_MACROS
- #define CATCH_TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ )
- #define CATCH_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ )
- #define CATCH_METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ )
- #define CATCH_REGISTER_TEST_CASE( Function, ... ) INTERNAL_CATCH_REGISTER_TESTCASE( Function, __VA_ARGS__ )
- #define CATCH_SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ )
- #define CATCH_FAIL( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "CATCH_FAIL", __VA_ARGS__ )
- #define CATCH_SUCCEED( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "CATCH_SUCCEED", __VA_ARGS__ )
-#else
- #define CATCH_TEST_CASE( name, description ) INTERNAL_CATCH_TESTCASE( name, description )
- #define CATCH_TEST_CASE_METHOD( className, name, description ) INTERNAL_CATCH_TEST_CASE_METHOD( className, name, description )
- #define CATCH_METHOD_AS_TEST_CASE( method, name, description ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, name, description )
- #define CATCH_REGISTER_TEST_CASE( function, name, description ) INTERNAL_CATCH_REGISTER_TESTCASE( function, name, description )
- #define CATCH_SECTION( name, description ) INTERNAL_CATCH_SECTION( name, description )
- #define CATCH_FAIL( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "CATCH_FAIL", msg )
- #define CATCH_SUCCEED( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "CATCH_SUCCEED", msg )
-#endif
-#define CATCH_ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE( "", "" )
-
-#define CATCH_REGISTER_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_REPORTER( name, reporterType )
-#define CATCH_REGISTER_LEGACY_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_LEGACY_REPORTER( name, reporterType )
-
-#define CATCH_GENERATE( expr) INTERNAL_CATCH_GENERATE( expr )
-
-// "BDD-style" convenience wrappers
-#ifdef CATCH_CONFIG_VARIADIC_MACROS
-#define CATCH_SCENARIO( ... ) CATCH_TEST_CASE( "Scenario: " __VA_ARGS__ )
-#define CATCH_SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " __VA_ARGS__ )
-#else
-#define CATCH_SCENARIO( name, tags ) CATCH_TEST_CASE( "Scenario: " name, tags )
-#define CATCH_SCENARIO_METHOD( className, name, tags ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " name, tags )
-#endif
-#define CATCH_GIVEN( desc ) CATCH_SECTION( std::string( "Given: ") + desc, "" )
-#define CATCH_WHEN( desc ) CATCH_SECTION( std::string( " When: ") + desc, "" )
-#define CATCH_AND_WHEN( desc ) CATCH_SECTION( std::string( " And: ") + desc, "" )
-#define CATCH_THEN( desc ) CATCH_SECTION( std::string( " Then: ") + desc, "" )
-#define CATCH_AND_THEN( desc ) CATCH_SECTION( std::string( " And: ") + desc, "" )
-
-// If CATCH_CONFIG_PREFIX_ALL is not defined then the CATCH_ prefix is not required
-#else
-
-#define REQUIRE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal, "REQUIRE" )
-#define REQUIRE_FALSE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, "REQUIRE_FALSE" )
-
-#define REQUIRE_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::Normal, "", "REQUIRE_THROWS" )
-#define REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::Normal, "REQUIRE_THROWS_AS" )
-#define REQUIRE_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::Normal, matcher, "REQUIRE_THROWS_WITH" )
-#define REQUIRE_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::Normal, "REQUIRE_NOTHROW" )
-
-#define CHECK( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECK" )
-#define CHECK_FALSE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, "CHECK_FALSE" )
-#define CHECKED_IF( expr ) INTERNAL_CATCH_IF( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECKED_IF" )
-#define CHECKED_ELSE( expr ) INTERNAL_CATCH_ELSE( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECKED_ELSE" )
-#define CHECK_NOFAIL( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, "CHECK_NOFAIL" )
-
-#define CHECK_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::ContinueOnFailure, "", "CHECK_THROWS" )
-#define CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::ContinueOnFailure, "CHECK_THROWS_AS" )
-#define CHECK_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::ContinueOnFailure, matcher, "CHECK_THROWS_WITH" )
-#define CHECK_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECK_NOTHROW" )
-
-#define CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, Catch::ResultDisposition::ContinueOnFailure, "CHECK_THAT" )
-#define REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, Catch::ResultDisposition::Normal, "REQUIRE_THAT" )
-
-#define INFO( msg ) INTERNAL_CATCH_INFO( msg, "INFO" )
-#define WARN( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, "WARN", msg )
-#define SCOPED_INFO( msg ) INTERNAL_CATCH_INFO( msg, "INFO" )
-#define CAPTURE( msg ) INTERNAL_CATCH_INFO( #msg " := " << msg, "CAPTURE" )
-#define SCOPED_CAPTURE( msg ) INTERNAL_CATCH_INFO( #msg " := " << msg, "CAPTURE" )
-
-#ifdef CATCH_CONFIG_VARIADIC_MACROS
- #define TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ )
- #define TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ )
- #define METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ )
- #define REGISTER_TEST_CASE( Function, ... ) INTERNAL_CATCH_REGISTER_TESTCASE( Function, __VA_ARGS__ )
- #define SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ )
- #define FAIL( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "FAIL", __VA_ARGS__ )
- #define SUCCEED( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "SUCCEED", __VA_ARGS__ )
-#else
- #define TEST_CASE( name, description ) INTERNAL_CATCH_TESTCASE( name, description )
- #define TEST_CASE_METHOD( className, name, description ) INTERNAL_CATCH_TEST_CASE_METHOD( className, name, description )
- #define METHOD_AS_TEST_CASE( method, name, description ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, name, description )
- #define REGISTER_TEST_CASE( method, name, description ) INTERNAL_CATCH_REGISTER_TESTCASE( method, name, description )
- #define SECTION( name, description ) INTERNAL_CATCH_SECTION( name, description )
- #define FAIL( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "FAIL", msg )
- #define SUCCEED( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "SUCCEED", msg )
-#endif
-#define ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE( "", "" )
-
-#define REGISTER_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_REPORTER( name, reporterType )
-#define REGISTER_LEGACY_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_LEGACY_REPORTER( name, reporterType )
-
-#define GENERATE( expr) INTERNAL_CATCH_GENERATE( expr )
-
-#endif
-
-#define CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature )
-
-// "BDD-style" convenience wrappers
-#ifdef CATCH_CONFIG_VARIADIC_MACROS
-#define SCENARIO( ... ) TEST_CASE( "Scenario: " __VA_ARGS__ )
-#define SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " __VA_ARGS__ )
-#else
-#define SCENARIO( name, tags ) TEST_CASE( "Scenario: " name, tags )
-#define SCENARIO_METHOD( className, name, tags ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " name, tags )
-#endif
-#define GIVEN( desc ) SECTION( std::string(" Given: ") + desc, "" )
-#define WHEN( desc ) SECTION( std::string(" When: ") + desc, "" )
-#define AND_WHEN( desc ) SECTION( std::string("And when: ") + desc, "" )
-#define THEN( desc ) SECTION( std::string(" Then: ") + desc, "" )
-#define AND_THEN( desc ) SECTION( std::string(" And: ") + desc, "" )
-
-using Catch::Detail::Approx;
-
-#endif // TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED
-
diff --git a/3rdparty/bx/3rdparty/catch/catch_amalgamated.cpp b/3rdparty/bx/3rdparty/catch/catch_amalgamated.cpp
new file mode 100644
index 00000000000..ecda2301b3a
--- /dev/null
+++ b/3rdparty/bx/3rdparty/catch/catch_amalgamated.cpp
@@ -0,0 +1,10360 @@
+// Copyright Catch2 Authors
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at
+// https://www.boost.org/LICENSE_1_0.txt)
+
+// SPDX-License-Identifier: BSL-1.0
+
+// Catch v3.1.0
+// Generated: 2022-07-17 20:14:05.885021
+// ----------------------------------------------------------
+// This file is an amalgamation of multiple different files.
+// You probably shouldn't edit it directly.
+// ----------------------------------------------------------
+
+#include "catch_amalgamated.hpp"
+
+
+
+
+namespace Catch {
+ namespace Benchmark {
+ namespace Detail {
+ ChronometerConcept::~ChronometerConcept() = default;
+ } // namespace Detail
+ } // namespace Benchmark
+} // namespace Catch
+
+
+
+
+namespace Catch {
+ namespace Benchmark {
+ namespace Detail {
+ BenchmarkFunction::callable::~callable() = default;
+ } // namespace Detail
+ } // namespace Benchmark
+} // namespace Catch
+
+
+
+#include <exception>
+
+namespace Catch {
+ namespace Benchmark {
+ namespace Detail {
+ struct optimized_away_error : std::exception {
+ const char* what() const noexcept override;
+ };
+
+ const char* optimized_away_error::what() const noexcept {
+ return "could not measure benchmark, maybe it was optimized away";
+ }
+
+ void throw_optimized_away_error() {
+ Catch::throw_exception(optimized_away_error{});
+ }
+
+ } // namespace Detail
+ } // namespace Benchmark
+} // namespace Catch
+
+
+// Adapted from donated nonius code.
+
+
+
+#include <cassert>
+#include <cstddef>
+#include <iterator>
+#include <random>
+
+
+#if defined(CATCH_CONFIG_USE_ASYNC)
+#include <future>
+#endif
+
+namespace {
+
+using Catch::Benchmark::Detail::sample;
+
+ template <typename URng, typename Estimator>
+ sample resample(URng& rng, unsigned int resamples, std::vector<double>::iterator first, std::vector<double>::iterator last, Estimator& estimator) {
+ auto n = static_cast<size_t>(last - first);
+ std::uniform_int_distribution<decltype(n)> dist(0, n - 1);
+
+ sample out;
+ out.reserve(resamples);
+ std::generate_n(std::back_inserter(out), resamples, [n, first, &estimator, &dist, &rng] {
+ std::vector<double> resampled;
+ resampled.reserve(n);
+ std::generate_n(std::back_inserter(resampled), n, [first, &dist, &rng] { return first[static_cast<std::ptrdiff_t>(dist(rng))]; });
+ return estimator(resampled.begin(), resampled.end());
+ });
+ std::sort(out.begin(), out.end());
+ return out;
+ }
+
+
+ double erf_inv(double x) {
+ // Code accompanying the article "Approximating the erfinv function" in GPU Computing Gems, Volume 2
+ double w, p;
+
+ w = -log((1.0 - x) * (1.0 + x));
+
+ if (w < 6.250000) {
+ w = w - 3.125000;
+ p = -3.6444120640178196996e-21;
+ p = -1.685059138182016589e-19 + p * w;
+ p = 1.2858480715256400167e-18 + p * w;
+ p = 1.115787767802518096e-17 + p * w;
+ p = -1.333171662854620906e-16 + p * w;
+ p = 2.0972767875968561637e-17 + p * w;
+ p = 6.6376381343583238325e-15 + p * w;
+ p = -4.0545662729752068639e-14 + p * w;
+ p = -8.1519341976054721522e-14 + p * w;
+ p = 2.6335093153082322977e-12 + p * w;
+ p = -1.2975133253453532498e-11 + p * w;
+ p = -5.4154120542946279317e-11 + p * w;
+ p = 1.051212273321532285e-09 + p * w;
+ p = -4.1126339803469836976e-09 + p * w;
+ p = -2.9070369957882005086e-08 + p * w;
+ p = 4.2347877827932403518e-07 + p * w;
+ p = -1.3654692000834678645e-06 + p * w;
+ p = -1.3882523362786468719e-05 + p * w;
+ p = 0.0001867342080340571352 + p * w;
+ p = -0.00074070253416626697512 + p * w;
+ p = -0.0060336708714301490533 + p * w;
+ p = 0.24015818242558961693 + p * w;
+ p = 1.6536545626831027356 + p * w;
+ } else if (w < 16.000000) {
+ w = sqrt(w) - 3.250000;
+ p = 2.2137376921775787049e-09;
+ p = 9.0756561938885390979e-08 + p * w;
+ p = -2.7517406297064545428e-07 + p * w;
+ p = 1.8239629214389227755e-08 + p * w;
+ p = 1.5027403968909827627e-06 + p * w;
+ p = -4.013867526981545969e-06 + p * w;
+ p = 2.9234449089955446044e-06 + p * w;
+ p = 1.2475304481671778723e-05 + p * w;
+ p = -4.7318229009055733981e-05 + p * w;
+ p = 6.8284851459573175448e-05 + p * w;
+ p = 2.4031110387097893999e-05 + p * w;
+ p = -0.0003550375203628474796 + p * w;
+ p = 0.00095328937973738049703 + p * w;
+ p = -0.0016882755560235047313 + p * w;
+ p = 0.0024914420961078508066 + p * w;
+ p = -0.0037512085075692412107 + p * w;
+ p = 0.005370914553590063617 + p * w;
+ p = 1.0052589676941592334 + p * w;
+ p = 3.0838856104922207635 + p * w;
+ } else {
+ w = sqrt(w) - 5.000000;
+ p = -2.7109920616438573243e-11;
+ p = -2.5556418169965252055e-10 + p * w;
+ p = 1.5076572693500548083e-09 + p * w;
+ p = -3.7894654401267369937e-09 + p * w;
+ p = 7.6157012080783393804e-09 + p * w;
+ p = -1.4960026627149240478e-08 + p * w;
+ p = 2.9147953450901080826e-08 + p * w;
+ p = -6.7711997758452339498e-08 + p * w;
+ p = 2.2900482228026654717e-07 + p * w;
+ p = -9.9298272942317002539e-07 + p * w;
+ p = 4.5260625972231537039e-06 + p * w;
+ p = -1.9681778105531670567e-05 + p * w;
+ p = 7.5995277030017761139e-05 + p * w;
+ p = -0.00021503011930044477347 + p * w;
+ p = -0.00013871931833623122026 + p * w;
+ p = 1.0103004648645343977 + p * w;
+ p = 4.8499064014085844221 + p * w;
+ }
+ return p * x;
+ }
+
+ double standard_deviation(std::vector<double>::iterator first, std::vector<double>::iterator last) {
+ auto m = Catch::Benchmark::Detail::mean(first, last);
+ double variance = std::accumulate( first,
+ last,
+ 0.,
+ [m]( double a, double b ) {
+ double diff = b - m;
+ return a + diff * diff;
+ } ) /
+ ( last - first );
+ return std::sqrt( variance );
+ }
+
+}
+
+namespace Catch {
+ namespace Benchmark {
+ namespace Detail {
+
+#if defined( __GNUC__ ) || defined( __clang__ )
+# pragma GCC diagnostic push
+# pragma GCC diagnostic ignored "-Wfloat-equal"
+#endif
+ bool directCompare( double lhs, double rhs ) { return lhs == rhs; }
+#if defined( __GNUC__ ) || defined( __clang__ )
+# pragma GCC diagnostic pop
+#endif
+
+ double weighted_average_quantile(int k, int q, std::vector<double>::iterator first, std::vector<double>::iterator last) {
+ auto count = last - first;
+ double idx = (count - 1) * k / static_cast<double>(q);
+ int j = static_cast<int>(idx);
+ double g = idx - j;
+ std::nth_element(first, first + j, last);
+ auto xj = first[j];
+ if ( directCompare( g, 0 ) ) {
+ return xj;
+ }
+
+ auto xj1 = *std::min_element(first + (j + 1), last);
+ return xj + g * (xj1 - xj);
+ }
+
+
+ double erfc_inv(double x) {
+ return erf_inv(1.0 - x);
+ }
+
+ double normal_quantile(double p) {
+ static const double ROOT_TWO = std::sqrt(2.0);
+
+ double result = 0.0;
+ assert(p >= 0 && p <= 1);
+ if (p < 0 || p > 1) {
+ return result;
+ }
+
+ result = -erfc_inv(2.0 * p);
+ // result *= normal distribution standard deviation (1.0) * sqrt(2)
+ result *= /*sd * */ ROOT_TWO;
+ // result += normal disttribution mean (0)
+ return result;
+ }
+
+
+ double outlier_variance(Estimate<double> mean, Estimate<double> stddev, int n) {
+ double sb = stddev.point;
+ double mn = mean.point / n;
+ double mg_min = mn / 2.;
+ double sg = (std::min)(mg_min / 4., sb / std::sqrt(n));
+ double sg2 = sg * sg;
+ double sb2 = sb * sb;
+
+ auto c_max = [n, mn, sb2, sg2](double x) -> double {
+ double k = mn - x;
+ double d = k * k;
+ double nd = n * d;
+ double k0 = -n * nd;
+ double k1 = sb2 - n * sg2 + nd;
+ double det = k1 * k1 - 4 * sg2 * k0;
+ return static_cast<int>(-2. * k0 / (k1 + std::sqrt(det)));
+ };
+
+ auto var_out = [n, sb2, sg2](double c) {
+ double nc = n - c;
+ return (nc / n) * (sb2 - nc * sg2);
+ };
+
+ return (std::min)(var_out(1), var_out((std::min)(c_max(0.), c_max(mg_min)))) / sb2;
+ }
+
+
+ bootstrap_analysis analyse_samples(double confidence_level, unsigned int n_resamples, std::vector<double>::iterator first, std::vector<double>::iterator last) {
+ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION
+ CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS
+ static std::random_device entropy;
+ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
+
+ auto n = static_cast<int>(last - first); // seriously, one can't use integral types without hell in C++
+
+ auto mean = &Detail::mean<std::vector<double>::iterator>;
+ auto stddev = &standard_deviation;
+
+#if defined(CATCH_CONFIG_USE_ASYNC)
+ auto Estimate = [=](double(*f)(std::vector<double>::iterator, std::vector<double>::iterator)) {
+ auto seed = entropy();
+ return std::async(std::launch::async, [=] {
+ std::mt19937 rng(seed);
+ auto resampled = resample(rng, n_resamples, first, last, f);
+ return bootstrap(confidence_level, first, last, resampled, f);
+ });
+ };
+
+ auto mean_future = Estimate(mean);
+ auto stddev_future = Estimate(stddev);
+
+ auto mean_estimate = mean_future.get();
+ auto stddev_estimate = stddev_future.get();
+#else
+ auto Estimate = [=](double(*f)(std::vector<double>::iterator, std::vector<double>::iterator)) {
+ auto seed = entropy();
+ std::mt19937 rng(seed);
+ auto resampled = resample(rng, n_resamples, first, last, f);
+ return bootstrap(confidence_level, first, last, resampled, f);
+ };
+
+ auto mean_estimate = Estimate(mean);
+ auto stddev_estimate = Estimate(stddev);
+#endif // CATCH_USE_ASYNC
+
+ double outlier_variance = Detail::outlier_variance(mean_estimate, stddev_estimate, n);
+
+ return { mean_estimate, stddev_estimate, outlier_variance };
+ }
+ } // namespace Detail
+ } // namespace Benchmark
+} // namespace Catch
+
+
+
+#include <cmath>
+#include <limits>
+
+namespace {
+
+// Performs equivalent check of std::fabs(lhs - rhs) <= margin
+// But without the subtraction to allow for INFINITY in comparison
+bool marginComparison(double lhs, double rhs, double margin) {
+ return (lhs + margin >= rhs) && (rhs + margin >= lhs);
+}
+
+}
+
+namespace Catch {
+
+ Approx::Approx ( double value )
+ : m_epsilon( std::numeric_limits<float>::epsilon()*100. ),
+ m_margin( 0.0 ),
+ m_scale( 0.0 ),
+ m_value( value )
+ {}
+
+ Approx Approx::custom() {
+ return Approx( 0 );
+ }
+
+ Approx Approx::operator-() const {
+ auto temp(*this);
+ temp.m_value = -temp.m_value;
+ return temp;
+ }
+
+
+ std::string Approx::toString() const {
+ ReusableStringStream rss;
+ rss << "Approx( " << ::Catch::Detail::stringify( m_value ) << " )";
+ return rss.str();
+ }
+
+ bool Approx::equalityComparisonImpl(const double other) const {
+ // First try with fixed margin, then compute margin based on epsilon, scale and Approx's value
+ // Thanks to Richard Harris for his help refining the scaled margin value
+ return marginComparison(m_value, other, m_margin)
+ || marginComparison(m_value, other, m_epsilon * (m_scale + std::fabs(std::isinf(m_value)? 0 : m_value)));
+ }
+
+ void Approx::setMargin(double newMargin) {
+ CATCH_ENFORCE(newMargin >= 0,
+ "Invalid Approx::margin: " << newMargin << '.'
+ << " Approx::Margin has to be non-negative.");
+ m_margin = newMargin;
+ }
+
+ void Approx::setEpsilon(double newEpsilon) {
+ CATCH_ENFORCE(newEpsilon >= 0 && newEpsilon <= 1.0,
+ "Invalid Approx::epsilon: " << newEpsilon << '.'
+ << " Approx::epsilon has to be in [0, 1]");
+ m_epsilon = newEpsilon;
+ }
+
+namespace literals {
+ Approx operator "" _a(long double val) {
+ return Approx(val);
+ }
+ Approx operator "" _a(unsigned long long val) {
+ return Approx(val);
+ }
+} // end namespace literals
+
+std::string StringMaker<Catch::Approx>::convert(Catch::Approx const& value) {
+ return value.toString();
+}
+
+} // end namespace Catch
+
+
+
+namespace Catch {
+
+ AssertionResultData::AssertionResultData(ResultWas::OfType _resultType, LazyExpression const & _lazyExpression):
+ lazyExpression(_lazyExpression),
+ resultType(_resultType) {}
+
+ std::string AssertionResultData::reconstructExpression() const {
+
+ if( reconstructedExpression.empty() ) {
+ if( lazyExpression ) {
+ ReusableStringStream rss;
+ rss << lazyExpression;
+ reconstructedExpression = rss.str();
+ }
+ }
+ return reconstructedExpression;
+ }
+
+ AssertionResult::AssertionResult( AssertionInfo const& info, AssertionResultData const& data )
+ : m_info( info ),
+ m_resultData( data )
+ {}
+
+ // Result was a success
+ bool AssertionResult::succeeded() const {
+ return Catch::isOk( m_resultData.resultType );
+ }
+
+ // Result was a success, or failure is suppressed
+ bool AssertionResult::isOk() const {
+ return Catch::isOk( m_resultData.resultType ) || shouldSuppressFailure( m_info.resultDisposition );
+ }
+
+ ResultWas::OfType AssertionResult::getResultType() const {
+ return m_resultData.resultType;
+ }
+
+ bool AssertionResult::hasExpression() const {
+ return !m_info.capturedExpression.empty();
+ }
+
+ bool AssertionResult::hasMessage() const {
+ return !m_resultData.message.empty();
+ }
+
+ std::string AssertionResult::getExpression() const {
+ // Possibly overallocating by 3 characters should be basically free
+ std::string expr; expr.reserve(m_info.capturedExpression.size() + 3);
+ if (isFalseTest(m_info.resultDisposition)) {
+ expr += "!(";
+ }
+ expr += m_info.capturedExpression;
+ if (isFalseTest(m_info.resultDisposition)) {
+ expr += ')';
+ }
+ return expr;
+ }
+
+ std::string AssertionResult::getExpressionInMacro() const {
+ std::string expr;
+ if( m_info.macroName.empty() )
+ expr = static_cast<std::string>(m_info.capturedExpression);
+ else {
+ expr.reserve( m_info.macroName.size() + m_info.capturedExpression.size() + 4 );
+ expr += m_info.macroName;
+ expr += "( ";
+ expr += m_info.capturedExpression;
+ expr += " )";
+ }
+ return expr;
+ }
+
+ bool AssertionResult::hasExpandedExpression() const {
+ return hasExpression() && getExpandedExpression() != getExpression();
+ }
+
+ std::string AssertionResult::getExpandedExpression() const {
+ std::string expr = m_resultData.reconstructExpression();
+ return expr.empty()
+ ? getExpression()
+ : expr;
+ }
+
+ StringRef AssertionResult::getMessage() const {
+ return m_resultData.message;
+ }
+ SourceLineInfo AssertionResult::getSourceInfo() const {
+ return m_info.lineInfo;
+ }
+
+ StringRef AssertionResult::getTestMacroName() const {
+ return m_info.macroName;
+ }
+
+} // end namespace Catch
+
+
+
+namespace {
+ bool provideBazelReporterOutput() {
+#ifdef CATCH_CONFIG_BAZEL_SUPPORT
+ return true;
+#else
+
+# if defined( _MSC_VER )
+ // On Windows getenv throws a warning as there is no input validation,
+ // since the switch is hardcoded, this should not be an issue.
+# pragma warning( push )
+# pragma warning( disable : 4996 )
+# endif
+
+ return std::getenv( "BAZEL_TEST" ) != nullptr;
+
+# if defined( _MSC_VER )
+# pragma warning( pop )
+# endif
+#endif
+ }
+}
+
+namespace Catch {
+
+ bool operator==( ProcessedReporterSpec const& lhs,
+ ProcessedReporterSpec const& rhs ) {
+ return lhs.name == rhs.name &&
+ lhs.outputFilename == rhs.outputFilename &&
+ lhs.colourMode == rhs.colourMode &&
+ lhs.customOptions == rhs.customOptions;
+ }
+
+ Config::Config( ConfigData const& data ):
+ m_data( data ) {
+ // We need to trim filter specs to avoid trouble with superfluous
+ // whitespace (esp. important for bdd macros, as those are manually
+ // aligned with whitespace).
+
+ for (auto& elem : m_data.testsOrTags) {
+ elem = trim(elem);
+ }
+ for (auto& elem : m_data.sectionsToRun) {
+ elem = trim(elem);
+ }
+
+
+ TestSpecParser parser(ITagAliasRegistry::get());
+ if (!m_data.testsOrTags.empty()) {
+ m_hasTestFilters = true;
+ for (auto const& testOrTags : m_data.testsOrTags) {
+ parser.parse(testOrTags);
+ }
+ }
+ m_testSpec = parser.testSpec();
+
+
+ // Insert the default reporter if user hasn't asked for a specfic one
+ if ( m_data.reporterSpecifications.empty() ) {
+ m_data.reporterSpecifications.push_back( {
+#if defined( CATCH_CONFIG_DEFAULT_REPORTER )
+ CATCH_CONFIG_DEFAULT_REPORTER,
+#else
+ "console",
+#endif
+ {}, {}, {}
+ } );
+ }
+
+ if(provideBazelReporterOutput()){
+ // Register a JUnit reporter for Bazel. Bazel sets an environment
+ // variable with the path to XML output. If this file is written to
+ // during test, Bazel will not generate a default XML output.
+ // This allows the XML output file to contain higher level of detail
+ // than what is possible otherwise.
+# if defined( _MSC_VER )
+ // On Windows getenv throws a warning as there is no input validation,
+ // since the key is hardcoded, this should not be an issue.
+# pragma warning( push )
+# pragma warning( disable : 4996 )
+# endif
+ const auto bazelOutputFilePtr = std::getenv( "XML_OUTPUT_FILE" );
+# if defined( _MSC_VER )
+# pragma warning( pop )
+# endif
+ if ( bazelOutputFilePtr != nullptr ) {
+ m_data.reporterSpecifications.push_back(
+ { "junit", std::string( bazelOutputFilePtr ), {}, {} } );
+ }
+ }
+
+
+ // We now fixup the reporter specs to handle default output spec,
+ // default colour spec, etc
+ bool defaultOutputUsed = false;
+ for ( auto const& reporterSpec : m_data.reporterSpecifications ) {
+ // We do the default-output check separately, while always
+ // using the default output below to make the code simpler
+ // and avoid superfluous copies.
+ if ( reporterSpec.outputFile().none() ) {
+ CATCH_ENFORCE( !defaultOutputUsed,
+ "Internal error: cannot use default output for "
+ "multiple reporters" );
+ defaultOutputUsed = true;
+ }
+
+ m_processedReporterSpecs.push_back( ProcessedReporterSpec{
+ reporterSpec.name(),
+ reporterSpec.outputFile() ? *reporterSpec.outputFile()
+ : data.defaultOutputFilename,
+ reporterSpec.colourMode().valueOr( data.defaultColourMode ),
+ reporterSpec.customOptions() } );
+ }
+ }
+
+ Config::~Config() = default;
+
+
+ bool Config::listTests() const { return m_data.listTests; }
+ bool Config::listTags() const { return m_data.listTags; }
+ bool Config::listReporters() const { return m_data.listReporters; }
+ bool Config::listListeners() const { return m_data.listListeners; }
+
+ std::vector<std::string> const& Config::getTestsOrTags() const { return m_data.testsOrTags; }
+ std::vector<std::string> const& Config::getSectionsToRun() const { return m_data.sectionsToRun; }
+
+ std::vector<ReporterSpec> const& Config::getReporterSpecs() const {
+ return m_data.reporterSpecifications;
+ }
+
+ std::vector<ProcessedReporterSpec> const&
+ Config::getProcessedReporterSpecs() const {
+ return m_processedReporterSpecs;
+ }
+
+ TestSpec const& Config::testSpec() const { return m_testSpec; }
+ bool Config::hasTestFilters() const { return m_hasTestFilters; }
+
+ bool Config::showHelp() const { return m_data.showHelp; }
+
+ // IConfig interface
+ bool Config::allowThrows() const { return !m_data.noThrow; }
+ StringRef Config::name() const { return m_data.name.empty() ? m_data.processName : m_data.name; }
+ bool Config::includeSuccessfulResults() const { return m_data.showSuccessfulTests; }
+ bool Config::warnAboutMissingAssertions() const {
+ return !!( m_data.warnings & WarnAbout::NoAssertions );
+ }
+ bool Config::warnAboutUnmatchedTestSpecs() const {
+ return !!( m_data.warnings & WarnAbout::UnmatchedTestSpec );
+ }
+ bool Config::zeroTestsCountAsSuccess() const { return m_data.allowZeroTests; }
+ ShowDurations Config::showDurations() const { return m_data.showDurations; }
+ double Config::minDuration() const { return m_data.minDuration; }
+ TestRunOrder Config::runOrder() const { return m_data.runOrder; }
+ uint32_t Config::rngSeed() const { return m_data.rngSeed; }
+ unsigned int Config::shardCount() const { return m_data.shardCount; }
+ unsigned int Config::shardIndex() const { return m_data.shardIndex; }
+ ColourMode Config::defaultColourMode() const { return m_data.defaultColourMode; }
+ bool Config::shouldDebugBreak() const { return m_data.shouldDebugBreak; }
+ int Config::abortAfter() const { return m_data.abortAfter; }
+ bool Config::showInvisibles() const { return m_data.showInvisibles; }
+ Verbosity Config::verbosity() const { return m_data.verbosity; }
+
+ bool Config::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; }
+ unsigned int Config::benchmarkResamples() const { return m_data.benchmarkResamples; }
+ std::chrono::milliseconds Config::benchmarkWarmupTime() const { return std::chrono::milliseconds(m_data.benchmarkWarmupTime); }
+
+} // end namespace Catch
+
+
+
+#include <cassert>
+#include <stack>
+
+namespace Catch {
+
+ ////////////////////////////////////////////////////////////////////////////
+
+
+ ScopedMessage::ScopedMessage( MessageBuilder const& builder ):
+ m_info( builder.m_info ) {
+ m_info.message = builder.m_stream.str();
+ getResultCapture().pushScopedMessage( m_info );
+ }
+
+ ScopedMessage::ScopedMessage( ScopedMessage&& old ) noexcept:
+ m_info( CATCH_MOVE( old.m_info ) ) {
+ old.m_moved = true;
+ }
+
+ ScopedMessage::~ScopedMessage() {
+ if ( !uncaught_exceptions() && !m_moved ){
+ getResultCapture().popScopedMessage(m_info);
+ }
+ }
+
+
+ Capturer::Capturer( StringRef macroName, SourceLineInfo const& lineInfo, ResultWas::OfType resultType, StringRef names ) {
+ auto trimmed = [&] (size_t start, size_t end) {
+ while (names[start] == ',' || isspace(static_cast<unsigned char>(names[start]))) {
+ ++start;
+ }
+ while (names[end] == ',' || isspace(static_cast<unsigned char>(names[end]))) {
+ --end;
+ }
+ return names.substr(start, end - start + 1);
+ };
+ auto skipq = [&] (size_t start, char quote) {
+ for (auto i = start + 1; i < names.size() ; ++i) {
+ if (names[i] == quote)
+ return i;
+ if (names[i] == '\\')
+ ++i;
+ }
+ CATCH_INTERNAL_ERROR("CAPTURE parsing encountered unmatched quote");
+ };
+
+ size_t start = 0;
+ std::stack<char> openings;
+ for (size_t pos = 0; pos < names.size(); ++pos) {
+ char c = names[pos];
+ switch (c) {
+ case '[':
+ case '{':
+ case '(':
+ // It is basically impossible to disambiguate between
+ // comparison and start of template args in this context
+// case '<':
+ openings.push(c);
+ break;
+ case ']':
+ case '}':
+ case ')':
+// case '>':
+ openings.pop();
+ break;
+ case '"':
+ case '\'':
+ pos = skipq(pos, c);
+ break;
+ case ',':
+ if (start != pos && openings.empty()) {
+ m_messages.emplace_back(macroName, lineInfo, resultType);
+ m_messages.back().message = static_cast<std::string>(trimmed(start, pos));
+ m_messages.back().message += " := ";
+ start = pos;
+ }
+ }
+ }
+ assert(openings.empty() && "Mismatched openings");
+ m_messages.emplace_back(macroName, lineInfo, resultType);
+ m_messages.back().message = static_cast<std::string>(trimmed(start, names.size() - 1));
+ m_messages.back().message += " := ";
+ }
+ Capturer::~Capturer() {
+ if ( !uncaught_exceptions() ){
+ assert( m_captured == m_messages.size() );
+ for( size_t i = 0; i < m_captured; ++i )
+ m_resultCapture.popScopedMessage( m_messages[i] );
+ }
+ }
+
+ void Capturer::captureValue( size_t index, std::string const& value ) {
+ assert( index < m_messages.size() );
+ m_messages[index].message += value;
+ m_resultCapture.pushScopedMessage( m_messages[index] );
+ m_captured++;
+ }
+
+} // end namespace Catch
+
+
+
+
+namespace Catch {
+
+ namespace {
+
+ class RegistryHub : public IRegistryHub,
+ public IMutableRegistryHub,
+ private Detail::NonCopyable {
+
+ public: // IRegistryHub
+ RegistryHub() = default;
+ IReporterRegistry const& getReporterRegistry() const override {
+ return m_reporterRegistry;
+ }
+ ITestCaseRegistry const& getTestCaseRegistry() const override {
+ return m_testCaseRegistry;
+ }
+ IExceptionTranslatorRegistry const& getExceptionTranslatorRegistry() const override {
+ return m_exceptionTranslatorRegistry;
+ }
+ ITagAliasRegistry const& getTagAliasRegistry() const override {
+ return m_tagAliasRegistry;
+ }
+ StartupExceptionRegistry const& getStartupExceptionRegistry() const override {
+ return m_exceptionRegistry;
+ }
+
+ public: // IMutableRegistryHub
+ void registerReporter( std::string const& name, IReporterFactoryPtr factory ) override {
+ m_reporterRegistry.registerReporter( name, CATCH_MOVE(factory) );
+ }
+ void registerListener( Detail::unique_ptr<EventListenerFactory> factory ) override {
+ m_reporterRegistry.registerListener( CATCH_MOVE(factory) );
+ }
+ void registerTest( Detail::unique_ptr<TestCaseInfo>&& testInfo, Detail::unique_ptr<ITestInvoker>&& invoker ) override {
+ m_testCaseRegistry.registerTest( CATCH_MOVE(testInfo), CATCH_MOVE(invoker) );
+ }
+ void registerTranslator( Detail::unique_ptr<IExceptionTranslator>&& translator ) override {
+ m_exceptionTranslatorRegistry.registerTranslator( CATCH_MOVE(translator) );
+ }
+ void registerTagAlias( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ) override {
+ m_tagAliasRegistry.add( alias, tag, lineInfo );
+ }
+ void registerStartupException() noexcept override {
+#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
+ m_exceptionRegistry.add(std::current_exception());
+#else
+ CATCH_INTERNAL_ERROR("Attempted to register active exception under CATCH_CONFIG_DISABLE_EXCEPTIONS!");
+#endif
+ }
+ IMutableEnumValuesRegistry& getMutableEnumValuesRegistry() override {
+ return m_enumValuesRegistry;
+ }
+
+ private:
+ TestRegistry m_testCaseRegistry;
+ ReporterRegistry m_reporterRegistry;
+ ExceptionTranslatorRegistry m_exceptionTranslatorRegistry;
+ TagAliasRegistry m_tagAliasRegistry;
+ StartupExceptionRegistry m_exceptionRegistry;
+ Detail::EnumValuesRegistry m_enumValuesRegistry;
+ };
+ }
+
+ using RegistryHubSingleton = Singleton<RegistryHub, IRegistryHub, IMutableRegistryHub>;
+
+ IRegistryHub const& getRegistryHub() {
+ return RegistryHubSingleton::get();
+ }
+ IMutableRegistryHub& getMutableRegistryHub() {
+ return RegistryHubSingleton::getMutable();
+ }
+ void cleanUp() {
+ cleanupSingletons();
+ cleanUpContext();
+ }
+ std::string translateActiveException() {
+ return getRegistryHub().getExceptionTranslatorRegistry().translateActiveException();
+ }
+
+
+} // end namespace Catch
+
+
+
+#include <algorithm>
+#include <cassert>
+#include <iomanip>
+#include <set>
+
+namespace Catch {
+
+ namespace {
+ const int MaxExitCode = 255;
+
+ IEventListenerPtr createReporter(std::string const& reporterName, ReporterConfig&& config) {
+ auto reporter = Catch::getRegistryHub().getReporterRegistry().create(reporterName, CATCH_MOVE(config));
+ CATCH_ENFORCE(reporter, "No reporter registered with name: '" << reporterName << '\'');
+
+ return reporter;
+ }
+
+ IEventListenerPtr prepareReporters(Config const* config) {
+ if (Catch::getRegistryHub().getReporterRegistry().getListeners().empty()
+ && config->getProcessedReporterSpecs().size() == 1) {
+ auto const& spec = config->getProcessedReporterSpecs()[0];
+ return createReporter(
+ spec.name,
+ ReporterConfig( config,
+ makeStream( spec.outputFilename ),
+ spec.colourMode,
+ spec.customOptions ) );
+ }
+
+ auto multi = Detail::make_unique<MultiReporter>(config);
+
+ auto const& listeners = Catch::getRegistryHub().getReporterRegistry().getListeners();
+ for (auto const& listener : listeners) {
+ multi->addListener(listener->create(config));
+ }
+
+ std::size_t reporterIdx = 0;
+ for ( auto const& reporterSpec : config->getProcessedReporterSpecs() ) {
+ multi->addReporter( createReporter(
+ reporterSpec.name,
+ ReporterConfig( config,
+ makeStream( reporterSpec.outputFilename ),
+ reporterSpec.colourMode,
+ reporterSpec.customOptions ) ) );
+ reporterIdx++;
+ }
+
+ return multi;
+ }
+
+ class TestGroup {
+ public:
+ explicit TestGroup(IEventListenerPtr&& reporter, Config const* config):
+ m_reporter(reporter.get()),
+ m_config{config},
+ m_context{config, CATCH_MOVE(reporter)} {
+
+ assert( m_config->testSpec().getInvalidSpecs().empty() &&
+ "Invalid test specs should be handled before running tests" );
+
+ auto const& allTestCases = getAllTestCasesSorted(*m_config);
+ auto const& testSpec = m_config->testSpec();
+ if ( !testSpec.hasFilters() ) {
+ for ( auto const& test : allTestCases ) {
+ if ( !test.getTestCaseInfo().isHidden() ) {
+ m_tests.emplace( &test );
+ }
+ }
+ } else {
+ m_matches =
+ testSpec.matchesByFilter( allTestCases, *m_config );
+ for ( auto const& match : m_matches ) {
+ m_tests.insert( match.tests.begin(),
+ match.tests.end() );
+ }
+ }
+
+ m_tests = createShard(m_tests, m_config->shardCount(), m_config->shardIndex());
+ }
+
+ Totals execute() {
+ Totals totals;
+ for (auto const& testCase : m_tests) {
+ if (!m_context.aborting())
+ totals += m_context.runTest(*testCase);
+ else
+ m_reporter->skipTest(testCase->getTestCaseInfo());
+ }
+
+ for (auto const& match : m_matches) {
+ if (match.tests.empty()) {
+ m_unmatchedTestSpecs = true;
+ m_reporter->noMatchingTestCases( match.name );
+ }
+ }
+
+ return totals;
+ }
+
+ bool hadUnmatchedTestSpecs() const {
+ return m_unmatchedTestSpecs;
+ }
+
+
+ private:
+ IEventListener* m_reporter;
+ Config const* m_config;
+ RunContext m_context;
+ std::set<TestCaseHandle const*> m_tests;
+ TestSpec::Matches m_matches;
+ bool m_unmatchedTestSpecs = false;
+ };
+
+ void applyFilenamesAsTags() {
+ for (auto const& testInfo : getRegistryHub().getTestCaseRegistry().getAllInfos()) {
+ testInfo->addFilenameTag();
+ }
+ }
+
+ } // anon namespace
+
+ Session::Session() {
+ static bool alreadyInstantiated = false;
+ if( alreadyInstantiated ) {
+ CATCH_TRY { CATCH_INTERNAL_ERROR( "Only one instance of Catch::Session can ever be used" ); }
+ CATCH_CATCH_ALL { getMutableRegistryHub().registerStartupException(); }
+ }
+
+ // There cannot be exceptions at startup in no-exception mode.
+#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
+ const auto& exceptions = getRegistryHub().getStartupExceptionRegistry().getExceptions();
+ if ( !exceptions.empty() ) {
+ config();
+ getCurrentMutableContext().setConfig(m_config.get());
+
+ m_startupExceptions = true;
+ auto errStream = makeStream( "%stderr" );
+ auto colourImpl = makeColourImpl(
+ ColourMode::PlatformDefault, errStream.get() );
+ auto guard = colourImpl->guardColour( Colour::Red );
+ errStream->stream() << "Errors occurred during startup!" << '\n';
+ // iterate over all exceptions and notify user
+ for ( const auto& ex_ptr : exceptions ) {
+ try {
+ std::rethrow_exception(ex_ptr);
+ } catch ( std::exception const& ex ) {
+ errStream->stream() << TextFlow::Column( ex.what() ).indent(2) << '\n';
+ }
+ }
+ }
+#endif
+
+ alreadyInstantiated = true;
+ m_cli = makeCommandLineParser( m_configData );
+ }
+ Session::~Session() {
+ Catch::cleanUp();
+ }
+
+ void Session::showHelp() const {
+ Catch::cout()
+ << "\nCatch2 v" << libraryVersion() << '\n'
+ << m_cli << '\n'
+ << "For more detailed usage please see the project docs\n\n" << std::flush;
+ }
+ void Session::libIdentify() {
+ Catch::cout()
+ << std::left << std::setw(16) << "description: " << "A Catch2 test executable\n"
+ << std::left << std::setw(16) << "category: " << "testframework\n"
+ << std::left << std::setw(16) << "framework: " << "Catch2\n"
+ << std::left << std::setw(16) << "version: " << libraryVersion() << '\n' << std::flush;
+ }
+
+ int Session::applyCommandLine( int argc, char const * const * argv ) {
+ if( m_startupExceptions )
+ return 1;
+
+ auto result = m_cli.parse( Clara::Args( argc, argv ) );
+
+ if( !result ) {
+ config();
+ getCurrentMutableContext().setConfig(m_config.get());
+ auto errStream = makeStream( "%stderr" );
+ auto colour = makeColourImpl( ColourMode::PlatformDefault, errStream.get() );
+
+ errStream->stream()
+ << colour->guardColour( Colour::Red )
+ << "\nError(s) in input:\n"
+ << TextFlow::Column( result.errorMessage() ).indent( 2 )
+ << "\n\n";
+ errStream->stream() << "Run with -? for usage\n\n" << std::flush;
+ return MaxExitCode;
+ }
+
+ if( m_configData.showHelp )
+ showHelp();
+ if( m_configData.libIdentify )
+ libIdentify();
+
+ m_config.reset();
+ return 0;
+ }
+
+#if defined(CATCH_CONFIG_WCHAR) && defined(_WIN32) && defined(UNICODE)
+ int Session::applyCommandLine( int argc, wchar_t const * const * argv ) {
+
+ char **utf8Argv = new char *[ argc ];
+
+ for ( int i = 0; i < argc; ++i ) {
+ int bufSize = WideCharToMultiByte( CP_UTF8, 0, argv[i], -1, nullptr, 0, nullptr, nullptr );
+
+ utf8Argv[ i ] = new char[ bufSize ];
+
+ WideCharToMultiByte( CP_UTF8, 0, argv[i], -1, utf8Argv[i], bufSize, nullptr, nullptr );
+ }
+
+ int returnCode = applyCommandLine( argc, utf8Argv );
+
+ for ( int i = 0; i < argc; ++i )
+ delete [] utf8Argv[ i ];
+
+ delete [] utf8Argv;
+
+ return returnCode;
+ }
+#endif
+
+ void Session::useConfigData( ConfigData const& configData ) {
+ m_configData = configData;
+ m_config.reset();
+ }
+
+ int Session::run() {
+ if( ( m_configData.waitForKeypress & WaitForKeypress::BeforeStart ) != 0 ) {
+ Catch::cout() << "...waiting for enter/ return before starting\n" << std::flush;
+ static_cast<void>(std::getchar());
+ }
+ int exitCode = runInternal();
+ if( ( m_configData.waitForKeypress & WaitForKeypress::BeforeExit ) != 0 ) {
+ Catch::cout() << "...waiting for enter/ return before exiting, with code: " << exitCode << '\n' << std::flush;
+ static_cast<void>(std::getchar());
+ }
+ return exitCode;
+ }
+
+ Clara::Parser const& Session::cli() const {
+ return m_cli;
+ }
+ void Session::cli( Clara::Parser const& newParser ) {
+ m_cli = newParser;
+ }
+ ConfigData& Session::configData() {
+ return m_configData;
+ }
+ Config& Session::config() {
+ if( !m_config )
+ m_config = Detail::make_unique<Config>( m_configData );
+ return *m_config;
+ }
+
+ int Session::runInternal() {
+ if( m_startupExceptions )
+ return 1;
+
+ if (m_configData.showHelp || m_configData.libIdentify) {
+ return 0;
+ }
+
+ if ( m_configData.shardIndex >= m_configData.shardCount ) {
+ Catch::cerr() << "The shard count (" << m_configData.shardCount
+ << ") must be greater than the shard index ("
+ << m_configData.shardIndex << ")\n"
+ << std::flush;
+ return 1;
+ }
+
+ CATCH_TRY {
+ config(); // Force config to be constructed
+
+ seedRng( *m_config );
+
+ if (m_configData.filenamesAsTags) {
+ applyFilenamesAsTags();
+ }
+
+ // Set up global config instance before we start calling into other functions
+ getCurrentMutableContext().setConfig(m_config.get());
+
+ // Create reporter(s) so we can route listings through them
+ auto reporter = prepareReporters(m_config.get());
+
+ auto const& invalidSpecs = m_config->testSpec().getInvalidSpecs();
+ if ( !invalidSpecs.empty() ) {
+ for ( auto const& spec : invalidSpecs ) {
+ reporter->reportInvalidTestSpec( spec );
+ }
+ return 1;
+ }
+
+
+ // Handle list request
+ if (list(*reporter, *m_config)) {
+ return 0;
+ }
+
+ TestGroup tests { CATCH_MOVE(reporter), m_config.get() };
+ auto const totals = tests.execute();
+
+ if ( tests.hadUnmatchedTestSpecs()
+ && m_config->warnAboutUnmatchedTestSpecs() ) {
+ return 3;
+ }
+
+ if ( totals.testCases.total() == 0
+ && !m_config->zeroTestsCountAsSuccess() ) {
+ return 2;
+ }
+
+ // Note that on unices only the lower 8 bits are usually used, clamping
+ // the return value to 255 prevents false negative when some multiple
+ // of 256 tests has failed
+ return (std::min) (MaxExitCode, static_cast<int>(totals.assertions.failed));
+ }
+#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
+ catch( std::exception& ex ) {
+ Catch::cerr() << ex.what() << '\n' << std::flush;
+ return MaxExitCode;
+ }
+#endif
+ }
+
+} // end namespace Catch
+
+
+
+
+namespace Catch {
+
+ RegistrarForTagAliases::RegistrarForTagAliases(char const* alias, char const* tag, SourceLineInfo const& lineInfo) {
+ CATCH_TRY {
+ getMutableRegistryHub().registerTagAlias(alias, tag, lineInfo);
+ } CATCH_CATCH_ALL {
+ // Do not throw when constructing global objects, instead register the exception to be processed later
+ getMutableRegistryHub().registerStartupException();
+ }
+ }
+
+}
+
+
+
+#include <cassert>
+#include <cctype>
+#include <algorithm>
+
+namespace Catch {
+
+ namespace {
+ using TCP_underlying_type = uint8_t;
+ static_assert(sizeof(TestCaseProperties) == sizeof(TCP_underlying_type),
+ "The size of the TestCaseProperties is different from the assumed size");
+
+ TestCaseProperties operator|(TestCaseProperties lhs, TestCaseProperties rhs) {
+ return static_cast<TestCaseProperties>(
+ static_cast<TCP_underlying_type>(lhs) | static_cast<TCP_underlying_type>(rhs)
+ );
+ }
+
+ TestCaseProperties& operator|=(TestCaseProperties& lhs, TestCaseProperties rhs) {
+ lhs = static_cast<TestCaseProperties>(
+ static_cast<TCP_underlying_type>(lhs) | static_cast<TCP_underlying_type>(rhs)
+ );
+ return lhs;
+ }
+
+ TestCaseProperties operator&(TestCaseProperties lhs, TestCaseProperties rhs) {
+ return static_cast<TestCaseProperties>(
+ static_cast<TCP_underlying_type>(lhs) & static_cast<TCP_underlying_type>(rhs)
+ );
+ }
+
+ bool applies(TestCaseProperties tcp) {
+ static_assert(static_cast<TCP_underlying_type>(TestCaseProperties::None) == 0,
+ "TestCaseProperties::None must be equal to 0");
+ return tcp != TestCaseProperties::None;
+ }
+
+ TestCaseProperties parseSpecialTag( StringRef tag ) {
+ if( !tag.empty() && tag[0] == '.' )
+ return TestCaseProperties::IsHidden;
+ else if( tag == "!throws"_sr )
+ return TestCaseProperties::Throws;
+ else if( tag == "!shouldfail"_sr )
+ return TestCaseProperties::ShouldFail;
+ else if( tag == "!mayfail"_sr )
+ return TestCaseProperties::MayFail;
+ else if( tag == "!nonportable"_sr )
+ return TestCaseProperties::NonPortable;
+ else if( tag == "!benchmark"_sr )
+ return TestCaseProperties::Benchmark | TestCaseProperties::IsHidden;
+ else
+ return TestCaseProperties::None;
+ }
+ bool isReservedTag( StringRef tag ) {
+ return parseSpecialTag( tag ) == TestCaseProperties::None
+ && tag.size() > 0
+ && !std::isalnum( static_cast<unsigned char>(tag[0]) );
+ }
+ void enforceNotReservedTag( StringRef tag, SourceLineInfo const& _lineInfo ) {
+ CATCH_ENFORCE( !isReservedTag(tag),
+ "Tag name: [" << tag << "] is not allowed.\n"
+ << "Tag names starting with non alphanumeric characters are reserved\n"
+ << _lineInfo );
+ }
+
+ std::string makeDefaultName() {
+ static size_t counter = 0;
+ return "Anonymous test case " + std::to_string(++counter);
+ }
+
+ StringRef extractFilenamePart(StringRef filename) {
+ size_t lastDot = filename.size();
+ while (lastDot > 0 && filename[lastDot - 1] != '.') {
+ --lastDot;
+ }
+ --lastDot;
+
+ size_t nameStart = lastDot;
+ while (nameStart > 0 && filename[nameStart - 1] != '/' && filename[nameStart - 1] != '\\') {
+ --nameStart;
+ }
+
+ return filename.substr(nameStart, lastDot - nameStart);
+ }
+
+ // Returns the upper bound on size of extra tags ([#file]+[.])
+ size_t sizeOfExtraTags(StringRef filepath) {
+ // [.] is 3, [#] is another 3
+ const size_t extras = 3 + 3;
+ return extractFilenamePart(filepath).size() + extras;
+ }
+ } // end unnamed namespace
+
+ bool operator<( Tag const& lhs, Tag const& rhs ) {
+ Detail::CaseInsensitiveLess cmp;
+ return cmp( lhs.original, rhs.original );
+ }
+ bool operator==( Tag const& lhs, Tag const& rhs ) {
+ Detail::CaseInsensitiveEqualTo cmp;
+ return cmp( lhs.original, rhs.original );
+ }
+
+ Detail::unique_ptr<TestCaseInfo>
+ makeTestCaseInfo(StringRef _className,
+ NameAndTags const& nameAndTags,
+ SourceLineInfo const& _lineInfo ) {
+ return Detail::make_unique<TestCaseInfo>(_className, nameAndTags, _lineInfo);
+ }
+
+ TestCaseInfo::TestCaseInfo(StringRef _className,
+ NameAndTags const& _nameAndTags,
+ SourceLineInfo const& _lineInfo):
+ name( _nameAndTags.name.empty() ? makeDefaultName() : _nameAndTags.name ),
+ className( _className ),
+ lineInfo( _lineInfo )
+ {
+ StringRef originalTags = _nameAndTags.tags;
+ // We need to reserve enough space to store all of the tags
+ // (including optional hidden tag and filename tag)
+ auto requiredSize = originalTags.size() + sizeOfExtraTags(_lineInfo.file);
+ backingTags.reserve(requiredSize);
+
+ // We cannot copy the tags directly, as we need to normalize
+ // some tags, so that [.foo] is copied as [.][foo].
+ size_t tagStart = 0;
+ size_t tagEnd = 0;
+ bool inTag = false;
+ for (size_t idx = 0; idx < originalTags.size(); ++idx) {
+ auto c = originalTags[idx];
+ if (c == '[') {
+ assert(!inTag);
+ inTag = true;
+ tagStart = idx;
+ }
+ if (c == ']') {
+ assert(inTag);
+ inTag = false;
+ tagEnd = idx;
+ assert(tagStart < tagEnd);
+
+ // We need to check the tag for special meanings, copy
+ // it over to backing storage and actually reference the
+ // backing storage in the saved tags
+ StringRef tagStr = originalTags.substr(tagStart+1, tagEnd - tagStart - 1);
+ CATCH_ENFORCE(!tagStr.empty(), "Empty tags are not allowed");
+ enforceNotReservedTag(tagStr, lineInfo);
+ properties |= parseSpecialTag(tagStr);
+ // When copying a tag to the backing storage, we need to
+ // check if it is a merged hide tag, such as [.foo], and
+ // if it is, we need to handle it as if it was [foo].
+ if (tagStr.size() > 1 && tagStr[0] == '.') {
+ tagStr = tagStr.substr(1, tagStr.size() - 1);
+ }
+ // We skip over dealing with the [.] tag, as we will add
+ // it later unconditionally and then sort and unique all
+ // the tags.
+ internalAppendTag(tagStr);
+ }
+ (void)inTag; // Silence "set-but-unused" warning in release mode.
+ }
+ // Add [.] if relevant
+ if (isHidden()) {
+ internalAppendTag("."_sr);
+ }
+
+ // Sort and prepare tags
+ std::sort(begin(tags), end(tags));
+ tags.erase(std::unique(begin(tags), end(tags)),
+ end(tags));
+ }
+
+ bool TestCaseInfo::isHidden() const {
+ return applies( properties & TestCaseProperties::IsHidden );
+ }
+ bool TestCaseInfo::throws() const {
+ return applies( properties & TestCaseProperties::Throws );
+ }
+ bool TestCaseInfo::okToFail() const {
+ return applies( properties & (TestCaseProperties::ShouldFail | TestCaseProperties::MayFail ) );
+ }
+ bool TestCaseInfo::expectedToFail() const {
+ return applies( properties & (TestCaseProperties::ShouldFail) );
+ }
+
+ void TestCaseInfo::addFilenameTag() {
+ std::string combined("#");
+ combined += extractFilenamePart(lineInfo.file);
+ internalAppendTag(combined);
+ }
+
+ std::string TestCaseInfo::tagsAsString() const {
+ std::string ret;
+ // '[' and ']' per tag
+ std::size_t full_size = 2 * tags.size();
+ for (const auto& tag : tags) {
+ full_size += tag.original.size();
+ }
+ ret.reserve(full_size);
+ for (const auto& tag : tags) {
+ ret.push_back('[');
+ ret += tag.original;
+ ret.push_back(']');
+ }
+
+ return ret;
+ }
+
+ void TestCaseInfo::internalAppendTag(StringRef tagStr) {
+ backingTags += '[';
+ const auto backingStart = backingTags.size();
+ backingTags += tagStr;
+ const auto backingEnd = backingTags.size();
+ backingTags += ']';
+ tags.emplace_back(StringRef(backingTags.c_str() + backingStart, backingEnd - backingStart));
+ }
+
+ bool operator<( TestCaseInfo const& lhs, TestCaseInfo const& rhs ) {
+ // We want to avoid redoing the string comparisons multiple times,
+ // so we store the result of a three-way comparison before using
+ // it in the actual comparison logic.
+ const auto cmpName = lhs.name.compare( rhs.name );
+ if ( cmpName != 0 ) {
+ return cmpName < 0;
+ }
+ const auto cmpClassName = lhs.className.compare( rhs.className );
+ if ( cmpClassName != 0 ) {
+ return cmpClassName < 0;
+ }
+ return lhs.tags < rhs.tags;
+ }
+
+ TestCaseInfo const& TestCaseHandle::getTestCaseInfo() const {
+ return *m_info;
+ }
+
+} // end namespace Catch
+
+
+
+#include <algorithm>
+#include <string>
+#include <vector>
+
+namespace Catch {
+
+ TestSpec::Pattern::Pattern( std::string const& name )
+ : m_name( name )
+ {}
+
+ TestSpec::Pattern::~Pattern() = default;
+
+ std::string const& TestSpec::Pattern::name() const {
+ return m_name;
+ }
+
+
+ TestSpec::NamePattern::NamePattern( std::string const& name, std::string const& filterString )
+ : Pattern( filterString )
+ , m_wildcardPattern( toLower( name ), CaseSensitive::No )
+ {}
+
+ bool TestSpec::NamePattern::matches( TestCaseInfo const& testCase ) const {
+ return m_wildcardPattern.matches( testCase.name );
+ }
+
+
+ TestSpec::TagPattern::TagPattern( std::string const& tag, std::string const& filterString )
+ : Pattern( filterString )
+ , m_tag( tag )
+ {}
+
+ bool TestSpec::TagPattern::matches( TestCaseInfo const& testCase ) const {
+ return std::find( begin( testCase.tags ),
+ end( testCase.tags ),
+ Tag( m_tag ) ) != end( testCase.tags );
+ }
+
+ bool TestSpec::Filter::matches( TestCaseInfo const& testCase ) const {
+ bool should_use = !testCase.isHidden();
+ for (auto const& pattern : m_required) {
+ should_use = true;
+ if (!pattern->matches(testCase)) {
+ return false;
+ }
+ }
+ for (auto const& pattern : m_forbidden) {
+ if (pattern->matches(testCase)) {
+ return false;
+ }
+ }
+ return should_use;
+ }
+
+ std::string TestSpec::Filter::name() const {
+ std::string name;
+ for (auto const& p : m_required) {
+ name += p->name();
+ }
+ for (auto const& p : m_forbidden) {
+ name += p->name();
+ }
+ return name;
+ }
+
+
+ bool TestSpec::hasFilters() const {
+ return !m_filters.empty();
+ }
+
+ bool TestSpec::matches( TestCaseInfo const& testCase ) const {
+ return std::any_of( m_filters.begin(), m_filters.end(), [&]( Filter const& f ){ return f.matches( testCase ); } );
+ }
+
+ TestSpec::Matches TestSpec::matchesByFilter( std::vector<TestCaseHandle> const& testCases, IConfig const& config ) const
+ {
+ Matches matches( m_filters.size() );
+ std::transform( m_filters.begin(), m_filters.end(), matches.begin(), [&]( Filter const& filter ){
+ std::vector<TestCaseHandle const*> currentMatches;
+ for( auto const& test : testCases )
+ if( isThrowSafe( test, config ) && filter.matches( test.getTestCaseInfo() ) )
+ currentMatches.emplace_back( &test );
+ return FilterMatch{ filter.name(), currentMatches };
+ } );
+ return matches;
+ }
+
+ const TestSpec::vectorStrings& TestSpec::getInvalidSpecs() const {
+ return m_invalidSpecs;
+ }
+
+}
+
+
+
+#include <chrono>
+
+namespace Catch {
+
+ namespace {
+ static auto getCurrentNanosecondsSinceEpoch() -> uint64_t {
+ return std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::high_resolution_clock::now().time_since_epoch()).count();
+ }
+ } // end unnamed namespace
+
+ void Timer::start() {
+ m_nanoseconds = getCurrentNanosecondsSinceEpoch();
+ }
+ auto Timer::getElapsedNanoseconds() const -> uint64_t {
+ return getCurrentNanosecondsSinceEpoch() - m_nanoseconds;
+ }
+ auto Timer::getElapsedMicroseconds() const -> uint64_t {
+ return getElapsedNanoseconds()/1000;
+ }
+ auto Timer::getElapsedMilliseconds() const -> unsigned int {
+ return static_cast<unsigned int>(getElapsedMicroseconds()/1000);
+ }
+ auto Timer::getElapsedSeconds() const -> double {
+ return getElapsedMicroseconds()/1000000.0;
+ }
+
+
+} // namespace Catch
+
+
+
+
+#include <cmath>
+#include <iomanip>
+
+namespace Catch {
+
+namespace Detail {
+
+ namespace {
+ const int hexThreshold = 255;
+
+ struct Endianness {
+ enum Arch { Big, Little };
+
+ static Arch which() {
+ int one = 1;
+ // If the lowest byte we read is non-zero, we can assume
+ // that little endian format is used.
+ auto value = *reinterpret_cast<char*>(&one);
+ return value ? Little : Big;
+ }
+ };
+
+ template<typename T>
+ std::string fpToString(T value, int precision) {
+ if (Catch::isnan(value)) {
+ return "nan";
+ }
+
+ ReusableStringStream rss;
+ rss << std::setprecision(precision)
+ << std::fixed
+ << value;
+ std::string d = rss.str();
+ std::size_t i = d.find_last_not_of('0');
+ if (i != std::string::npos && i != d.size() - 1) {
+ if (d[i] == '.')
+ i++;
+ d = d.substr(0, i + 1);
+ }
+ return d;
+ }
+ } // end unnamed namespace
+
+ std::string convertIntoString(StringRef string, bool escape_invisibles) {
+ std::string ret;
+ // This is enough for the "don't escape invisibles" case, and a good
+ // lower bound on the "escape invisibles" case.
+ ret.reserve(string.size() + 2);
+
+ if (!escape_invisibles) {
+ ret += '"';
+ ret += string;
+ ret += '"';
+ return ret;
+ }
+
+ ret += '"';
+ for (char c : string) {
+ switch (c) {
+ case '\r':
+ ret.append("\\r");
+ break;
+ case '\n':
+ ret.append("\\n");
+ break;
+ case '\t':
+ ret.append("\\t");
+ break;
+ case '\f':
+ ret.append("\\f");
+ break;
+ default:
+ ret.push_back(c);
+ break;
+ }
+ }
+ ret += '"';
+
+ return ret;
+ }
+
+ std::string convertIntoString(StringRef string) {
+ return convertIntoString(string, getCurrentContext().getConfig()->showInvisibles());
+ }
+
+ std::string rawMemoryToString( const void *object, std::size_t size ) {
+ // Reverse order for little endian architectures
+ int i = 0, end = static_cast<int>( size ), inc = 1;
+ if( Endianness::which() == Endianness::Little ) {
+ i = end-1;
+ end = inc = -1;
+ }
+
+ unsigned char const *bytes = static_cast<unsigned char const *>(object);
+ ReusableStringStream rss;
+ rss << "0x" << std::setfill('0') << std::hex;
+ for( ; i != end; i += inc )
+ rss << std::setw(2) << static_cast<unsigned>(bytes[i]);
+ return rss.str();
+ }
+} // end Detail namespace
+
+
+
+//// ======================================================= ////
+//
+// Out-of-line defs for full specialization of StringMaker
+//
+//// ======================================================= ////
+
+std::string StringMaker<std::string>::convert(const std::string& str) {
+ return Detail::convertIntoString( str );
+}
+
+#ifdef CATCH_CONFIG_CPP17_STRING_VIEW
+std::string StringMaker<std::string_view>::convert(std::string_view str) {
+ return Detail::convertIntoString( StringRef( str.data(), str.size() ) );
+}
+#endif
+
+std::string StringMaker<char const*>::convert(char const* str) {
+ if (str) {
+ return Detail::convertIntoString( str );
+ } else {
+ return{ "{null string}" };
+ }
+}
+std::string StringMaker<char*>::convert(char* str) {
+ if (str) {
+ return Detail::convertIntoString( str );
+ } else {
+ return{ "{null string}" };
+ }
+}
+
+#ifdef CATCH_CONFIG_WCHAR
+std::string StringMaker<std::wstring>::convert(const std::wstring& wstr) {
+ std::string s;
+ s.reserve(wstr.size());
+ for (auto c : wstr) {
+ s += (c <= 0xff) ? static_cast<char>(c) : '?';
+ }
+ return ::Catch::Detail::stringify(s);
+}
+
+# ifdef CATCH_CONFIG_CPP17_STRING_VIEW
+std::string StringMaker<std::wstring_view>::convert(std::wstring_view str) {
+ return StringMaker<std::wstring>::convert(std::wstring(str));
+}
+# endif
+
+std::string StringMaker<wchar_t const*>::convert(wchar_t const * str) {
+ if (str) {
+ return ::Catch::Detail::stringify(std::wstring{ str });
+ } else {
+ return{ "{null string}" };
+ }
+}
+std::string StringMaker<wchar_t *>::convert(wchar_t * str) {
+ if (str) {
+ return ::Catch::Detail::stringify(std::wstring{ str });
+ } else {
+ return{ "{null string}" };
+ }
+}
+#endif
+
+#if defined(CATCH_CONFIG_CPP17_BYTE)
+#include <cstddef>
+std::string StringMaker<std::byte>::convert(std::byte value) {
+ return ::Catch::Detail::stringify(std::to_integer<unsigned long long>(value));
+}
+#endif // defined(CATCH_CONFIG_CPP17_BYTE)
+
+std::string StringMaker<int>::convert(int value) {
+ return ::Catch::Detail::stringify(static_cast<long long>(value));
+}
+std::string StringMaker<long>::convert(long value) {
+ return ::Catch::Detail::stringify(static_cast<long long>(value));
+}
+std::string StringMaker<long long>::convert(long long value) {
+ ReusableStringStream rss;
+ rss << value;
+ if (value > Detail::hexThreshold) {
+ rss << " (0x" << std::hex << value << ')';
+ }
+ return rss.str();
+}
+
+std::string StringMaker<unsigned int>::convert(unsigned int value) {
+ return ::Catch::Detail::stringify(static_cast<unsigned long long>(value));
+}
+std::string StringMaker<unsigned long>::convert(unsigned long value) {
+ return ::Catch::Detail::stringify(static_cast<unsigned long long>(value));
+}
+std::string StringMaker<unsigned long long>::convert(unsigned long long value) {
+ ReusableStringStream rss;
+ rss << value;
+ if (value > Detail::hexThreshold) {
+ rss << " (0x" << std::hex << value << ')';
+ }
+ return rss.str();
+}
+
+std::string StringMaker<signed char>::convert(signed char value) {
+ if (value == '\r') {
+ return "'\\r'";
+ } else if (value == '\f') {
+ return "'\\f'";
+ } else if (value == '\n') {
+ return "'\\n'";
+ } else if (value == '\t') {
+ return "'\\t'";
+ } else if ('\0' <= value && value < ' ') {
+ return ::Catch::Detail::stringify(static_cast<unsigned int>(value));
+ } else {
+ char chstr[] = "' '";
+ chstr[1] = value;
+ return chstr;
+ }
+}
+std::string StringMaker<char>::convert(char c) {
+ return ::Catch::Detail::stringify(static_cast<signed char>(c));
+}
+std::string StringMaker<unsigned char>::convert(unsigned char c) {
+ return ::Catch::Detail::stringify(static_cast<char>(c));
+}
+
+int StringMaker<float>::precision = 5;
+
+std::string StringMaker<float>::convert(float value) {
+ return Detail::fpToString(value, precision) + 'f';
+}
+
+int StringMaker<double>::precision = 10;
+
+std::string StringMaker<double>::convert(double value) {
+ return Detail::fpToString(value, precision);
+}
+
+} // end namespace Catch
+
+
+
+namespace Catch {
+
+ Counts Counts::operator - ( Counts const& other ) const {
+ Counts diff;
+ diff.passed = passed - other.passed;
+ diff.failed = failed - other.failed;
+ diff.failedButOk = failedButOk - other.failedButOk;
+ return diff;
+ }
+
+ Counts& Counts::operator += ( Counts const& other ) {
+ passed += other.passed;
+ failed += other.failed;
+ failedButOk += other.failedButOk;
+ return *this;
+ }
+
+ std::uint64_t Counts::total() const {
+ return passed + failed + failedButOk;
+ }
+ bool Counts::allPassed() const {
+ return failed == 0 && failedButOk == 0;
+ }
+ bool Counts::allOk() const {
+ return failed == 0;
+ }
+
+ Totals Totals::operator - ( Totals const& other ) const {
+ Totals diff;
+ diff.assertions = assertions - other.assertions;
+ diff.testCases = testCases - other.testCases;
+ return diff;
+ }
+
+ Totals& Totals::operator += ( Totals const& other ) {
+ assertions += other.assertions;
+ testCases += other.testCases;
+ return *this;
+ }
+
+ Totals Totals::delta( Totals const& prevTotals ) const {
+ Totals diff = *this - prevTotals;
+ if( diff.assertions.failed > 0 )
+ ++diff.testCases.failed;
+ else if( diff.assertions.failedButOk > 0 )
+ ++diff.testCases.failedButOk;
+ else
+ ++diff.testCases.passed;
+ return diff;
+ }
+
+}
+
+
+#include <ostream>
+
+namespace Catch {
+
+ Version::Version
+ ( unsigned int _majorVersion,
+ unsigned int _minorVersion,
+ unsigned int _patchNumber,
+ char const * const _branchName,
+ unsigned int _buildNumber )
+ : majorVersion( _majorVersion ),
+ minorVersion( _minorVersion ),
+ patchNumber( _patchNumber ),
+ branchName( _branchName ),
+ buildNumber( _buildNumber )
+ {}
+
+ std::ostream& operator << ( std::ostream& os, Version const& version ) {
+ os << version.majorVersion << '.'
+ << version.minorVersion << '.'
+ << version.patchNumber;
+ // branchName is never null -> 0th char is \0 if it is empty
+ if (version.branchName[0]) {
+ os << '-' << version.branchName
+ << '.' << version.buildNumber;
+ }
+ return os;
+ }
+
+ Version const& libraryVersion() {
+ static Version version( 3, 1, 0, "", 0 );
+ return version;
+ }
+
+}
+
+
+
+
+namespace Catch {
+
+ const char* GeneratorException::what() const noexcept {
+ return m_msg;
+ }
+
+} // end namespace Catch
+
+
+
+
+namespace Catch {
+
+ IGeneratorTracker::~IGeneratorTracker() = default;
+
+namespace Generators {
+
+namespace Detail {
+
+ [[noreturn]]
+ void throw_generator_exception(char const* msg) {
+ Catch::throw_exception(GeneratorException{ msg });
+ }
+} // end namespace Detail
+
+ GeneratorUntypedBase::~GeneratorUntypedBase() = default;
+
+ auto acquireGeneratorTracker(StringRef generatorName, SourceLineInfo const& lineInfo ) -> IGeneratorTracker& {
+ return getResultCapture().acquireGeneratorTracker( generatorName, lineInfo );
+ }
+
+} // namespace Generators
+} // namespace Catch
+
+
+
+
+
+std::uint32_t Catch::Generators::Detail::getSeed() { return sharedRng()(); }
+
+
+
+
+namespace Catch {
+ IResultCapture::~IResultCapture() = default;
+}
+
+
+
+
+namespace Catch {
+ IConfig::~IConfig() = default;
+}
+
+
+
+
+namespace Catch {
+ IExceptionTranslator::~IExceptionTranslator() = default;
+ IExceptionTranslatorRegistry::~IExceptionTranslatorRegistry() = default;
+}
+
+
+
+#include <string>
+
+namespace Catch {
+ namespace Generators {
+
+ bool GeneratorUntypedBase::countedNext() {
+ auto ret = next();
+ if ( ret ) {
+ m_stringReprCache.clear();
+ ++m_currentElementIndex;
+ }
+ return ret;
+ }
+
+ StringRef GeneratorUntypedBase::currentElementAsString() const {
+ if ( m_stringReprCache.empty() ) {
+ m_stringReprCache = stringifyImpl();
+ }
+ return m_stringReprCache;
+ }
+
+ } // namespace Generators
+} // namespace Catch
+
+
+
+
+namespace Catch {
+ IRegistryHub::~IRegistryHub() = default;
+ IMutableRegistryHub::~IMutableRegistryHub() = default;
+}
+
+
+
+#include <algorithm>
+#include <cassert>
+#include <iomanip>
+
+namespace Catch {
+
+ ReporterConfig::ReporterConfig(
+ IConfig const* _fullConfig,
+ Detail::unique_ptr<IStream> _stream,
+ ColourMode colourMode,
+ std::map<std::string, std::string> customOptions ):
+ m_stream( CATCH_MOVE(_stream) ),
+ m_fullConfig( _fullConfig ),
+ m_colourMode( colourMode ),
+ m_customOptions( CATCH_MOVE( customOptions ) ) {}
+
+ Detail::unique_ptr<IStream> ReporterConfig::takeStream() && {
+ assert( m_stream );
+ return CATCH_MOVE( m_stream );
+ }
+ IConfig const * ReporterConfig::fullConfig() const { return m_fullConfig; }
+ ColourMode ReporterConfig::colourMode() const { return m_colourMode; }
+
+ std::map<std::string, std::string> const&
+ ReporterConfig::customOptions() const {
+ return m_customOptions;
+ }
+
+ ReporterConfig::~ReporterConfig() = default;
+
+ AssertionStats::AssertionStats( AssertionResult const& _assertionResult,
+ std::vector<MessageInfo> const& _infoMessages,
+ Totals const& _totals )
+ : assertionResult( _assertionResult ),
+ infoMessages( _infoMessages ),
+ totals( _totals )
+ {
+ assertionResult.m_resultData.lazyExpression.m_transientExpression = _assertionResult.m_resultData.lazyExpression.m_transientExpression;
+
+ if( assertionResult.hasMessage() ) {
+ // Copy message into messages list.
+ // !TBD This should have been done earlier, somewhere
+ MessageBuilder builder( assertionResult.getTestMacroName(), assertionResult.getSourceInfo(), assertionResult.getResultType() );
+ builder << assertionResult.getMessage();
+ builder.m_info.message = builder.m_stream.str();
+
+ infoMessages.push_back( builder.m_info );
+ }
+ }
+
+ SectionStats::SectionStats( SectionInfo const& _sectionInfo,
+ Counts const& _assertions,
+ double _durationInSeconds,
+ bool _missingAssertions )
+ : sectionInfo( _sectionInfo ),
+ assertions( _assertions ),
+ durationInSeconds( _durationInSeconds ),
+ missingAssertions( _missingAssertions )
+ {}
+
+
+ TestCaseStats::TestCaseStats( TestCaseInfo const& _testInfo,
+ Totals const& _totals,
+ std::string const& _stdOut,
+ std::string const& _stdErr,
+ bool _aborting )
+ : testInfo( &_testInfo ),
+ totals( _totals ),
+ stdOut( _stdOut ),
+ stdErr( _stdErr ),
+ aborting( _aborting )
+ {}
+
+
+ TestRunStats::TestRunStats( TestRunInfo const& _runInfo,
+ Totals const& _totals,
+ bool _aborting )
+ : runInfo( _runInfo ),
+ totals( _totals ),
+ aborting( _aborting )
+ {}
+
+ IEventListener::~IEventListener() = default;
+
+} // end namespace Catch
+
+
+
+
+namespace Catch {
+ IReporterFactory::~IReporterFactory() = default;
+ EventListenerFactory::~EventListenerFactory() = default;
+}
+
+
+
+
+namespace Catch {
+ IReporterRegistry::~IReporterRegistry() = default;
+}
+
+
+
+
+namespace Catch {
+ ITestInvoker::~ITestInvoker() = default;
+ ITestCaseRegistry::~ITestCaseRegistry() = default;
+}
+
+
+
+namespace Catch {
+
+ AssertionHandler::AssertionHandler
+ ( StringRef macroName,
+ SourceLineInfo const& lineInfo,
+ StringRef capturedExpression,
+ ResultDisposition::Flags resultDisposition )
+ : m_assertionInfo{ macroName, lineInfo, capturedExpression, resultDisposition },
+ m_resultCapture( getResultCapture() )
+ {}
+
+ void AssertionHandler::handleExpr( ITransientExpression const& expr ) {
+ m_resultCapture.handleExpr( m_assertionInfo, expr, m_reaction );
+ }
+ void AssertionHandler::handleMessage(ResultWas::OfType resultType, StringRef message) {
+ m_resultCapture.handleMessage( m_assertionInfo, resultType, message, m_reaction );
+ }
+
+ auto AssertionHandler::allowThrows() const -> bool {
+ return getCurrentContext().getConfig()->allowThrows();
+ }
+
+ void AssertionHandler::complete() {
+ setCompleted();
+ if( m_reaction.shouldDebugBreak ) {
+
+ // If you find your debugger stopping you here then go one level up on the
+ // call-stack for the code that caused it (typically a failed assertion)
+
+ // (To go back to the test and change execution, jump over the throw, next)
+ CATCH_BREAK_INTO_DEBUGGER();
+ }
+ if (m_reaction.shouldThrow) {
+#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
+ throw Catch::TestFailureException();
+#else
+ CATCH_ERROR( "Test failure requires aborting test!" );
+#endif
+ }
+ }
+ void AssertionHandler::setCompleted() {
+ m_completed = true;
+ }
+
+ void AssertionHandler::handleUnexpectedInflightException() {
+ m_resultCapture.handleUnexpectedInflightException( m_assertionInfo, Catch::translateActiveException(), m_reaction );
+ }
+
+ void AssertionHandler::handleExceptionThrownAsExpected() {
+ m_resultCapture.handleNonExpr(m_assertionInfo, ResultWas::Ok, m_reaction);
+ }
+ void AssertionHandler::handleExceptionNotThrownAsExpected() {
+ m_resultCapture.handleNonExpr(m_assertionInfo, ResultWas::Ok, m_reaction);
+ }
+
+ void AssertionHandler::handleUnexpectedExceptionNotThrown() {
+ m_resultCapture.handleUnexpectedExceptionNotThrown( m_assertionInfo, m_reaction );
+ }
+
+ void AssertionHandler::handleThrowingCallSkipped() {
+ m_resultCapture.handleNonExpr(m_assertionInfo, ResultWas::Ok, m_reaction);
+ }
+
+ // This is the overload that takes a string and infers the Equals matcher from it
+ // The more general overload, that takes any string matcher, is in catch_capture_matchers.cpp
+ void handleExceptionMatchExpr( AssertionHandler& handler, std::string const& str, StringRef matcherString ) {
+ handleExceptionMatchExpr( handler, Matchers::Equals( str ), matcherString );
+ }
+
+} // namespace Catch
+
+
+
+
+#include <algorithm>
+
+namespace Catch {
+ namespace Detail {
+
+ bool CaseInsensitiveLess::operator()( StringRef lhs,
+ StringRef rhs ) const {
+ return std::lexicographical_compare(
+ lhs.begin(), lhs.end(),
+ rhs.begin(), rhs.end(),
+ []( char l, char r ) { return toLower( l ) < toLower( r ); } );
+ }
+
+ bool
+ CaseInsensitiveEqualTo::operator()( StringRef lhs,
+ StringRef rhs ) const {
+ return std::equal(
+ lhs.begin(), lhs.end(),
+ rhs.begin(), rhs.end(),
+ []( char l, char r ) { return toLower( l ) == toLower( r ); } );
+ }
+
+ } // namespace Detail
+} // namespace Catch
+
+
+
+
+#include <algorithm>
+#include <ostream>
+
+namespace {
+ bool isOptPrefix( char c ) {
+ return c == '-'
+#ifdef CATCH_PLATFORM_WINDOWS
+ || c == '/'
+#endif
+ ;
+ }
+
+ std::string normaliseOpt( std::string const& optName ) {
+#ifdef CATCH_PLATFORM_WINDOWS
+ if ( optName[0] == '/' )
+ return "-" + optName.substr( 1 );
+ else
+#endif
+ return optName;
+ }
+
+} // namespace
+
+namespace Catch {
+ namespace Clara {
+ namespace Detail {
+
+ void TokenStream::loadBuffer() {
+ m_tokenBuffer.clear();
+
+ // Skip any empty strings
+ while ( it != itEnd && it->empty() ) {
+ ++it;
+ }
+
+ if ( it != itEnd ) {
+ auto const& next = *it;
+ if ( isOptPrefix( next[0] ) ) {
+ auto delimiterPos = next.find_first_of( " :=" );
+ if ( delimiterPos != std::string::npos ) {
+ m_tokenBuffer.push_back(
+ { TokenType::Option,
+ next.substr( 0, delimiterPos ) } );
+ m_tokenBuffer.push_back(
+ { TokenType::Argument,
+ next.substr( delimiterPos + 1 ) } );
+ } else {
+ if ( next[1] != '-' && next.size() > 2 ) {
+ std::string opt = "- ";
+ for ( size_t i = 1; i < next.size(); ++i ) {
+ opt[1] = next[i];
+ m_tokenBuffer.push_back(
+ { TokenType::Option, opt } );
+ }
+ } else {
+ m_tokenBuffer.push_back(
+ { TokenType::Option, next } );
+ }
+ }
+ } else {
+ m_tokenBuffer.push_back(
+ { TokenType::Argument, next } );
+ }
+ }
+ }
+
+ TokenStream::TokenStream( Args const& args ):
+ TokenStream( args.m_args.begin(), args.m_args.end() ) {}
+
+ TokenStream::TokenStream( Iterator it_, Iterator itEnd_ ):
+ it( it_ ), itEnd( itEnd_ ) {
+ loadBuffer();
+ }
+
+ TokenStream& TokenStream::operator++() {
+ if ( m_tokenBuffer.size() >= 2 ) {
+ m_tokenBuffer.erase( m_tokenBuffer.begin() );
+ } else {
+ if ( it != itEnd )
+ ++it;
+ loadBuffer();
+ }
+ return *this;
+ }
+
+ ParserResult convertInto( std::string const& source,
+ std::string& target ) {
+ target = source;
+ return ParserResult::ok( ParseResultType::Matched );
+ }
+
+ ParserResult convertInto( std::string const& source,
+ bool& target ) {
+ std::string srcLC = toLower( source );
+
+ if ( srcLC == "y" || srcLC == "1" || srcLC == "true" ||
+ srcLC == "yes" || srcLC == "on" ) {
+ target = true;
+ } else if ( srcLC == "n" || srcLC == "0" || srcLC == "false" ||
+ srcLC == "no" || srcLC == "off" ) {
+ target = false;
+ } else {
+ return ParserResult::runtimeError(
+ "Expected a boolean value but did not recognise: '" +
+ source + '\'' );
+ }
+ return ParserResult::ok( ParseResultType::Matched );
+ }
+
+ size_t ParserBase::cardinality() const { return 1; }
+
+ InternalParseResult ParserBase::parse( Args const& args ) const {
+ return parse( args.exeName(), TokenStream( args ) );
+ }
+
+ ParseState::ParseState( ParseResultType type,
+ TokenStream const& remainingTokens ):
+ m_type( type ), m_remainingTokens( remainingTokens ) {}
+
+ ParserResult BoundFlagRef::setFlag( bool flag ) {
+ m_ref = flag;
+ return ParserResult::ok( ParseResultType::Matched );
+ }
+
+ ResultBase::~ResultBase() = default;
+
+ bool BoundRef::isContainer() const { return false; }
+
+ bool BoundRef::isFlag() const { return false; }
+
+ bool BoundFlagRefBase::isFlag() const { return true; }
+
+} // namespace Detail
+
+ Detail::InternalParseResult Arg::parse(std::string const&,
+ Detail::TokenStream const& tokens) const {
+ auto validationResult = validate();
+ if (!validationResult)
+ return Detail::InternalParseResult(validationResult);
+
+ auto remainingTokens = tokens;
+ auto const& token = *remainingTokens;
+ if (token.type != Detail::TokenType::Argument)
+ return Detail::InternalParseResult::ok(Detail::ParseState(
+ ParseResultType::NoMatch, remainingTokens));
+
+ assert(!m_ref->isFlag());
+ auto valueRef =
+ static_cast<Detail::BoundValueRefBase*>(m_ref.get());
+
+ auto result = valueRef->setValue(remainingTokens->token);
+ if (!result)
+ return Detail::InternalParseResult(result);
+ else
+ return Detail::InternalParseResult::ok(Detail::ParseState(
+ ParseResultType::Matched, ++remainingTokens));
+ }
+
+ Opt::Opt(bool& ref) :
+ ParserRefImpl(std::make_shared<Detail::BoundFlagRef>(ref)) {}
+
+ std::vector<Detail::HelpColumns> Opt::getHelpColumns() const {
+ std::ostringstream oss;
+ bool first = true;
+ for (auto const& opt : m_optNames) {
+ if (first)
+ first = false;
+ else
+ oss << ", ";
+ oss << opt;
+ }
+ if (!m_hint.empty())
+ oss << " <" << m_hint << '>';
+ return { { oss.str(), m_description } };
+ }
+
+ bool Opt::isMatch(std::string const& optToken) const {
+ auto normalisedToken = normaliseOpt(optToken);
+ for (auto const& name : m_optNames) {
+ if (normaliseOpt(name) == normalisedToken)
+ return true;
+ }
+ return false;
+ }
+
+ Detail::InternalParseResult Opt::parse(std::string const&,
+ Detail::TokenStream const& tokens) const {
+ auto validationResult = validate();
+ if (!validationResult)
+ return Detail::InternalParseResult(validationResult);
+
+ auto remainingTokens = tokens;
+ if (remainingTokens &&
+ remainingTokens->type == Detail::TokenType::Option) {
+ auto const& token = *remainingTokens;
+ if (isMatch(token.token)) {
+ if (m_ref->isFlag()) {
+ auto flagRef =
+ static_cast<Detail::BoundFlagRefBase*>(
+ m_ref.get());
+ auto result = flagRef->setFlag(true);
+ if (!result)
+ return Detail::InternalParseResult(result);
+ if (result.value() ==
+ ParseResultType::ShortCircuitAll)
+ return Detail::InternalParseResult::ok(Detail::ParseState(
+ result.value(), remainingTokens));
+ } else {
+ auto valueRef =
+ static_cast<Detail::BoundValueRefBase*>(
+ m_ref.get());
+ ++remainingTokens;
+ if (!remainingTokens)
+ return Detail::InternalParseResult::runtimeError(
+ "Expected argument following " +
+ token.token);
+ auto const& argToken = *remainingTokens;
+ if (argToken.type != Detail::TokenType::Argument)
+ return Detail::InternalParseResult::runtimeError(
+ "Expected argument following " +
+ token.token);
+ const auto result = valueRef->setValue(argToken.token);
+ if (!result)
+ return Detail::InternalParseResult(result);
+ if (result.value() ==
+ ParseResultType::ShortCircuitAll)
+ return Detail::InternalParseResult::ok(Detail::ParseState(
+ result.value(), remainingTokens));
+ }
+ return Detail::InternalParseResult::ok(Detail::ParseState(
+ ParseResultType::Matched, ++remainingTokens));
+ }
+ }
+ return Detail::InternalParseResult::ok(
+ Detail::ParseState(ParseResultType::NoMatch, remainingTokens));
+ }
+
+ Detail::Result Opt::validate() const {
+ if (m_optNames.empty())
+ return Detail::Result::logicError("No options supplied to Opt");
+ for (auto const& name : m_optNames) {
+ if (name.empty())
+ return Detail::Result::logicError(
+ "Option name cannot be empty");
+#ifdef CATCH_PLATFORM_WINDOWS
+ if (name[0] != '-' && name[0] != '/')
+ return Detail::Result::logicError(
+ "Option name must begin with '-' or '/'");
+#else
+ if (name[0] != '-')
+ return Detail::Result::logicError(
+ "Option name must begin with '-'");
+#endif
+ }
+ return ParserRefImpl::validate();
+ }
+
+ ExeName::ExeName() :
+ m_name(std::make_shared<std::string>("<executable>")) {}
+
+ ExeName::ExeName(std::string& ref) : ExeName() {
+ m_ref = std::make_shared<Detail::BoundValueRef<std::string>>(ref);
+ }
+
+ Detail::InternalParseResult
+ ExeName::parse(std::string const&,
+ Detail::TokenStream const& tokens) const {
+ return Detail::InternalParseResult::ok(
+ Detail::ParseState(ParseResultType::NoMatch, tokens));
+ }
+
+ ParserResult ExeName::set(std::string const& newName) {
+ auto lastSlash = newName.find_last_of("\\/");
+ auto filename = (lastSlash == std::string::npos)
+ ? newName
+ : newName.substr(lastSlash + 1);
+
+ *m_name = filename;
+ if (m_ref)
+ return m_ref->setValue(filename);
+ else
+ return ParserResult::ok(ParseResultType::Matched);
+ }
+
+
+
+
+ Parser& Parser::operator|=( Parser const& other ) {
+ m_options.insert( m_options.end(),
+ other.m_options.begin(),
+ other.m_options.end() );
+ m_args.insert(
+ m_args.end(), other.m_args.begin(), other.m_args.end() );
+ return *this;
+ }
+
+ std::vector<Detail::HelpColumns> Parser::getHelpColumns() const {
+ std::vector<Detail::HelpColumns> cols;
+ for ( auto const& o : m_options ) {
+ auto childCols = o.getHelpColumns();
+ cols.insert( cols.end(), childCols.begin(), childCols.end() );
+ }
+ return cols;
+ }
+
+ void Parser::writeToStream( std::ostream& os ) const {
+ if ( !m_exeName.name().empty() ) {
+ os << "usage:\n"
+ << " " << m_exeName.name() << ' ';
+ bool required = true, first = true;
+ for ( auto const& arg : m_args ) {
+ if ( first )
+ first = false;
+ else
+ os << ' ';
+ if ( arg.isOptional() && required ) {
+ os << '[';
+ required = false;
+ }
+ os << '<' << arg.hint() << '>';
+ if ( arg.cardinality() == 0 )
+ os << " ... ";
+ }
+ if ( !required )
+ os << ']';
+ if ( !m_options.empty() )
+ os << " options";
+ os << "\n\nwhere options are:\n";
+ }
+
+ auto rows = getHelpColumns();
+ size_t consoleWidth = CATCH_CONFIG_CONSOLE_WIDTH;
+ size_t optWidth = 0;
+ for ( auto const& cols : rows )
+ optWidth = ( std::max )( optWidth, cols.left.size() + 2 );
+
+ optWidth = ( std::min )( optWidth, consoleWidth / 2 );
+
+ for ( auto const& cols : rows ) {
+ auto row = TextFlow::Column( cols.left )
+ .width( optWidth )
+ .indent( 2 ) +
+ TextFlow::Spacer( 4 ) +
+ TextFlow::Column( cols.right )
+ .width( consoleWidth - 7 - optWidth );
+ os << row << '\n';
+ }
+ }
+
+ Detail::Result Parser::validate() const {
+ for ( auto const& opt : m_options ) {
+ auto result = opt.validate();
+ if ( !result )
+ return result;
+ }
+ for ( auto const& arg : m_args ) {
+ auto result = arg.validate();
+ if ( !result )
+ return result;
+ }
+ return Detail::Result::ok();
+ }
+
+ Detail::InternalParseResult
+ Parser::parse( std::string const& exeName,
+ Detail::TokenStream const& tokens ) const {
+
+ struct ParserInfo {
+ ParserBase const* parser = nullptr;
+ size_t count = 0;
+ };
+ std::vector<ParserInfo> parseInfos;
+ parseInfos.reserve( m_options.size() + m_args.size() );
+ for ( auto const& opt : m_options ) {
+ parseInfos.push_back( { &opt, 0 } );
+ }
+ for ( auto const& arg : m_args ) {
+ parseInfos.push_back( { &arg, 0 } );
+ }
+
+ m_exeName.set( exeName );
+
+ auto result = Detail::InternalParseResult::ok(
+ Detail::ParseState( ParseResultType::NoMatch, tokens ) );
+ while ( result.value().remainingTokens() ) {
+ bool tokenParsed = false;
+
+ for ( auto& parseInfo : parseInfos ) {
+ if ( parseInfo.parser->cardinality() == 0 ||
+ parseInfo.count < parseInfo.parser->cardinality() ) {
+ result = parseInfo.parser->parse(
+ exeName, result.value().remainingTokens() );
+ if ( !result )
+ return result;
+ if ( result.value().type() !=
+ ParseResultType::NoMatch ) {
+ tokenParsed = true;
+ ++parseInfo.count;
+ break;
+ }
+ }
+ }
+
+ if ( result.value().type() == ParseResultType::ShortCircuitAll )
+ return result;
+ if ( !tokenParsed )
+ return Detail::InternalParseResult::runtimeError(
+ "Unrecognised token: " +
+ result.value().remainingTokens()->token );
+ }
+ // !TBD Check missing required options
+ return result;
+ }
+
+ Args::Args(int argc, char const* const* argv) :
+ m_exeName(argv[0]), m_args(argv + 1, argv + argc) {}
+
+ Args::Args(std::initializer_list<std::string> args) :
+ m_exeName(*args.begin()),
+ m_args(args.begin() + 1, args.end()) {}
+
+
+ Help::Help( bool& showHelpFlag ):
+ Opt( [&]( bool flag ) {
+ showHelpFlag = flag;
+ return ParserResult::ok( ParseResultType::ShortCircuitAll );
+ } ) {
+ static_cast<Opt&> ( *this )(
+ "display usage information" )["-?"]["-h"]["--help"]
+ .optional();
+ }
+
+ } // namespace Clara
+} // namespace Catch
+
+
+
+
+#include <fstream>
+#include <string>
+
+namespace Catch {
+
+ Clara::Parser makeCommandLineParser( ConfigData& config ) {
+
+ using namespace Clara;
+
+ auto const setWarning = [&]( std::string const& warning ) {
+ if ( warning == "NoAssertions" ) {
+ config.warnings = static_cast<WarnAbout::What>(config.warnings | WarnAbout::NoAssertions);
+ return ParserResult::ok( ParseResultType::Matched );
+ } else if ( warning == "UnmatchedTestSpec" ) {
+ config.warnings = static_cast<WarnAbout::What>(config.warnings | WarnAbout::UnmatchedTestSpec);
+ return ParserResult::ok( ParseResultType::Matched );
+ }
+
+ return ParserResult ::runtimeError(
+ "Unrecognised warning option: '" + warning + '\'' );
+ };
+ auto const loadTestNamesFromFile = [&]( std::string const& filename ) {
+ std::ifstream f( filename.c_str() );
+ if( !f.is_open() )
+ return ParserResult::runtimeError( "Unable to load input file: '" + filename + '\'' );
+
+ std::string line;
+ while( std::getline( f, line ) ) {
+ line = trim(line);
+ if( !line.empty() && !startsWith( line, '#' ) ) {
+ if( !startsWith( line, '"' ) )
+ line = '"' + line + '"';
+ config.testsOrTags.push_back( line );
+ config.testsOrTags.emplace_back( "," );
+ }
+ }
+ //Remove comma in the end
+ if(!config.testsOrTags.empty())
+ config.testsOrTags.erase( config.testsOrTags.end()-1 );
+
+ return ParserResult::ok( ParseResultType::Matched );
+ };
+ auto const setTestOrder = [&]( std::string const& order ) {
+ if( startsWith( "declared", order ) )
+ config.runOrder = TestRunOrder::Declared;
+ else if( startsWith( "lexical", order ) )
+ config.runOrder = TestRunOrder::LexicographicallySorted;
+ else if( startsWith( "random", order ) )
+ config.runOrder = TestRunOrder::Randomized;
+ else
+ return ParserResult::runtimeError( "Unrecognised ordering: '" + order + '\'' );
+ return ParserResult::ok( ParseResultType::Matched );
+ };
+ auto const setRngSeed = [&]( std::string const& seed ) {
+ if( seed == "time" ) {
+ config.rngSeed = generateRandomSeed(GenerateFrom::Time);
+ return ParserResult::ok(ParseResultType::Matched);
+ } else if (seed == "random-device") {
+ config.rngSeed = generateRandomSeed(GenerateFrom::RandomDevice);
+ return ParserResult::ok(ParseResultType::Matched);
+ }
+
+ CATCH_TRY {
+ std::size_t parsedTo = 0;
+ unsigned long parsedSeed = std::stoul(seed, &parsedTo, 0);
+ if (parsedTo != seed.size()) {
+ return ParserResult::runtimeError("Could not parse '" + seed + "' as seed");
+ }
+
+ // TODO: Ideally we could parse unsigned int directly,
+ // but the stdlib doesn't provide helper for that
+ // type. After this is refactored to use fixed size
+ // type, we should check the parsed value is in range
+ // of the underlying type.
+ config.rngSeed = static_cast<unsigned int>(parsedSeed);
+ return ParserResult::ok(ParseResultType::Matched);
+ } CATCH_CATCH_ANON(std::exception const&) {
+ return ParserResult::runtimeError("Could not parse '" + seed + "' as seed");
+ }
+ };
+ auto const setDefaultColourMode = [&]( std::string const& colourMode ) {
+ Optional<ColourMode> maybeMode = Catch::Detail::stringToColourMode(toLower( colourMode ));
+ if ( !maybeMode ) {
+ return ParserResult::runtimeError(
+ "colour mode must be one of: default, ansi, win32, "
+ "or none. '" +
+ colourMode + "' is not recognised" );
+ }
+ auto mode = *maybeMode;
+ if ( !isColourImplAvailable( mode ) ) {
+ return ParserResult::runtimeError(
+ "colour mode '" + colourMode +
+ "' is not supported in this binary" );
+ }
+ config.defaultColourMode = mode;
+ return ParserResult::ok( ParseResultType::Matched );
+ };
+ auto const setWaitForKeypress = [&]( std::string const& keypress ) {
+ auto keypressLc = toLower( keypress );
+ if (keypressLc == "never")
+ config.waitForKeypress = WaitForKeypress::Never;
+ else if( keypressLc == "start" )
+ config.waitForKeypress = WaitForKeypress::BeforeStart;
+ else if( keypressLc == "exit" )
+ config.waitForKeypress = WaitForKeypress::BeforeExit;
+ else if( keypressLc == "both" )
+ config.waitForKeypress = WaitForKeypress::BeforeStartAndExit;
+ else
+ return ParserResult::runtimeError( "keypress argument must be one of: never, start, exit or both. '" + keypress + "' not recognised" );
+ return ParserResult::ok( ParseResultType::Matched );
+ };
+ auto const setVerbosity = [&]( std::string const& verbosity ) {
+ auto lcVerbosity = toLower( verbosity );
+ if( lcVerbosity == "quiet" )
+ config.verbosity = Verbosity::Quiet;
+ else if( lcVerbosity == "normal" )
+ config.verbosity = Verbosity::Normal;
+ else if( lcVerbosity == "high" )
+ config.verbosity = Verbosity::High;
+ else
+ return ParserResult::runtimeError( "Unrecognised verbosity, '" + verbosity + '\'' );
+ return ParserResult::ok( ParseResultType::Matched );
+ };
+ auto const setReporter = [&]( std::string const& userReporterSpec ) {
+ if ( userReporterSpec.empty() ) {
+ return ParserResult::runtimeError( "Received empty reporter spec." );
+ }
+
+ Optional<ReporterSpec> parsed =
+ parseReporterSpec( userReporterSpec );
+ if ( !parsed ) {
+ return ParserResult::runtimeError(
+ "Could not parse reporter spec '" + userReporterSpec +
+ "'" );
+ }
+
+ auto const& reporterSpec = *parsed;
+
+ IReporterRegistry::FactoryMap const& factories =
+ getRegistryHub().getReporterRegistry().getFactories();
+ auto result = factories.find( reporterSpec.name() );
+
+ if ( result == factories.end() ) {
+ return ParserResult::runtimeError(
+ "Unrecognized reporter, '" + reporterSpec.name() +
+ "'. Check available with --list-reporters" );
+ }
+
+
+ const bool hadOutputFile = reporterSpec.outputFile().some();
+ config.reporterSpecifications.push_back( CATCH_MOVE( *parsed ) );
+ // It would be enough to check this only once at the very end, but
+ // there is not a place where we could call this check, so do it
+ // every time it could fail. For valid inputs, this is still called
+ // at most once.
+ if (!hadOutputFile) {
+ int n_reporters_without_file = 0;
+ for (auto const& spec : config.reporterSpecifications) {
+ if (spec.outputFile().none()) {
+ n_reporters_without_file++;
+ }
+ }
+ if (n_reporters_without_file > 1) {
+ return ParserResult::runtimeError( "Only one reporter may have unspecified output file." );
+ }
+ }
+
+ return ParserResult::ok( ParseResultType::Matched );
+ };
+ auto const setShardCount = [&]( std::string const& shardCount ) {
+ CATCH_TRY{
+ std::size_t parsedTo = 0;
+ int64_t parsedCount = std::stoll(shardCount, &parsedTo, 0);
+ if (parsedTo != shardCount.size()) {
+ return ParserResult::runtimeError("Could not parse '" + shardCount + "' as shard count");
+ }
+ if (parsedCount <= 0) {
+ return ParserResult::runtimeError("Shard count must be a positive number");
+ }
+
+ config.shardCount = static_cast<unsigned int>(parsedCount);
+ return ParserResult::ok(ParseResultType::Matched);
+ } CATCH_CATCH_ANON(std::exception const&) {
+ return ParserResult::runtimeError("Could not parse '" + shardCount + "' as shard count");
+ }
+ };
+
+ auto const setShardIndex = [&](std::string const& shardIndex) {
+ CATCH_TRY{
+ std::size_t parsedTo = 0;
+ int64_t parsedIndex = std::stoll(shardIndex, &parsedTo, 0);
+ if (parsedTo != shardIndex.size()) {
+ return ParserResult::runtimeError("Could not parse '" + shardIndex + "' as shard index");
+ }
+ if (parsedIndex < 0) {
+ return ParserResult::runtimeError("Shard index must be a non-negative number");
+ }
+
+ config.shardIndex = static_cast<unsigned int>(parsedIndex);
+ return ParserResult::ok(ParseResultType::Matched);
+ } CATCH_CATCH_ANON(std::exception const&) {
+ return ParserResult::runtimeError("Could not parse '" + shardIndex + "' as shard index");
+ }
+ };
+
+
+ auto cli
+ = ExeName( config.processName )
+ | Help( config.showHelp )
+ | Opt( config.showSuccessfulTests )
+ ["-s"]["--success"]
+ ( "include successful tests in output" )
+ | Opt( config.shouldDebugBreak )
+ ["-b"]["--break"]
+ ( "break into debugger on failure" )
+ | Opt( config.noThrow )
+ ["-e"]["--nothrow"]
+ ( "skip exception tests" )
+ | Opt( config.showInvisibles )
+ ["-i"]["--invisibles"]
+ ( "show invisibles (tabs, newlines)" )
+ | Opt( config.defaultOutputFilename, "filename" )
+ ["-o"]["--out"]
+ ( "default output filename" )
+ | Opt( accept_many, setReporter, "name[::key=value]*" )
+ ["-r"]["--reporter"]
+ ( "reporter to use (defaults to console)" )
+ | Opt( config.name, "name" )
+ ["-n"]["--name"]
+ ( "suite name" )
+ | Opt( [&]( bool ){ config.abortAfter = 1; } )
+ ["-a"]["--abort"]
+ ( "abort at first failure" )
+ | Opt( [&]( int x ){ config.abortAfter = x; }, "no. failures" )
+ ["-x"]["--abortx"]
+ ( "abort after x failures" )
+ | Opt( accept_many, setWarning, "warning name" )
+ ["-w"]["--warn"]
+ ( "enable warnings" )
+ | Opt( [&]( bool flag ) { config.showDurations = flag ? ShowDurations::Always : ShowDurations::Never; }, "yes|no" )
+ ["-d"]["--durations"]
+ ( "show test durations" )
+ | Opt( config.minDuration, "seconds" )
+ ["-D"]["--min-duration"]
+ ( "show test durations for tests taking at least the given number of seconds" )
+ | Opt( loadTestNamesFromFile, "filename" )
+ ["-f"]["--input-file"]
+ ( "load test names to run from a file" )
+ | Opt( config.filenamesAsTags )
+ ["-#"]["--filenames-as-tags"]
+ ( "adds a tag for the filename" )
+ | Opt( config.sectionsToRun, "section name" )
+ ["-c"]["--section"]
+ ( "specify section to run" )
+ | Opt( setVerbosity, "quiet|normal|high" )
+ ["-v"]["--verbosity"]
+ ( "set output verbosity" )
+ | Opt( config.listTests )
+ ["--list-tests"]
+ ( "list all/matching test cases" )
+ | Opt( config.listTags )
+ ["--list-tags"]
+ ( "list all/matching tags" )
+ | Opt( config.listReporters )
+ ["--list-reporters"]
+ ( "list all available reporters" )
+ | Opt( config.listListeners )
+ ["--list-listeners"]
+ ( "list all listeners" )
+ | Opt( setTestOrder, "decl|lex|rand" )
+ ["--order"]
+ ( "test case order (defaults to decl)" )
+ | Opt( setRngSeed, "'time'|'random-device'|number" )
+ ["--rng-seed"]
+ ( "set a specific seed for random numbers" )
+ | Opt( setDefaultColourMode, "ansi|win32|none|default" )
+ ["--colour-mode"]
+ ( "what color mode should be used as default" )
+ | Opt( config.libIdentify )
+ ["--libidentify"]
+ ( "report name and version according to libidentify standard" )
+ | 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)" )
+ | Opt( config.benchmarkResamples, "resamples" )
+ ["--benchmark-resamples"]
+ ( "number of resamples for the bootstrap (default: 100000)" )
+ | Opt( config.benchmarkConfidenceInterval, "confidence interval" )
+ ["--benchmark-confidence-interval"]
+ ( "confidence interval for the bootstrap (between 0 and 1, default: 0.95)" )
+ | Opt( config.benchmarkNoAnalysis )
+ ["--benchmark-no-analysis"]
+ ( "perform only measurements; do not perform any analysis" )
+ | Opt( config.benchmarkWarmupTime, "benchmarkWarmupTime" )
+ ["--benchmark-warmup-time"]
+ ( "amount of time in milliseconds spent on warming up each test (default: 100)" )
+ | Opt( setShardCount, "shard count" )
+ ["--shard-count"]
+ ( "split the tests to execute into this many groups" )
+ | Opt( setShardIndex, "shard index" )
+ ["--shard-index"]
+ ( "index of the group of tests to execute (see --shard-count)" ) |
+ Opt( config.allowZeroTests )
+ ["--allow-running-no-tests"]
+ ( "Treat 'No tests run' as a success" )
+ | Arg( config.testsOrTags, "test name|pattern|tags" )
+ ( "which test or tests to use" );
+
+ return cli;
+ }
+
+} // end namespace Catch
+
+
+#if defined(__clang__)
+# pragma clang diagnostic push
+# pragma clang diagnostic ignored "-Wexit-time-destructors"
+#endif
+
+
+
+#include <cassert>
+#include <ostream>
+#include <utility>
+
+namespace Catch {
+
+ ColourImpl::~ColourImpl() = default;
+
+ ColourImpl::ColourGuard ColourImpl::guardColour( Colour::Code colourCode ) {
+ return ColourGuard(colourCode, this );
+ }
+
+ void ColourImpl::ColourGuard::engageImpl( std::ostream& stream ) {
+ assert( &stream == &m_colourImpl->m_stream->stream() &&
+ "Engaging colour guard for different stream than used by the "
+ "parent colour implementation" );
+ static_cast<void>( stream );
+
+ m_engaged = true;
+ m_colourImpl->use( m_code );
+ }
+
+ ColourImpl::ColourGuard::ColourGuard( Colour::Code code,
+ ColourImpl const* colour ):
+ m_colourImpl( colour ), m_code( code ) {
+ }
+ ColourImpl::ColourGuard::ColourGuard( ColourGuard&& rhs ) noexcept:
+ m_colourImpl( rhs.m_colourImpl ),
+ m_code( rhs.m_code ),
+ m_engaged( rhs.m_engaged ) {
+ rhs.m_engaged = false;
+ }
+ ColourImpl::ColourGuard&
+ ColourImpl::ColourGuard::operator=( ColourGuard&& rhs ) noexcept {
+ using std::swap;
+ swap( m_colourImpl, rhs.m_colourImpl );
+ swap( m_code, rhs.m_code );
+ swap( m_engaged, rhs.m_engaged );
+
+ return *this;
+ }
+ ColourImpl::ColourGuard::~ColourGuard() {
+ if ( m_engaged ) {
+ m_colourImpl->use( Colour::None );
+ }
+ }
+
+ ColourImpl::ColourGuard&
+ ColourImpl::ColourGuard::engage( std::ostream& stream ) & {
+ engageImpl( stream );
+ return *this;
+ }
+
+ ColourImpl::ColourGuard&&
+ ColourImpl::ColourGuard::engage( std::ostream& stream ) && {
+ engageImpl( stream );
+ return CATCH_MOVE(*this);
+ }
+
+ namespace {
+ //! A do-nothing implementation of colour, used as fallback for unknown
+ //! platforms, and when the user asks to deactivate all colours.
+ class NoColourImpl : public ColourImpl {
+ public:
+ NoColourImpl( IStream* stream ): ColourImpl( stream ) {}
+
+ private:
+ void use( Colour::Code ) const override {}
+ };
+ } // namespace
+
+
+} // namespace Catch
+
+
+#if defined ( CATCH_CONFIG_COLOUR_WIN32 ) /////////////////////////////////////////
+
+namespace Catch {
+namespace {
+
+ class Win32ColourImpl : public ColourImpl {
+ public:
+ Win32ColourImpl(IStream* stream):
+ ColourImpl(stream) {
+ CONSOLE_SCREEN_BUFFER_INFO csbiInfo;
+ GetConsoleScreenBufferInfo( GetStdHandle( STD_OUTPUT_HANDLE ),
+ &csbiInfo );
+ originalForegroundAttributes = csbiInfo.wAttributes & ~( BACKGROUND_GREEN | BACKGROUND_RED | BACKGROUND_BLUE | BACKGROUND_INTENSITY );
+ originalBackgroundAttributes = csbiInfo.wAttributes & ~( FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_INTENSITY );
+ }
+
+ static bool useImplementationForStream(IStream const& stream) {
+ // Win32 text colour APIs can only be used on console streams
+ // We cannot check that the output hasn't been redirected,
+ // so we just check that the original stream is console stream.
+ return stream.isConsole();
+ }
+
+ private:
+ void use( Colour::Code _colourCode ) const override {
+ switch( _colourCode ) {
+ case Colour::None: return setTextAttribute( originalForegroundAttributes );
+ case Colour::White: return setTextAttribute( FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE );
+ case Colour::Red: return setTextAttribute( FOREGROUND_RED );
+ case Colour::Green: return setTextAttribute( FOREGROUND_GREEN );
+ case Colour::Blue: return setTextAttribute( FOREGROUND_BLUE );
+ case Colour::Cyan: return setTextAttribute( FOREGROUND_BLUE | FOREGROUND_GREEN );
+ case Colour::Yellow: return setTextAttribute( FOREGROUND_RED | FOREGROUND_GREEN );
+ case Colour::Grey: return setTextAttribute( 0 );
+
+ case Colour::LightGrey: return setTextAttribute( FOREGROUND_INTENSITY );
+ case Colour::BrightRed: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_RED );
+ case Colour::BrightGreen: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN );
+ case Colour::BrightWhite: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE );
+ case Colour::BrightYellow: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_GREEN );
+
+ case Colour::Bright: CATCH_INTERNAL_ERROR( "not a colour" );
+
+ default:
+ CATCH_ERROR( "Unknown colour requested" );
+ }
+ }
+
+ void setTextAttribute( WORD _textAttribute ) const {
+ SetConsoleTextAttribute( GetStdHandle( STD_OUTPUT_HANDLE ),
+ _textAttribute |
+ originalBackgroundAttributes );
+ }
+ WORD originalForegroundAttributes;
+ WORD originalBackgroundAttributes;
+ };
+
+} // end anon namespace
+} // end namespace Catch
+
+#endif // Windows/ ANSI/ None
+
+
+#if defined( CATCH_PLATFORM_LINUX ) || defined( CATCH_PLATFORM_MAC )
+# define CATCH_INTERNAL_HAS_ISATTY
+# include <unistd.h>
+#endif
+
+namespace Catch {
+namespace {
+
+ class ANSIColourImpl : public ColourImpl {
+ public:
+ ANSIColourImpl( IStream* stream ): ColourImpl( stream ) {}
+
+ static bool useImplementationForStream(IStream const& stream) {
+ // This is kinda messy due to trying to support a bunch of
+ // different platforms at once.
+ // The basic idea is that if we are asked to do autodetection (as
+ // opposed to being told to use posixy colours outright), then we
+ // only want to use the colours if we are writing to console.
+ // However, console might be redirected, so we make an attempt at
+ // checking for that on platforms where we know how to do that.
+ bool useColour = stream.isConsole();
+#if defined( CATCH_INTERNAL_HAS_ISATTY ) && \
+ !( defined( __DJGPP__ ) && defined( __STRICT_ANSI__ ) )
+ ErrnoGuard _; // for isatty
+ useColour = useColour && isatty( STDOUT_FILENO );
+# endif
+# if defined( CATCH_PLATFORM_MAC ) || defined( CATCH_PLATFORM_IPHONE )
+ useColour = useColour && !isDebuggerActive();
+# endif
+
+ return useColour;
+ }
+
+ private:
+ void use( Colour::Code _colourCode ) const override {
+ auto setColour = [&out =
+ m_stream->stream()]( char const* escapeCode ) {
+ // The escape sequence must be flushed to console, otherwise
+ // if stdin and stderr are intermixed, we'd get accidentally
+ // coloured output.
+ out << '\033' << escapeCode << std::flush;
+ };
+ switch( _colourCode ) {
+ case Colour::None:
+ case Colour::White: return setColour( "[0m" );
+ case Colour::Red: return setColour( "[0;31m" );
+ case Colour::Green: return setColour( "[0;32m" );
+ case Colour::Blue: return setColour( "[0;34m" );
+ case Colour::Cyan: return setColour( "[0;36m" );
+ case Colour::Yellow: return setColour( "[0;33m" );
+ case Colour::Grey: return setColour( "[1;30m" );
+
+ case Colour::LightGrey: return setColour( "[0;37m" );
+ case Colour::BrightRed: return setColour( "[1;31m" );
+ case Colour::BrightGreen: return setColour( "[1;32m" );
+ case Colour::BrightWhite: return setColour( "[1;37m" );
+ case Colour::BrightYellow: return setColour( "[1;33m" );
+
+ case Colour::Bright: CATCH_INTERNAL_ERROR( "not a colour" );
+ default: CATCH_INTERNAL_ERROR( "Unknown colour requested" );
+ }
+ }
+ };
+
+} // end anon namespace
+} // end namespace Catch
+
+namespace Catch {
+
+ Detail::unique_ptr<ColourImpl> makeColourImpl( ColourMode implSelection,
+ IStream* stream ) {
+#if defined( CATCH_CONFIG_COLOUR_WIN32 )
+ if ( implSelection == ColourMode::Win32 ) {
+ return Detail::make_unique<Win32ColourImpl>( stream );
+ }
+#endif
+ if ( implSelection == ColourMode::ANSI ) {
+ return Detail::make_unique<ANSIColourImpl>( stream );
+ }
+ if ( implSelection == ColourMode::None ) {
+ return Detail::make_unique<NoColourImpl>( stream );
+ }
+
+ if ( implSelection == ColourMode::PlatformDefault) {
+#if defined( CATCH_CONFIG_COLOUR_WIN32 )
+ if ( Win32ColourImpl::useImplementationForStream( *stream ) ) {
+ return Detail::make_unique<Win32ColourImpl>( stream );
+ }
+#endif
+ if ( ANSIColourImpl::useImplementationForStream( *stream ) ) {
+ return Detail::make_unique<ANSIColourImpl>( stream );
+ }
+ return Detail::make_unique<NoColourImpl>( stream );
+ }
+
+ CATCH_ERROR( "Could not create colour impl for selection " << static_cast<int>(implSelection) );
+ }
+
+ bool isColourImplAvailable( ColourMode colourSelection ) {
+ switch ( colourSelection ) {
+#if defined( CATCH_CONFIG_COLOUR_WIN32 )
+ case ColourMode::Win32:
+#endif
+ case ColourMode::ANSI:
+ case ColourMode::None:
+ case ColourMode::PlatformDefault:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+
+} // end namespace Catch
+
+#if defined(__clang__)
+# pragma clang diagnostic pop
+#endif
+
+
+
+
+namespace Catch {
+
+ class Context : public IMutableContext, private Detail::NonCopyable {
+
+ public: // IContext
+ IResultCapture* getResultCapture() override {
+ return m_resultCapture;
+ }
+
+ IConfig const* getConfig() const override {
+ return m_config;
+ }
+
+ ~Context() override;
+
+ public: // IMutableContext
+ void setResultCapture( IResultCapture* resultCapture ) override {
+ m_resultCapture = resultCapture;
+ }
+ void setConfig( IConfig const* config ) override {
+ m_config = config;
+ }
+
+ friend IMutableContext& getCurrentMutableContext();
+
+ private:
+ IConfig const* m_config = nullptr;
+ IResultCapture* m_resultCapture = nullptr;
+ };
+
+ IMutableContext *IMutableContext::currentContext = nullptr;
+
+ void IMutableContext::createContext()
+ {
+ currentContext = new Context();
+ }
+
+ void cleanUpContext() {
+ delete IMutableContext::currentContext;
+ IMutableContext::currentContext = nullptr;
+ }
+ IContext::~IContext() = default;
+ IMutableContext::~IMutableContext() = default;
+ Context::~Context() = default;
+
+
+ SimplePcg32& sharedRng() {
+ static SimplePcg32 s_rng;
+ return s_rng;
+ }
+
+}
+
+
+
+
+
+#include <ostream>
+
+#if defined(CATCH_CONFIG_ANDROID_LOGWRITE)
+#include <android/log.h>
+
+ namespace Catch {
+ void writeToDebugConsole( std::string const& text ) {
+ __android_log_write( ANDROID_LOG_DEBUG, "Catch", text.c_str() );
+ }
+ }
+
+#elif defined(CATCH_PLATFORM_WINDOWS)
+
+ namespace Catch {
+ void writeToDebugConsole( std::string const& text ) {
+ ::OutputDebugStringA( text.c_str() );
+ }
+ }
+
+#else
+
+ namespace Catch {
+ void writeToDebugConsole( std::string const& text ) {
+ // !TBD: Need a version for Mac/ XCode and other IDEs
+ Catch::cout() << text;
+ }
+ }
+
+#endif // Platform
+
+
+
+#if defined(CATCH_PLATFORM_MAC) || defined(CATCH_PLATFORM_IPHONE)
+
+# include <cassert>
+# include <sys/types.h>
+# include <unistd.h>
+# include <cstddef>
+# include <ostream>
+
+#ifdef __apple_build_version__
+ // These headers will only compile with AppleClang (XCode)
+ // For other compilers (Clang, GCC, ... ) we need to exclude them
+# include <sys/sysctl.h>
+#endif
+
+ namespace Catch {
+ #ifdef __apple_build_version__
+ // The following function is taken directly from the following technical note:
+ // https://developer.apple.com/library/archive/qa/qa1361/_index.html
+
+ // Returns true if the current process is being debugged (either
+ // running under the debugger or has a debugger attached post facto).
+ bool isDebuggerActive(){
+ int mib[4];
+ struct kinfo_proc info;
+ std::size_t size;
+
+ // Initialize the flags so that, if sysctl fails for some bizarre
+ // reason, we get a predictable result.
+
+ info.kp_proc.p_flag = 0;
+
+ // Initialize mib, which tells sysctl the info we want, in this case
+ // we're looking for information about a specific process ID.
+
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_PROC;
+ mib[2] = KERN_PROC_PID;
+ mib[3] = getpid();
+
+ // Call sysctl.
+
+ size = sizeof(info);
+ if( sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, nullptr, 0) != 0 ) {
+ Catch::cerr() << "\n** Call to sysctl failed - unable to determine if debugger is active **\n\n" << std::flush;
+ return false;
+ }
+
+ // We're being debugged if the P_TRACED flag is set.
+
+ return ( (info.kp_proc.p_flag & P_TRACED) != 0 );
+ }
+ #else
+ bool isDebuggerActive() {
+ // We need to find another way to determine this for non-appleclang compilers on macOS
+ return false;
+ }
+ #endif
+ } // namespace Catch
+
+#elif defined(CATCH_PLATFORM_LINUX)
+ #include <fstream>
+ #include <string>
+
+ namespace Catch{
+ // The standard POSIX way of detecting a debugger is to attempt to
+ // ptrace() the process, but this needs to be done from a child and not
+ // this process itself to still allow attaching to this process later
+ // if wanted, so is rather heavy. Under Linux we have the PID of the
+ // "debugger" (which doesn't need to be gdb, of course, it could also
+ // be strace, for example) in /proc/$PID/status, so just get it from
+ // there instead.
+ bool isDebuggerActive(){
+ // Libstdc++ has a bug, where std::ifstream sets errno to 0
+ // This way our users can properly assert over errno values
+ ErrnoGuard guard;
+ std::ifstream in("/proc/self/status");
+ for( std::string line; std::getline(in, line); ) {
+ static const int PREFIX_LEN = 11;
+ if( line.compare(0, PREFIX_LEN, "TracerPid:\t") == 0 ) {
+ // We're traced if the PID is not 0 and no other PID starts
+ // with 0 digit, so it's enough to check for just a single
+ // character.
+ return line.length() > PREFIX_LEN && line[PREFIX_LEN] != '0';
+ }
+ }
+
+ return false;
+ }
+ } // namespace Catch
+#elif defined(_MSC_VER)
+ extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent();
+ namespace Catch {
+ bool isDebuggerActive() {
+ return IsDebuggerPresent() != 0;
+ }
+ }
+#elif defined(__MINGW32__)
+ extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent();
+ namespace Catch {
+ bool isDebuggerActive() {
+ return IsDebuggerPresent() != 0;
+ }
+ }
+#else
+ namespace Catch {
+ bool isDebuggerActive() { return false; }
+ }
+#endif // Platform
+
+
+
+
+namespace Catch {
+
+ ITransientExpression::~ITransientExpression() = default;
+
+ void formatReconstructedExpression( std::ostream &os, std::string const& lhs, StringRef op, std::string const& rhs ) {
+ if( lhs.size() + rhs.size() < 40 &&
+ lhs.find('\n') == std::string::npos &&
+ rhs.find('\n') == std::string::npos )
+ os << lhs << ' ' << op << ' ' << rhs;
+ else
+ os << lhs << '\n' << op << '\n' << rhs;
+ }
+}
+
+
+
+#include <stdexcept>
+
+
+namespace Catch {
+#if defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) && !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS_CUSTOM_HANDLER)
+ [[noreturn]]
+ void throw_exception(std::exception const& e) {
+ Catch::cerr() << "Catch will terminate because it needed to throw an exception.\n"
+ << "The message was: " << e.what() << '\n';
+ std::terminate();
+ }
+#endif
+
+ [[noreturn]]
+ void throw_logic_error(std::string const& msg) {
+ throw_exception(std::logic_error(msg));
+ }
+
+ [[noreturn]]
+ void throw_domain_error(std::string const& msg) {
+ throw_exception(std::domain_error(msg));
+ }
+
+ [[noreturn]]
+ void throw_runtime_error(std::string const& msg) {
+ throw_exception(std::runtime_error(msg));
+ }
+
+
+
+} // namespace Catch;
+
+
+
+#include <cassert>
+
+namespace Catch {
+
+ IMutableEnumValuesRegistry::~IMutableEnumValuesRegistry() = default;
+
+ namespace Detail {
+
+ namespace {
+ // Extracts the actual name part of an enum instance
+ // In other words, it returns the Blue part of Bikeshed::Colour::Blue
+ StringRef extractInstanceName(StringRef enumInstance) {
+ // Find last occurrence of ":"
+ size_t name_start = enumInstance.size();
+ while (name_start > 0 && enumInstance[name_start - 1] != ':') {
+ --name_start;
+ }
+ return enumInstance.substr(name_start, enumInstance.size() - name_start);
+ }
+ }
+
+ std::vector<StringRef> parseEnums( StringRef enums ) {
+ auto enumValues = splitStringRef( enums, ',' );
+ std::vector<StringRef> parsed;
+ parsed.reserve( enumValues.size() );
+ for( auto const& enumValue : enumValues ) {
+ parsed.push_back(trim(extractInstanceName(enumValue)));
+ }
+ return parsed;
+ }
+
+ EnumInfo::~EnumInfo() {}
+
+ StringRef EnumInfo::lookup( int value ) const {
+ for( auto const& valueToName : m_values ) {
+ if( valueToName.first == value )
+ return valueToName.second;
+ }
+ return "{** unexpected enum value **}"_sr;
+ }
+
+ Catch::Detail::unique_ptr<EnumInfo> makeEnumInfo( StringRef enumName, StringRef allValueNames, std::vector<int> const& values ) {
+ auto enumInfo = Catch::Detail::make_unique<EnumInfo>();
+ enumInfo->m_name = enumName;
+ enumInfo->m_values.reserve( values.size() );
+
+ const auto valueNames = Catch::Detail::parseEnums( allValueNames );
+ assert( valueNames.size() == values.size() );
+ std::size_t i = 0;
+ for( auto value : values )
+ enumInfo->m_values.emplace_back(value, valueNames[i++]);
+
+ return enumInfo;
+ }
+
+ EnumInfo const& EnumValuesRegistry::registerEnum( StringRef enumName, StringRef allValueNames, std::vector<int> const& values ) {
+ m_enumInfos.push_back(makeEnumInfo(enumName, allValueNames, values));
+ return *m_enumInfos.back();
+ }
+
+ } // Detail
+} // Catch
+
+
+
+
+
+#include <cerrno>
+
+namespace Catch {
+ ErrnoGuard::ErrnoGuard():m_oldErrno(errno){}
+ ErrnoGuard::~ErrnoGuard() { errno = m_oldErrno; }
+}
+
+
+
+namespace Catch {
+
+ ExceptionTranslatorRegistry::~ExceptionTranslatorRegistry() {
+ }
+
+ void ExceptionTranslatorRegistry::registerTranslator( Detail::unique_ptr<IExceptionTranslator>&& translator ) {
+ m_translators.push_back( CATCH_MOVE( translator ) );
+ }
+
+#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
+ std::string ExceptionTranslatorRegistry::translateActiveException() const {
+ // Compiling a mixed mode project with MSVC means that CLR
+ // exceptions will be caught in (...) as well. However, these do
+ // do not fill-in std::current_exception and thus lead to crash
+ // when attempting rethrow.
+ // /EHa switch also causes structured exceptions to be caught
+ // here, but they fill-in current_exception properly, so
+ // at worst the output should be a little weird, instead of
+ // causing a crash.
+ if ( std::current_exception() == nullptr ) {
+ return "Non C++ exception. Possibly a CLR exception.";
+ }
+
+ // First we try user-registered translators. If none of them can
+ // handle the exception, it will be rethrown handled by our defaults.
+ try {
+ return tryTranslators();
+ }
+ // To avoid having to handle TFE explicitly everywhere, we just
+ // rethrow it so that it goes back up the caller.
+ catch( TestFailureException& ) {
+ std::rethrow_exception(std::current_exception());
+ }
+ catch( std::exception const& ex ) {
+ return ex.what();
+ }
+ catch( std::string const& msg ) {
+ return msg;
+ }
+ catch( const char* msg ) {
+ return msg;
+ }
+ catch(...) {
+ return "Unknown exception";
+ }
+ }
+
+ std::string ExceptionTranslatorRegistry::tryTranslators() const {
+ if (m_translators.empty()) {
+ std::rethrow_exception(std::current_exception());
+ } else {
+ return m_translators[0]->translate(m_translators.begin() + 1, m_translators.end());
+ }
+ }
+
+#else // ^^ Exceptions are enabled // Exceptions are disabled vv
+ std::string ExceptionTranslatorRegistry::translateActiveException() const {
+ CATCH_INTERNAL_ERROR("Attempted to translate active exception under CATCH_CONFIG_DISABLE_EXCEPTIONS!");
+ }
+
+ std::string ExceptionTranslatorRegistry::tryTranslators() const {
+ CATCH_INTERNAL_ERROR("Attempted to use exception translators under CATCH_CONFIG_DISABLE_EXCEPTIONS!");
+ }
+#endif
+
+
+}
+
+
+
+/** \file
+ * This file provides platform specific implementations of FatalConditionHandler
+ *
+ * This means that there is a lot of conditional compilation, and platform
+ * specific code. Currently, Catch2 supports a dummy handler (if no
+ * handler is desired), and 2 platform specific handlers:
+ * * Windows' SEH
+ * * POSIX signals
+ *
+ * Consequently, various pieces of code below are compiled if either of
+ * the platform specific handlers is enabled, or if none of them are
+ * enabled. It is assumed that both cannot be enabled at the same time,
+ * and doing so should cause a compilation error.
+ *
+ * If another platform specific handler is added, the compile guards
+ * below will need to be updated taking these assumptions into account.
+ */
+
+
+
+#include <algorithm>
+
+#if !defined( CATCH_CONFIG_WINDOWS_SEH ) && !defined( CATCH_CONFIG_POSIX_SIGNALS )
+
+namespace Catch {
+
+ // If neither SEH nor signal handling is required, the handler impls
+ // do not have to do anything, and can be empty.
+ void FatalConditionHandler::engage_platform() {}
+ void FatalConditionHandler::disengage_platform() noexcept {}
+ FatalConditionHandler::FatalConditionHandler() = default;
+ FatalConditionHandler::~FatalConditionHandler() = default;
+
+} // end namespace Catch
+
+#endif // !CATCH_CONFIG_WINDOWS_SEH && !CATCH_CONFIG_POSIX_SIGNALS
+
+#if defined( CATCH_CONFIG_WINDOWS_SEH ) && defined( CATCH_CONFIG_POSIX_SIGNALS )
+#error "Inconsistent configuration: Windows' SEH handling and POSIX signals cannot be enabled at the same time"
+#endif // CATCH_CONFIG_WINDOWS_SEH && CATCH_CONFIG_POSIX_SIGNALS
+
+#if defined( CATCH_CONFIG_WINDOWS_SEH ) || defined( CATCH_CONFIG_POSIX_SIGNALS )
+
+namespace {
+ //! Signals fatal error message to the run context
+ void reportFatal( char const * const message ) {
+ Catch::getCurrentContext().getResultCapture()->handleFatalErrorCondition( message );
+ }
+
+ //! Minimal size Catch2 needs for its own fatal error handling.
+ //! Picked empirically, so it might not be sufficient on all
+ //! platforms, and for all configurations.
+ constexpr std::size_t minStackSizeForErrors = 32 * 1024;
+} // end unnamed namespace
+
+#endif // CATCH_CONFIG_WINDOWS_SEH || CATCH_CONFIG_POSIX_SIGNALS
+
+#if defined( CATCH_CONFIG_WINDOWS_SEH )
+
+namespace Catch {
+
+ struct SignalDefs { DWORD id; const char* name; };
+
+ // There is no 1-1 mapping between signals and windows exceptions.
+ // Windows can easily distinguish between SO and SigSegV,
+ // but SigInt, SigTerm, etc are handled differently.
+ static SignalDefs signalDefs[] = {
+ { EXCEPTION_ILLEGAL_INSTRUCTION, "SIGILL - Illegal instruction signal" },
+ { EXCEPTION_STACK_OVERFLOW, "SIGSEGV - Stack overflow" },
+ { EXCEPTION_ACCESS_VIOLATION, "SIGSEGV - Segmentation violation signal" },
+ { EXCEPTION_INT_DIVIDE_BY_ZERO, "Divide by zero error" },
+ };
+
+ static LONG CALLBACK topLevelExceptionFilter(PEXCEPTION_POINTERS ExceptionInfo) {
+ for (auto const& def : signalDefs) {
+ if (ExceptionInfo->ExceptionRecord->ExceptionCode == def.id) {
+ reportFatal(def.name);
+ }
+ }
+ // If its not an exception we care about, pass it along.
+ // This stops us from eating debugger breaks etc.
+ return EXCEPTION_CONTINUE_SEARCH;
+ }
+
+ // Since we do not support multiple instantiations, we put these
+ // into global variables and rely on cleaning them up in outlined
+ // constructors/destructors
+ static LPTOP_LEVEL_EXCEPTION_FILTER previousTopLevelExceptionFilter = nullptr;
+
+
+ // For MSVC, we reserve part of the stack memory for handling
+ // memory overflow structured exception.
+ FatalConditionHandler::FatalConditionHandler() {
+ ULONG guaranteeSize = static_cast<ULONG>(minStackSizeForErrors);
+ if (!SetThreadStackGuarantee(&guaranteeSize)) {
+ // We do not want to fully error out, because needing
+ // the stack reserve should be rare enough anyway.
+ Catch::cerr()
+ << "Failed to reserve piece of stack."
+ << " Stack overflows will not be reported successfully.";
+ }
+ }
+
+ // We do not attempt to unset the stack guarantee, because
+ // Windows does not support lowering the stack size guarantee.
+ FatalConditionHandler::~FatalConditionHandler() = default;
+
+
+ void FatalConditionHandler::engage_platform() {
+ // Register as a the top level exception filter.
+ previousTopLevelExceptionFilter = SetUnhandledExceptionFilter(topLevelExceptionFilter);
+ }
+
+ void FatalConditionHandler::disengage_platform() noexcept {
+ if (SetUnhandledExceptionFilter(previousTopLevelExceptionFilter) != topLevelExceptionFilter) {
+ Catch::cerr()
+ << "Unexpected SEH unhandled exception filter on disengage."
+ << " The filter was restored, but might be rolled back unexpectedly.";
+ }
+ previousTopLevelExceptionFilter = nullptr;
+ }
+
+} // end namespace Catch
+
+#endif // CATCH_CONFIG_WINDOWS_SEH
+
+#if defined( CATCH_CONFIG_POSIX_SIGNALS )
+
+#include <signal.h>
+
+namespace Catch {
+
+ struct SignalDefs {
+ int id;
+ const char* name;
+ };
+
+ static SignalDefs signalDefs[] = {
+ { SIGINT, "SIGINT - Terminal interrupt signal" },
+ { SIGILL, "SIGILL - Illegal instruction signal" },
+ { SIGFPE, "SIGFPE - Floating point error signal" },
+ { SIGSEGV, "SIGSEGV - Segmentation violation signal" },
+ { SIGTERM, "SIGTERM - Termination request signal" },
+ { SIGABRT, "SIGABRT - Abort (abnormal termination) signal" }
+ };
+
+// Older GCCs trigger -Wmissing-field-initializers for T foo = {}
+// which is zero initialization, but not explicit. We want to avoid
+// that.
+#if defined(__GNUC__)
+# pragma GCC diagnostic push
+# pragma GCC diagnostic ignored "-Wmissing-field-initializers"
+#endif
+
+ static char* altStackMem = nullptr;
+ static std::size_t altStackSize = 0;
+ static stack_t oldSigStack{};
+ static struct sigaction oldSigActions[sizeof(signalDefs) / sizeof(SignalDefs)]{};
+
+ static void restorePreviousSignalHandlers() noexcept {
+ // We set signal handlers back to the previous ones. Hopefully
+ // nobody overwrote them in the meantime, and doesn't expect
+ // their signal handlers to live past ours given that they
+ // installed them after ours..
+ for (std::size_t i = 0; i < sizeof(signalDefs) / sizeof(SignalDefs); ++i) {
+ sigaction(signalDefs[i].id, &oldSigActions[i], nullptr);
+ }
+ // Return the old stack
+ sigaltstack(&oldSigStack, nullptr);
+ }
+
+ static void handleSignal( int sig ) {
+ char const * name = "<unknown signal>";
+ for (auto const& def : signalDefs) {
+ if (sig == def.id) {
+ name = def.name;
+ break;
+ }
+ }
+ // We need to restore previous signal handlers and let them do
+ // their thing, so that the users can have the debugger break
+ // when a signal is raised, and so on.
+ restorePreviousSignalHandlers();
+ reportFatal( name );
+ raise( sig );
+ }
+
+ FatalConditionHandler::FatalConditionHandler() {
+ assert(!altStackMem && "Cannot initialize POSIX signal handler when one already exists");
+ if (altStackSize == 0) {
+ altStackSize = std::max(static_cast<size_t>(SIGSTKSZ), minStackSizeForErrors);
+ }
+ altStackMem = new char[altStackSize]();
+ }
+
+ FatalConditionHandler::~FatalConditionHandler() {
+ delete[] altStackMem;
+ // We signal that another instance can be constructed by zeroing
+ // out the pointer.
+ altStackMem = nullptr;
+ }
+
+ void FatalConditionHandler::engage_platform() {
+ stack_t sigStack;
+ sigStack.ss_sp = altStackMem;
+ sigStack.ss_size = altStackSize;
+ sigStack.ss_flags = 0;
+ sigaltstack(&sigStack, &oldSigStack);
+ struct sigaction sa = { };
+
+ sa.sa_handler = handleSignal;
+ sa.sa_flags = SA_ONSTACK;
+ for (std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i) {
+ sigaction(signalDefs[i].id, &sa, &oldSigActions[i]);
+ }
+ }
+
+#if defined(__GNUC__)
+# pragma GCC diagnostic pop
+#endif
+
+
+ void FatalConditionHandler::disengage_platform() noexcept {
+ restorePreviousSignalHandlers();
+ }
+
+} // end namespace Catch
+
+#endif // CATCH_CONFIG_POSIX_SIGNALS
+
+
+
+
+#include <cstring>
+
+namespace Catch {
+ namespace Detail {
+
+ uint32_t convertToBits(float f) {
+ static_assert(sizeof(float) == sizeof(uint32_t), "Important ULP matcher assumption violated");
+ uint32_t i;
+ std::memcpy(&i, &f, sizeof(f));
+ return i;
+ }
+
+ uint64_t convertToBits(double d) {
+ static_assert(sizeof(double) == sizeof(uint64_t), "Important ULP matcher assumption violated");
+ uint64_t i;
+ std::memcpy(&i, &d, sizeof(d));
+ return i;
+ }
+
+ } // end namespace Detail
+} // end namespace Catch
+
+
+
+
+
+#include <cstdio>
+#include <fstream>
+#include <sstream>
+#include <vector>
+
+namespace Catch {
+
+ Catch::IStream::~IStream() = default;
+
+namespace Detail {
+ namespace {
+ template<typename WriterF, std::size_t bufferSize=256>
+ class StreamBufImpl : public std::streambuf {
+ char data[bufferSize];
+ WriterF m_writer;
+
+ public:
+ StreamBufImpl() {
+ setp( data, data + sizeof(data) );
+ }
+
+ ~StreamBufImpl() noexcept override {
+ StreamBufImpl::sync();
+ }
+
+ private:
+ int overflow( int c ) override {
+ sync();
+
+ if( c != EOF ) {
+ if( pbase() == epptr() )
+ m_writer( std::string( 1, static_cast<char>( c ) ) );
+ else
+ sputc( static_cast<char>( c ) );
+ }
+ return 0;
+ }
+
+ int sync() override {
+ if( pbase() != pptr() ) {
+ m_writer( std::string( pbase(), static_cast<std::string::size_type>( pptr() - pbase() ) ) );
+ setp( pbase(), epptr() );
+ }
+ return 0;
+ }
+ };
+
+ ///////////////////////////////////////////////////////////////////////////
+
+ struct OutputDebugWriter {
+
+ void operator()( std::string const& str ) {
+ if ( !str.empty() ) {
+ writeToDebugConsole( str );
+ }
+ }
+ };
+
+ ///////////////////////////////////////////////////////////////////////////
+
+ class FileStream : public IStream {
+ std::ofstream m_ofs;
+ public:
+ FileStream( std::string const& filename ) {
+ m_ofs.open( filename.c_str() );
+ CATCH_ENFORCE( !m_ofs.fail(), "Unable to open file: '" << filename << '\'' );
+ }
+ ~FileStream() override = default;
+ public: // IStream
+ std::ostream& stream() override {
+ return m_ofs;
+ }
+ };
+
+ ///////////////////////////////////////////////////////////////////////////
+
+ class CoutStream : public IStream {
+ std::ostream m_os;
+ public:
+ // Store the streambuf from cout up-front because
+ // cout may get redirected when running tests
+ CoutStream() : m_os( Catch::cout().rdbuf() ) {}
+ ~CoutStream() override = default;
+
+ public: // IStream
+ std::ostream& stream() override { return m_os; }
+ bool isConsole() const override { return true; }
+ };
+
+ class CerrStream : public IStream {
+ std::ostream m_os;
+
+ public:
+ // Store the streambuf from cerr up-front because
+ // cout may get redirected when running tests
+ CerrStream(): m_os( Catch::cerr().rdbuf() ) {}
+ ~CerrStream() override = default;
+
+ public: // IStream
+ std::ostream& stream() override { return m_os; }
+ bool isConsole() const override { return true; }
+ };
+
+ ///////////////////////////////////////////////////////////////////////////
+
+ class DebugOutStream : public IStream {
+ Detail::unique_ptr<StreamBufImpl<OutputDebugWriter>> m_streamBuf;
+ std::ostream m_os;
+ public:
+ DebugOutStream()
+ : m_streamBuf( Detail::make_unique<StreamBufImpl<OutputDebugWriter>>() ),
+ m_os( m_streamBuf.get() )
+ {}
+
+ ~DebugOutStream() override = default;
+
+ public: // IStream
+ std::ostream& stream() override { return m_os; }
+ };
+
+ } // unnamed namespace
+} // namespace Detail
+
+ ///////////////////////////////////////////////////////////////////////////
+
+ auto makeStream( std::string const& filename ) -> Detail::unique_ptr<IStream> {
+ if ( filename.empty() || filename == "-" ) {
+ return Detail::make_unique<Detail::CoutStream>();
+ }
+ if( filename[0] == '%' ) {
+ if ( filename == "%debug" ) {
+ return Detail::make_unique<Detail::DebugOutStream>();
+ } else if ( filename == "%stderr" ) {
+ return Detail::make_unique<Detail::CerrStream>();
+ } else if ( filename == "%stdout" ) {
+ return Detail::make_unique<Detail::CoutStream>();
+ } else {
+ CATCH_ERROR( "Unrecognised stream: '" << filename << '\'' );
+ }
+ }
+ return Detail::make_unique<Detail::FileStream>( filename );
+ }
+
+}
+
+
+
+
+namespace Catch {
+
+ auto operator << (std::ostream& os, LazyExpression const& lazyExpr) -> std::ostream& {
+ if (lazyExpr.m_isNegated)
+ os << '!';
+
+ if (lazyExpr) {
+ if (lazyExpr.m_isNegated && lazyExpr.m_transientExpression->isBinaryExpression())
+ os << '(' << *lazyExpr.m_transientExpression << ')';
+ else
+ os << *lazyExpr.m_transientExpression;
+ } else {
+ os << "{** error - unchecked empty expression requested **}";
+ }
+ return os;
+ }
+
+} // namespace Catch
+
+
+
+
+#ifdef CATCH_CONFIG_WINDOWS_CRTDBG
+#include <crtdbg.h>
+
+namespace Catch {
+
+ LeakDetector::LeakDetector() {
+ int flag = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG);
+ flag |= _CRTDBG_LEAK_CHECK_DF;
+ flag |= _CRTDBG_ALLOC_MEM_DF;
+ _CrtSetDbgFlag(flag);
+ _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG);
+ _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR);
+ // Change this to leaking allocation's number to break there
+ _CrtSetBreakAlloc(-1);
+ }
+}
+
+#else // ^^ Windows crt debug heap enabled // Windows crt debug heap disabled vv
+
+ Catch::LeakDetector::LeakDetector() {}
+
+#endif // CATCH_CONFIG_WINDOWS_CRTDBG
+
+Catch::LeakDetector::~LeakDetector() {
+ Catch::cleanUp();
+}
+
+
+
+
+
+namespace Catch {
+ namespace {
+
+ void listTests(IEventListener& reporter, IConfig const& config) {
+ auto const& testSpec = config.testSpec();
+ auto matchedTestCases = filterTests(getAllTestCasesSorted(config), testSpec, config);
+ reporter.listTests(matchedTestCases);
+ }
+
+ void listTags(IEventListener& reporter, IConfig const& config) {
+ auto const& testSpec = config.testSpec();
+ std::vector<TestCaseHandle> matchedTestCases = filterTests(getAllTestCasesSorted(config), testSpec, config);
+
+ std::map<StringRef, TagInfo, Detail::CaseInsensitiveLess> tagCounts;
+ for (auto const& testCase : matchedTestCases) {
+ for (auto const& tagName : testCase.getTestCaseInfo().tags) {
+ auto it = tagCounts.find(tagName.original);
+ if (it == tagCounts.end())
+ it = tagCounts.insert(std::make_pair(tagName.original, TagInfo())).first;
+ it->second.add(tagName.original);
+ }
+ }
+
+ std::vector<TagInfo> infos; infos.reserve(tagCounts.size());
+ for (auto& tagc : tagCounts) {
+ infos.push_back(CATCH_MOVE(tagc.second));
+ }
+
+ reporter.listTags(infos);
+ }
+
+ void listReporters(IEventListener& reporter) {
+ std::vector<ReporterDescription> descriptions;
+
+ IReporterRegistry::FactoryMap const& factories = getRegistryHub().getReporterRegistry().getFactories();
+ descriptions.reserve(factories.size());
+ for (auto const& fac : factories) {
+ descriptions.push_back({ fac.first, fac.second->getDescription() });
+ }
+
+ reporter.listReporters(descriptions);
+ }
+
+ void listListeners(IEventListener& reporter) {
+ std::vector<ListenerDescription> descriptions;
+
+ auto const& factories =
+ getRegistryHub().getReporterRegistry().getListeners();
+ descriptions.reserve( factories.size() );
+ for ( auto const& fac : factories ) {
+ descriptions.push_back( { fac->getName(), fac->getDescription() } );
+ }
+
+ reporter.listListeners( descriptions );
+ }
+
+ } // end anonymous namespace
+
+ void TagInfo::add( StringRef spelling ) {
+ ++count;
+ spellings.insert( spelling );
+ }
+
+ std::string TagInfo::all() const {
+ // 2 per tag for brackets '[' and ']'
+ size_t size = spellings.size() * 2;
+ for (auto const& spelling : spellings) {
+ size += spelling.size();
+ }
+
+ std::string out; out.reserve(size);
+ for (auto const& spelling : spellings) {
+ out += '[';
+ out += spelling;
+ out += ']';
+ }
+ return out;
+ }
+
+ bool list( IEventListener& reporter, Config const& config ) {
+ bool listed = false;
+ if (config.listTests()) {
+ listed = true;
+ listTests(reporter, config);
+ }
+ if (config.listTags()) {
+ listed = true;
+ listTags(reporter, config);
+ }
+ if (config.listReporters()) {
+ listed = true;
+ listReporters(reporter);
+ }
+ if ( config.listListeners() ) {
+ listed = true;
+ listListeners( reporter );
+ }
+ return listed;
+ }
+
+} // end namespace Catch
+
+
+
+namespace Catch {
+ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION
+ CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS
+ static LeakDetector leakDetector;
+ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
+}
+
+// Allow users of amalgamated .cpp file to remove our main and provide their own.
+#if !defined(CATCH_AMALGAMATED_CUSTOM_MAIN)
+
+#if defined(CATCH_CONFIG_WCHAR) && defined(CATCH_PLATFORM_WINDOWS) && defined(_UNICODE) && !defined(DO_NOT_USE_WMAIN)
+// Standard C/C++ Win32 Unicode wmain entry point
+extern "C" int __cdecl wmain (int argc, wchar_t * argv[], wchar_t * []) {
+#else
+// Standard C/C++ main entry point
+int main (int argc, char * argv[]) {
+#endif
+
+ // We want to force the linker not to discard the global variable
+ // and its constructor, as it (optionally) registers leak detector
+ (void)&Catch::leakDetector;
+
+ return Catch::Session().run( argc, argv );
+}
+
+#endif // !defined(CATCH_AMALGAMATED_CUSTOM_MAIN
+
+
+
+
+namespace Catch {
+
+ MessageInfo::MessageInfo( StringRef _macroName,
+ SourceLineInfo const& _lineInfo,
+ ResultWas::OfType _type )
+ : macroName( _macroName ),
+ lineInfo( _lineInfo ),
+ type( _type ),
+ sequence( ++globalCount )
+ {}
+
+ // This may need protecting if threading support is added
+ unsigned int MessageInfo::globalCount = 0;
+
+} // end namespace Catch
+
+
+
+#include <cstdio>
+#include <cstring>
+#include <sstream>
+
+#if defined(CATCH_CONFIG_NEW_CAPTURE)
+ #if defined(_MSC_VER)
+ #include <io.h> //_dup and _dup2
+ #define dup _dup
+ #define dup2 _dup2
+ #define fileno _fileno
+ #else
+ #include <unistd.h> // dup and dup2
+ #endif
+#endif
+
+
+namespace Catch {
+
+ RedirectedStream::RedirectedStream( std::ostream& originalStream, std::ostream& redirectionStream )
+ : m_originalStream( originalStream ),
+ m_redirectionStream( redirectionStream ),
+ m_prevBuf( m_originalStream.rdbuf() )
+ {
+ m_originalStream.rdbuf( m_redirectionStream.rdbuf() );
+ }
+
+ RedirectedStream::~RedirectedStream() {
+ m_originalStream.rdbuf( m_prevBuf );
+ }
+
+ RedirectedStdOut::RedirectedStdOut() : m_cout( Catch::cout(), m_rss.get() ) {}
+ auto RedirectedStdOut::str() const -> std::string { return m_rss.str(); }
+
+ RedirectedStdErr::RedirectedStdErr()
+ : m_cerr( Catch::cerr(), m_rss.get() ),
+ m_clog( Catch::clog(), m_rss.get() )
+ {}
+ auto RedirectedStdErr::str() const -> std::string { return m_rss.str(); }
+
+ RedirectedStreams::RedirectedStreams(std::string& redirectedCout, std::string& redirectedCerr)
+ : m_redirectedCout(redirectedCout),
+ m_redirectedCerr(redirectedCerr)
+ {}
+
+ RedirectedStreams::~RedirectedStreams() {
+ m_redirectedCout += m_redirectedStdOut.str();
+ m_redirectedCerr += m_redirectedStdErr.str();
+ }
+
+#if defined(CATCH_CONFIG_NEW_CAPTURE)
+
+#if defined(_MSC_VER)
+ TempFile::TempFile() {
+ if (tmpnam_s(m_buffer)) {
+ CATCH_RUNTIME_ERROR("Could not get a temp filename");
+ }
+ if (fopen_s(&m_file, m_buffer, "w+")) {
+ char buffer[100];
+ if (strerror_s(buffer, errno)) {
+ CATCH_RUNTIME_ERROR("Could not translate errno to a string");
+ }
+ CATCH_RUNTIME_ERROR("Could not open the temp file: '" << m_buffer << "' because: " << buffer);
+ }
+ }
+#else
+ TempFile::TempFile() {
+ m_file = std::tmpfile();
+ if (!m_file) {
+ CATCH_RUNTIME_ERROR("Could not create a temp file.");
+ }
+ }
+
+#endif
+
+ TempFile::~TempFile() {
+ // TBD: What to do about errors here?
+ std::fclose(m_file);
+ // We manually create the file on Windows only, on Linux
+ // it will be autodeleted
+#if defined(_MSC_VER)
+ std::remove(m_buffer);
+#endif
+ }
+
+
+ FILE* TempFile::getFile() {
+ return m_file;
+ }
+
+ std::string TempFile::getContents() {
+ std::stringstream sstr;
+ char buffer[100] = {};
+ std::rewind(m_file);
+ while (std::fgets(buffer, sizeof(buffer), m_file)) {
+ sstr << buffer;
+ }
+ return sstr.str();
+ }
+
+ OutputRedirect::OutputRedirect(std::string& stdout_dest, std::string& stderr_dest) :
+ m_originalStdout(dup(1)),
+ m_originalStderr(dup(2)),
+ m_stdoutDest(stdout_dest),
+ m_stderrDest(stderr_dest) {
+ dup2(fileno(m_stdoutFile.getFile()), 1);
+ dup2(fileno(m_stderrFile.getFile()), 2);
+ }
+
+ OutputRedirect::~OutputRedirect() {
+ Catch::cout() << std::flush;
+ fflush(stdout);
+ // Since we support overriding these streams, we flush cerr
+ // even though std::cerr is unbuffered
+ Catch::cerr() << std::flush;
+ Catch::clog() << std::flush;
+ fflush(stderr);
+
+ dup2(m_originalStdout, 1);
+ dup2(m_originalStderr, 2);
+
+ m_stdoutDest += m_stdoutFile.getContents();
+ m_stderrDest += m_stderrFile.getContents();
+ }
+
+#endif // CATCH_CONFIG_NEW_CAPTURE
+
+} // namespace Catch
+
+#if defined(CATCH_CONFIG_NEW_CAPTURE)
+ #if defined(_MSC_VER)
+ #undef dup
+ #undef dup2
+ #undef fileno
+ #endif
+#endif
+
+
+
+
+#include <cmath>
+
+namespace Catch {
+
+#if !defined(CATCH_CONFIG_POLYFILL_ISNAN)
+ bool isnan(float f) {
+ return std::isnan(f);
+ }
+ bool isnan(double d) {
+ return std::isnan(d);
+ }
+#else
+ // For now we only use this for embarcadero
+ bool isnan(float f) {
+ return std::_isnan(f);
+ }
+ bool isnan(double d) {
+ return std::_isnan(d);
+ }
+#endif
+
+} // end namespace Catch
+
+
+
+namespace Catch {
+
+namespace {
+
+#if defined(_MSC_VER)
+#pragma warning(push)
+#pragma warning(disable:4146) // we negate uint32 during the rotate
+#endif
+ // Safe rotr implementation thanks to John Regehr
+ uint32_t rotate_right(uint32_t val, uint32_t count) {
+ const uint32_t mask = 31;
+ count &= mask;
+ return (val >> count) | (val << (-count & mask));
+ }
+
+#if defined(_MSC_VER)
+#pragma warning(pop)
+#endif
+
+}
+
+
+ SimplePcg32::SimplePcg32(result_type seed_) {
+ seed(seed_);
+ }
+
+
+ void SimplePcg32::seed(result_type seed_) {
+ m_state = 0;
+ (*this)();
+ m_state += seed_;
+ (*this)();
+ }
+
+ void SimplePcg32::discard(uint64_t skip) {
+ // We could implement this to run in O(log n) steps, but this
+ // should suffice for our use case.
+ for (uint64_t s = 0; s < skip; ++s) {
+ static_cast<void>((*this)());
+ }
+ }
+
+ SimplePcg32::result_type SimplePcg32::operator()() {
+ // prepare the output value
+ const uint32_t xorshifted = static_cast<uint32_t>(((m_state >> 18u) ^ m_state) >> 27u);
+ const auto output = rotate_right(xorshifted, m_state >> 59u);
+
+ // advance state
+ m_state = m_state * 6364136223846793005ULL + s_inc;
+
+ return output;
+ }
+
+ bool operator==(SimplePcg32 const& lhs, SimplePcg32 const& rhs) {
+ return lhs.m_state == rhs.m_state;
+ }
+
+ bool operator!=(SimplePcg32 const& lhs, SimplePcg32 const& rhs) {
+ return lhs.m_state != rhs.m_state;
+ }
+}
+
+
+
+
+
+#include <ctime>
+#include <random>
+
+namespace Catch {
+
+ std::uint32_t generateRandomSeed( GenerateFrom from ) {
+ switch ( from ) {
+ case GenerateFrom::Time:
+ return static_cast<std::uint32_t>( std::time( nullptr ) );
+
+ case GenerateFrom::Default:
+ case GenerateFrom::RandomDevice:
+ // In theory, a platform could have random_device that returns just
+ // 16 bits. That is still some randomness, so we don't care too much
+ return static_cast<std::uint32_t>( std::random_device{}() );
+
+ default:
+ CATCH_ERROR("Unknown generation method");
+ }
+ }
+
+} // end namespace Catch
+
+
+
+
+namespace Catch {
+
+ ReporterRegistry::ReporterRegistry() {
+ // Because it is impossible to move out of initializer list,
+ // we have to add the elements manually
+ m_factories["Automake"] = Detail::make_unique<ReporterFactory<AutomakeReporter>>();
+ m_factories["compact"] = Detail::make_unique<ReporterFactory<CompactReporter>>();
+ m_factories["console"] = Detail::make_unique<ReporterFactory<ConsoleReporter>>();
+ m_factories["JUnit"] = Detail::make_unique<ReporterFactory<JunitReporter>>();
+ m_factories["SonarQube"] = Detail::make_unique<ReporterFactory<SonarQubeReporter>>();
+ m_factories["TAP"] = Detail::make_unique<ReporterFactory<TAPReporter>>();
+ m_factories["TeamCity"] = Detail::make_unique<ReporterFactory<TeamCityReporter>>();
+ m_factories["XML"] = Detail::make_unique<ReporterFactory<XmlReporter>>();
+ }
+
+ ReporterRegistry::~ReporterRegistry() = default;
+
+
+ IEventListenerPtr ReporterRegistry::create( std::string const& name, ReporterConfig&& config ) const {
+ auto it = m_factories.find( name );
+ if( it == m_factories.end() )
+ return nullptr;
+ return it->second->create( CATCH_MOVE(config) );
+ }
+
+ void ReporterRegistry::registerReporter( std::string const& name, IReporterFactoryPtr factory ) {
+ CATCH_ENFORCE( name.find( "::" ) == name.npos,
+ "'::' is not allowed in reporter name: '" + name + '\'' );
+ auto ret = m_factories.emplace(name, CATCH_MOVE(factory));
+ CATCH_ENFORCE( ret.second, "reporter using '" + name + "' as name was already registered" );
+ }
+ void ReporterRegistry::registerListener(
+ Detail::unique_ptr<EventListenerFactory> factory ) {
+ m_listeners.push_back( CATCH_MOVE(factory) );
+ }
+
+ IReporterRegistry::FactoryMap const& ReporterRegistry::getFactories() const {
+ return m_factories;
+ }
+ IReporterRegistry::Listeners const& ReporterRegistry::getListeners() const {
+ return m_listeners;
+ }
+
+}
+
+
+
+
+
+#include <algorithm>
+
+namespace Catch {
+
+ namespace {
+ struct kvPair {
+ StringRef key, value;
+ };
+
+ kvPair splitKVPair(StringRef kvString) {
+ auto splitPos = static_cast<size_t>( std::distance(
+ kvString.begin(),
+ std::find( kvString.begin(), kvString.end(), '=' ) ) );
+
+ return { kvString.substr( 0, splitPos ),
+ kvString.substr( splitPos + 1, kvString.size() ) };
+ }
+ }
+
+ namespace Detail {
+ std::vector<std::string> splitReporterSpec( StringRef reporterSpec ) {
+ static constexpr auto separator = "::";
+ static constexpr size_t separatorSize = 2;
+
+ size_t separatorPos = 0;
+ auto findNextSeparator = [&reporterSpec]( size_t startPos ) {
+ static_assert(
+ separatorSize == 2,
+ "The code below currently assumes 2 char separator" );
+
+ auto currentPos = startPos;
+ do {
+ while ( currentPos < reporterSpec.size() &&
+ reporterSpec[currentPos] != separator[0] ) {
+ ++currentPos;
+ }
+ if ( currentPos + 1 < reporterSpec.size() &&
+ reporterSpec[currentPos + 1] == separator[1] ) {
+ return currentPos;
+ }
+ ++currentPos;
+ } while ( currentPos < reporterSpec.size() );
+
+ return static_cast<size_t>( -1 );
+ };
+
+ std::vector<std::string> parts;
+
+ while ( separatorPos < reporterSpec.size() ) {
+ const auto nextSeparator = findNextSeparator( separatorPos );
+ parts.push_back( static_cast<std::string>( reporterSpec.substr(
+ separatorPos, nextSeparator - separatorPos ) ) );
+
+ if ( nextSeparator == static_cast<size_t>( -1 ) ) {
+ break;
+ }
+ separatorPos = nextSeparator + separatorSize;
+ }
+
+ // Handle a separator at the end.
+ // This is not a valid spec, but we want to do validation in a
+ // centralized place
+ if ( separatorPos == reporterSpec.size() ) {
+ parts.emplace_back();
+ }
+
+ return parts;
+ }
+
+ Optional<ColourMode> stringToColourMode( StringRef colourMode ) {
+ if ( colourMode == "default" ) {
+ return ColourMode::PlatformDefault;
+ } else if ( colourMode == "ansi" ) {
+ return ColourMode::ANSI;
+ } else if ( colourMode == "win32" ) {
+ return ColourMode::Win32;
+ } else if ( colourMode == "none" ) {
+ return ColourMode::None;
+ } else {
+ return {};
+ }
+ }
+ } // namespace Detail
+
+
+ bool operator==( ReporterSpec const& lhs, ReporterSpec const& rhs ) {
+ return lhs.m_name == rhs.m_name &&
+ lhs.m_outputFileName == rhs.m_outputFileName &&
+ lhs.m_colourMode == rhs.m_colourMode &&
+ lhs.m_customOptions == rhs.m_customOptions;
+ }
+
+ Optional<ReporterSpec> parseReporterSpec( StringRef reporterSpec ) {
+ auto parts = Detail::splitReporterSpec( reporterSpec );
+
+ assert( parts.size() > 0 && "Split should never return empty vector" );
+
+ std::map<std::string, std::string> kvPairs;
+ Optional<std::string> outputFileName;
+ Optional<ColourMode> colourMode;
+
+ // First part is always reporter name, so we skip it
+ for ( size_t i = 1; i < parts.size(); ++i ) {
+ auto kv = splitKVPair( parts[i] );
+ auto key = kv.key, value = kv.value;
+
+ if ( key.empty() || value.empty() ) {
+ return {};
+ } else if ( key[0] == 'X' ) {
+ // This is a reporter-specific option, we don't check these
+ // apart from basic sanity checks
+ if ( key.size() == 1 ) {
+ return {};
+ }
+
+ auto ret = kvPairs.emplace( std::string(kv.key), std::string(kv.value) );
+ if ( !ret.second ) {
+ // Duplicated key. We might want to handle this differently,
+ // e.g. by overwriting the existing value?
+ return {};
+ }
+ } else if ( key == "out" ) {
+ // Duplicated key
+ if ( outputFileName ) {
+ return {};
+ }
+ outputFileName = static_cast<std::string>( value );
+ } else if ( key == "colour-mode" ) {
+ // Duplicated key
+ if ( colourMode ) {
+ return {};
+ }
+ colourMode = Detail::stringToColourMode( value );
+ // Parsing failed
+ if ( !colourMode ) {
+ return {};
+ }
+ } else {
+ // Unrecognized option
+ return {};
+ }
+ }
+
+ return ReporterSpec{ CATCH_MOVE( parts[0] ),
+ CATCH_MOVE( outputFileName ),
+ CATCH_MOVE( colourMode ),
+ CATCH_MOVE( kvPairs ) };
+ }
+
+ReporterSpec::ReporterSpec(
+ std::string name,
+ Optional<std::string> outputFileName,
+ Optional<ColourMode> colourMode,
+ std::map<std::string, std::string> customOptions ):
+ m_name( CATCH_MOVE( name ) ),
+ m_outputFileName( CATCH_MOVE( outputFileName ) ),
+ m_colourMode( CATCH_MOVE( colourMode ) ),
+ m_customOptions( CATCH_MOVE( customOptions ) ) {}
+
+} // namespace Catch
+
+
+
+namespace Catch {
+
+ bool isOk( ResultWas::OfType resultType ) {
+ return ( resultType & ResultWas::FailureBit ) == 0;
+ }
+ bool isJustInfo( int flags ) {
+ return flags == ResultWas::Info;
+ }
+
+ ResultDisposition::Flags operator | ( ResultDisposition::Flags lhs, ResultDisposition::Flags rhs ) {
+ return static_cast<ResultDisposition::Flags>( static_cast<int>( lhs ) | static_cast<int>( rhs ) );
+ }
+
+ bool shouldContinueOnFailure( int flags ) { return ( flags & ResultDisposition::ContinueOnFailure ) != 0; }
+ bool shouldSuppressFailure( int flags ) { return ( flags & ResultDisposition::SuppressFail ) != 0; }
+
+} // end namespace Catch
+
+
+
+#include <cstdio>
+#include <sstream>
+#include <vector>
+
+namespace Catch {
+
+ // This class encapsulates the idea of a pool of ostringstreams that can be reused.
+ struct StringStreams {
+ std::vector<Detail::unique_ptr<std::ostringstream>> m_streams;
+ std::vector<std::size_t> m_unused;
+ std::ostringstream m_referenceStream; // Used for copy state/ flags from
+
+ auto add() -> std::size_t {
+ if( m_unused.empty() ) {
+ m_streams.push_back( Detail::make_unique<std::ostringstream>() );
+ return m_streams.size()-1;
+ }
+ else {
+ auto index = m_unused.back();
+ m_unused.pop_back();
+ return index;
+ }
+ }
+
+ void release( std::size_t index ) {
+ m_streams[index]->copyfmt( m_referenceStream ); // Restore initial flags and other state
+ m_unused.push_back(index);
+ }
+ };
+
+ ReusableStringStream::ReusableStringStream()
+ : m_index( Singleton<StringStreams>::getMutable().add() ),
+ m_oss( Singleton<StringStreams>::getMutable().m_streams[m_index].get() )
+ {}
+
+ ReusableStringStream::~ReusableStringStream() {
+ static_cast<std::ostringstream*>( m_oss )->str("");
+ m_oss->clear();
+ Singleton<StringStreams>::getMutable().release( m_index );
+ }
+
+ std::string ReusableStringStream::str() const {
+ return static_cast<std::ostringstream*>( m_oss )->str();
+ }
+
+ void ReusableStringStream::str( std::string const& str ) {
+ static_cast<std::ostringstream*>( m_oss )->str( str );
+ }
+
+
+}
+
+
+
+
+#include <cassert>
+#include <algorithm>
+
+namespace Catch {
+
+ namespace Generators {
+ struct GeneratorTracker : TestCaseTracking::TrackerBase, IGeneratorTracker {
+ GeneratorBasePtr m_generator;
+
+ GeneratorTracker( TestCaseTracking::NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent )
+ : TrackerBase( nameAndLocation, ctx, parent )
+ {}
+ ~GeneratorTracker() override;
+
+ static GeneratorTracker& acquire( TrackerContext& ctx, TestCaseTracking::NameAndLocation const& nameAndLocation ) {
+ GeneratorTracker* tracker;
+
+ ITracker& currentTracker = ctx.currentTracker();
+ // Under specific circumstances, the generator we want
+ // to acquire is also the current tracker. If this is
+ // the case, we have to avoid looking through current
+ // tracker's children, and instead return the current
+ // tracker.
+ // A case where this check is important is e.g.
+ // for (int i = 0; i < 5; ++i) {
+ // int n = GENERATE(1, 2);
+ // }
+ //
+ // without it, the code above creates 5 nested generators.
+ if ( currentTracker.nameAndLocation() == nameAndLocation ) {
+ auto thisTracker =
+ currentTracker.parent()->findChild( nameAndLocation );
+ assert( thisTracker );
+ assert( thisTracker->isGeneratorTracker() );
+ tracker = static_cast<GeneratorTracker*>( thisTracker );
+ } else if ( ITracker* childTracker =
+ currentTracker.findChild( nameAndLocation ) ) {
+ assert( childTracker );
+ assert( childTracker->isGeneratorTracker() );
+ tracker = static_cast<GeneratorTracker*>( childTracker );
+ } else {
+ auto newTracker =
+ Catch::Detail::make_unique<GeneratorTracker>(
+ nameAndLocation, ctx, &currentTracker );
+ tracker = newTracker.get();
+ currentTracker.addChild( CATCH_MOVE(newTracker) );
+ }
+
+ if( !tracker->isComplete() ) {
+ tracker->open();
+ }
+
+ return *tracker;
+ }
+
+ // TrackerBase interface
+ bool isGeneratorTracker() const override { return true; }
+ auto hasGenerator() const -> bool override {
+ return !!m_generator;
+ }
+ void close() override {
+ TrackerBase::close();
+ // If a generator has a child (it is followed by a section)
+ // and none of its children have started, then we must wait
+ // until later to start consuming its values.
+ // This catches cases where `GENERATE` is placed between two
+ // `SECTION`s.
+ // **The check for m_children.empty cannot be removed**.
+ // doing so would break `GENERATE` _not_ followed by `SECTION`s.
+ const bool should_wait_for_child = [&]() {
+ // No children -> nobody to wait for
+ if ( m_children.empty() ) {
+ return false;
+ }
+ // If at least one child started executing, don't wait
+ if ( std::find_if(
+ m_children.begin(),
+ m_children.end(),
+ []( TestCaseTracking::ITrackerPtr const& tracker ) {
+ return tracker->hasStarted();
+ } ) != m_children.end() ) {
+ return false;
+ }
+
+ // No children have started. We need to check if they _can_
+ // start, and thus we should wait for them, or they cannot
+ // start (due to filters), and we shouldn't wait for them
+ ITracker* parent = m_parent;
+ // This is safe: there is always at least one section
+ // tracker in a test case tracking tree
+ while ( !parent->isSectionTracker() ) {
+ parent = parent->parent();
+ }
+ assert( parent &&
+ "Missing root (test case) level section" );
+
+ auto const& parentSection =
+ static_cast<SectionTracker const&>( *parent );
+ auto const& filters = parentSection.getFilters();
+ // No filters -> no restrictions on running sections
+ if ( filters.empty() ) {
+ return true;
+ }
+
+ for ( auto const& child : m_children ) {
+ if ( child->isSectionTracker() &&
+ std::find(
+ filters.begin(),
+ filters.end(),
+ static_cast<SectionTracker const&>( *child )
+ .trimmedName() ) != filters.end() ) {
+ return true;
+ }
+ }
+ return false;
+ }();
+
+ // This check is a bit tricky, because m_generator->next()
+ // has a side-effect, where it consumes generator's current
+ // value, but we do not want to invoke the side-effect if
+ // this generator is still waiting for any child to start.
+ if ( should_wait_for_child ||
+ ( m_runState == CompletedSuccessfully &&
+ m_generator->countedNext() ) ) {
+ m_children.clear();
+ m_runState = Executing;
+ }
+ }
+
+ // IGeneratorTracker interface
+ auto getGenerator() const -> GeneratorBasePtr const& override {
+ return m_generator;
+ }
+ void setGenerator( GeneratorBasePtr&& generator ) override {
+ m_generator = CATCH_MOVE( generator );
+ }
+ };
+ GeneratorTracker::~GeneratorTracker() = default;
+ }
+
+ RunContext::RunContext(IConfig const* _config, IEventListenerPtr&& reporter)
+ : m_runInfo(_config->name()),
+ m_context(getCurrentMutableContext()),
+ m_config(_config),
+ m_reporter(CATCH_MOVE(reporter)),
+ m_lastAssertionInfo{ StringRef(), SourceLineInfo("",0), StringRef(), ResultDisposition::Normal },
+ m_includeSuccessfulResults( m_config->includeSuccessfulResults() || m_reporter->getPreferences().shouldReportAllAssertions )
+ {
+ m_context.setResultCapture(this);
+ m_reporter->testRunStarting(m_runInfo);
+ }
+
+ RunContext::~RunContext() {
+ m_reporter->testRunEnded(TestRunStats(m_runInfo, m_totals, aborting()));
+ }
+
+ Totals RunContext::runTest(TestCaseHandle const& testCase) {
+ const Totals prevTotals = m_totals;
+
+ std::string redirectedCout;
+ std::string redirectedCerr;
+
+ auto const& testInfo = testCase.getTestCaseInfo();
+
+ m_reporter->testCaseStarting(testInfo);
+
+ m_activeTestCase = &testCase;
+
+
+ ITracker& rootTracker = m_trackerContext.startRun();
+ assert(rootTracker.isSectionTracker());
+ static_cast<SectionTracker&>(rootTracker).addInitialFilters(m_config->getSectionsToRun());
+
+ // We intentionally only seed the internal RNG once per test case,
+ // before it is first invoked. The reason for that is a complex
+ // interplay of generator/section implementation details and the
+ // Random*Generator types.
+ //
+ // The issue boils down to us needing to seed the Random*Generators
+ // with different seed each, so that they return different sequences
+ // of random numbers. We do this by giving them a number from the
+ // shared RNG instance as their seed.
+ //
+ // However, this runs into an issue if the reseeding happens each
+ // time the test case is entered (as opposed to first time only),
+ // because multiple generators could get the same seed, e.g. in
+ // ```cpp
+ // TEST_CASE() {
+ // auto i = GENERATE(take(10, random(0, 100));
+ // SECTION("A") {
+ // auto j = GENERATE(take(10, random(0, 100));
+ // }
+ // SECTION("B") {
+ // auto k = GENERATE(take(10, random(0, 100));
+ // }
+ // }
+ // ```
+ // `i` and `j` would properly return values from different sequences,
+ // but `i` and `k` would return the same sequence, because their seed
+ // would be the same.
+ // (The reason their seeds would be the same is that the generator
+ // for k would be initialized when the test case is entered the second
+ // time, after the shared RNG instance was reset to the same value
+ // it had when the generator for i was initialized.)
+ seedRng( *m_config );
+
+ uint64_t testRuns = 0;
+ do {
+ m_trackerContext.startCycle();
+ m_testCaseTracker = &SectionTracker::acquire(m_trackerContext, TestCaseTracking::NameAndLocation(testInfo.name, testInfo.lineInfo));
+
+ m_reporter->testCasePartialStarting(testInfo, testRuns);
+
+ const auto beforeRunTotals = m_totals;
+ std::string oneRunCout, oneRunCerr;
+ runCurrentTest(oneRunCout, oneRunCerr);
+ redirectedCout += oneRunCout;
+ redirectedCerr += oneRunCerr;
+
+ const auto singleRunTotals = m_totals.delta(beforeRunTotals);
+ auto statsForOneRun = TestCaseStats(testInfo, singleRunTotals, oneRunCout, oneRunCerr, aborting());
+
+ m_reporter->testCasePartialEnded(statsForOneRun, testRuns);
+ ++testRuns;
+ } while (!m_testCaseTracker->isSuccessfullyCompleted() && !aborting());
+
+ Totals deltaTotals = m_totals.delta(prevTotals);
+ if (testInfo.expectedToFail() && deltaTotals.testCases.passed > 0) {
+ deltaTotals.assertions.failed++;
+ deltaTotals.testCases.passed--;
+ deltaTotals.testCases.failed++;
+ }
+ m_totals.testCases += deltaTotals.testCases;
+ m_reporter->testCaseEnded(TestCaseStats(testInfo,
+ deltaTotals,
+ redirectedCout,
+ redirectedCerr,
+ aborting()));
+
+ m_activeTestCase = nullptr;
+ m_testCaseTracker = nullptr;
+
+ return deltaTotals;
+ }
+
+
+ void RunContext::assertionEnded(AssertionResult const & result) {
+ if (result.getResultType() == ResultWas::Ok) {
+ m_totals.assertions.passed++;
+ m_lastAssertionPassed = true;
+ } else if (!result.succeeded()) {
+ m_lastAssertionPassed = false;
+ if (result.isOk()) {
+ }
+ else if( m_activeTestCase->getTestCaseInfo().okToFail() )
+ m_totals.assertions.failedButOk++;
+ else
+ m_totals.assertions.failed++;
+ }
+ else {
+ m_lastAssertionPassed = true;
+ }
+
+ m_reporter->assertionEnded(AssertionStats(result, m_messages, m_totals));
+
+ if (result.getResultType() != ResultWas::Warning)
+ m_messageScopes.clear();
+
+ // Reset working state
+ resetAssertionInfo();
+ m_lastResult = result;
+ }
+ void RunContext::resetAssertionInfo() {
+ m_lastAssertionInfo.macroName = StringRef();
+ m_lastAssertionInfo.capturedExpression = "{Unknown expression after the reported line}"_sr;
+ }
+
+ bool RunContext::sectionStarted(SectionInfo const & sectionInfo, Counts & assertions) {
+ ITracker& sectionTracker = SectionTracker::acquire(m_trackerContext, TestCaseTracking::NameAndLocation(sectionInfo.name, sectionInfo.lineInfo));
+ if (!sectionTracker.isOpen())
+ return false;
+ m_activeSections.push_back(&sectionTracker);
+
+ m_lastAssertionInfo.lineInfo = sectionInfo.lineInfo;
+
+ m_reporter->sectionStarting(sectionInfo);
+
+ assertions = m_totals.assertions;
+
+ return true;
+ }
+ auto RunContext::acquireGeneratorTracker( StringRef generatorName, SourceLineInfo const& lineInfo ) -> IGeneratorTracker& {
+ using namespace Generators;
+ GeneratorTracker& tracker = GeneratorTracker::acquire(m_trackerContext,
+ TestCaseTracking::NameAndLocation( static_cast<std::string>(generatorName), lineInfo ) );
+ m_lastAssertionInfo.lineInfo = lineInfo;
+ return tracker;
+ }
+
+ bool RunContext::testForMissingAssertions(Counts& assertions) {
+ if (assertions.total() != 0)
+ return false;
+ if (!m_config->warnAboutMissingAssertions())
+ return false;
+ if (m_trackerContext.currentTracker().hasChildren())
+ return false;
+ m_totals.assertions.failed++;
+ assertions.failed++;
+ return true;
+ }
+
+ void RunContext::sectionEnded(SectionEndInfo const & endInfo) {
+ Counts assertions = m_totals.assertions - endInfo.prevAssertions;
+ bool missingAssertions = testForMissingAssertions(assertions);
+
+ if (!m_activeSections.empty()) {
+ m_activeSections.back()->close();
+ m_activeSections.pop_back();
+ }
+
+ m_reporter->sectionEnded(SectionStats(endInfo.sectionInfo, assertions, endInfo.durationInSeconds, missingAssertions));
+ m_messages.clear();
+ m_messageScopes.clear();
+ }
+
+ void RunContext::sectionEndedEarly(SectionEndInfo const & endInfo) {
+ if (m_unfinishedSections.empty())
+ m_activeSections.back()->fail();
+ else
+ m_activeSections.back()->close();
+ m_activeSections.pop_back();
+
+ m_unfinishedSections.push_back(endInfo);
+ }
+
+ void RunContext::benchmarkPreparing( StringRef name ) {
+ m_reporter->benchmarkPreparing(name);
+ }
+ void RunContext::benchmarkStarting( BenchmarkInfo const& info ) {
+ m_reporter->benchmarkStarting( info );
+ }
+ void RunContext::benchmarkEnded( BenchmarkStats<> const& stats ) {
+ m_reporter->benchmarkEnded( stats );
+ }
+ void RunContext::benchmarkFailed( StringRef error ) {
+ m_reporter->benchmarkFailed( error );
+ }
+
+ void RunContext::pushScopedMessage(MessageInfo const & message) {
+ m_messages.push_back(message);
+ }
+
+ void RunContext::popScopedMessage(MessageInfo const & message) {
+ m_messages.erase(std::remove(m_messages.begin(), m_messages.end(), message), m_messages.end());
+ }
+
+ void RunContext::emplaceUnscopedMessage( MessageBuilder const& builder ) {
+ m_messageScopes.emplace_back( builder );
+ }
+
+ std::string RunContext::getCurrentTestName() const {
+ return m_activeTestCase
+ ? m_activeTestCase->getTestCaseInfo().name
+ : std::string();
+ }
+
+ const AssertionResult * RunContext::getLastResult() const {
+ return &(*m_lastResult);
+ }
+
+ void RunContext::exceptionEarlyReported() {
+ m_shouldReportUnexpected = false;
+ }
+
+ void RunContext::handleFatalErrorCondition( StringRef message ) {
+ // First notify reporter that bad things happened
+ m_reporter->fatalErrorEncountered(message);
+
+ // Don't rebuild the result -- the stringification itself can cause more fatal errors
+ // Instead, fake a result data.
+ AssertionResultData tempResult( ResultWas::FatalErrorCondition, { false } );
+ tempResult.message = static_cast<std::string>(message);
+ AssertionResult result(m_lastAssertionInfo, tempResult);
+
+ assertionEnded(result);
+
+ handleUnfinishedSections();
+
+ // Recreate section for test case (as we will lose the one that was in scope)
+ auto const& testCaseInfo = m_activeTestCase->getTestCaseInfo();
+ SectionInfo testCaseSection(testCaseInfo.lineInfo, testCaseInfo.name);
+
+ Counts assertions;
+ assertions.failed = 1;
+ SectionStats testCaseSectionStats(testCaseSection, assertions, 0, false);
+ m_reporter->sectionEnded(testCaseSectionStats);
+
+ auto const& testInfo = m_activeTestCase->getTestCaseInfo();
+
+ Totals deltaTotals;
+ deltaTotals.testCases.failed = 1;
+ deltaTotals.assertions.failed = 1;
+ m_reporter->testCaseEnded(TestCaseStats(testInfo,
+ deltaTotals,
+ std::string(),
+ std::string(),
+ false));
+ m_totals.testCases.failed++;
+ m_reporter->testRunEnded(TestRunStats(m_runInfo, m_totals, false));
+ }
+
+ bool RunContext::lastAssertionPassed() {
+ return m_lastAssertionPassed;
+ }
+
+ void RunContext::assertionPassed() {
+ m_lastAssertionPassed = true;
+ ++m_totals.assertions.passed;
+ resetAssertionInfo();
+ m_messageScopes.clear();
+ }
+
+ bool RunContext::aborting() const {
+ return m_totals.assertions.failed >= static_cast<std::size_t>(m_config->abortAfter());
+ }
+
+ void RunContext::runCurrentTest(std::string & redirectedCout, std::string & redirectedCerr) {
+ auto const& testCaseInfo = m_activeTestCase->getTestCaseInfo();
+ SectionInfo testCaseSection(testCaseInfo.lineInfo, testCaseInfo.name);
+ m_reporter->sectionStarting(testCaseSection);
+ Counts prevAssertions = m_totals.assertions;
+ double duration = 0;
+ m_shouldReportUnexpected = true;
+ m_lastAssertionInfo = { "TEST_CASE"_sr, testCaseInfo.lineInfo, StringRef(), ResultDisposition::Normal };
+
+ Timer timer;
+ CATCH_TRY {
+ if (m_reporter->getPreferences().shouldRedirectStdOut) {
+#if !defined(CATCH_CONFIG_EXPERIMENTAL_REDIRECT)
+ RedirectedStreams redirectedStreams(redirectedCout, redirectedCerr);
+
+ timer.start();
+ invokeActiveTestCase();
+#else
+ OutputRedirect r(redirectedCout, redirectedCerr);
+ timer.start();
+ invokeActiveTestCase();
+#endif
+ } else {
+ timer.start();
+ invokeActiveTestCase();
+ }
+ duration = timer.getElapsedSeconds();
+ } CATCH_CATCH_ANON (TestFailureException&) {
+ // This just means the test was aborted due to failure
+ } CATCH_CATCH_ALL {
+ // Under CATCH_CONFIG_FAST_COMPILE, unexpected exceptions under REQUIRE assertions
+ // are reported without translation at the point of origin.
+ if( m_shouldReportUnexpected ) {
+ AssertionReaction dummyReaction;
+ handleUnexpectedInflightException( m_lastAssertionInfo, translateActiveException(), dummyReaction );
+ }
+ }
+ Counts assertions = m_totals.assertions - prevAssertions;
+ bool missingAssertions = testForMissingAssertions(assertions);
+
+ m_testCaseTracker->close();
+ handleUnfinishedSections();
+ m_messages.clear();
+ m_messageScopes.clear();
+
+ SectionStats testCaseSectionStats(testCaseSection, assertions, duration, missingAssertions);
+ m_reporter->sectionEnded(testCaseSectionStats);
+ }
+
+ void RunContext::invokeActiveTestCase() {
+ // We need to engage a handler for signals/structured exceptions
+ // before running the tests themselves, or the binary can crash
+ // without failed test being reported.
+ FatalConditionHandlerGuard _(&m_fatalConditionhandler);
+ // We keep having issue where some compilers warn about an unused
+ // variable, even though the type has non-trivial constructor and
+ // destructor. This is annoying and ugly, but it makes them stfu.
+ (void)_;
+
+ m_activeTestCase->invoke();
+ }
+
+ void RunContext::handleUnfinishedSections() {
+ // If sections ended prematurely due to an exception we stored their
+ // infos here so we can tear them down outside the unwind process.
+ for (auto it = m_unfinishedSections.rbegin(),
+ itEnd = m_unfinishedSections.rend();
+ it != itEnd;
+ ++it)
+ sectionEnded(*it);
+ m_unfinishedSections.clear();
+ }
+
+ void RunContext::handleExpr(
+ AssertionInfo const& info,
+ ITransientExpression const& expr,
+ AssertionReaction& reaction
+ ) {
+ m_reporter->assertionStarting( info );
+
+ bool negated = isFalseTest( info.resultDisposition );
+ bool result = expr.getResult() != negated;
+
+ if( result ) {
+ if (!m_includeSuccessfulResults) {
+ assertionPassed();
+ }
+ else {
+ reportExpr(info, ResultWas::Ok, &expr, negated);
+ }
+ }
+ else {
+ reportExpr(info, ResultWas::ExpressionFailed, &expr, negated );
+ populateReaction( reaction );
+ }
+ }
+ void RunContext::reportExpr(
+ AssertionInfo const &info,
+ ResultWas::OfType resultType,
+ ITransientExpression const *expr,
+ bool negated ) {
+
+ m_lastAssertionInfo = info;
+ AssertionResultData data( resultType, LazyExpression( negated ) );
+
+ AssertionResult assertionResult{ info, data };
+ assertionResult.m_resultData.lazyExpression.m_transientExpression = expr;
+
+ assertionEnded( assertionResult );
+ }
+
+ void RunContext::handleMessage(
+ AssertionInfo const& info,
+ ResultWas::OfType resultType,
+ StringRef message,
+ AssertionReaction& reaction
+ ) {
+ m_reporter->assertionStarting( info );
+
+ m_lastAssertionInfo = info;
+
+ AssertionResultData data( resultType, LazyExpression( false ) );
+ data.message = static_cast<std::string>(message);
+ AssertionResult assertionResult{ m_lastAssertionInfo, data };
+ assertionEnded( assertionResult );
+ if( !assertionResult.isOk() )
+ populateReaction( reaction );
+ }
+ void RunContext::handleUnexpectedExceptionNotThrown(
+ AssertionInfo const& info,
+ AssertionReaction& reaction
+ ) {
+ handleNonExpr(info, Catch::ResultWas::DidntThrowException, reaction);
+ }
+
+ void RunContext::handleUnexpectedInflightException(
+ AssertionInfo const& info,
+ std::string const& message,
+ AssertionReaction& reaction
+ ) {
+ m_lastAssertionInfo = info;
+
+ AssertionResultData data( ResultWas::ThrewException, LazyExpression( false ) );
+ data.message = message;
+ AssertionResult assertionResult{ info, data };
+ assertionEnded( assertionResult );
+ populateReaction( reaction );
+ }
+
+ void RunContext::populateReaction( AssertionReaction& reaction ) {
+ reaction.shouldDebugBreak = m_config->shouldDebugBreak();
+ reaction.shouldThrow = aborting() || (m_lastAssertionInfo.resultDisposition & ResultDisposition::Normal);
+ }
+
+ void RunContext::handleIncomplete(
+ AssertionInfo const& info
+ ) {
+ m_lastAssertionInfo = info;
+
+ AssertionResultData data( ResultWas::ThrewException, LazyExpression( false ) );
+ data.message = "Exception translation was disabled by CATCH_CONFIG_FAST_COMPILE";
+ AssertionResult assertionResult{ info, data };
+ assertionEnded( assertionResult );
+ }
+ void RunContext::handleNonExpr(
+ AssertionInfo const &info,
+ ResultWas::OfType resultType,
+ AssertionReaction &reaction
+ ) {
+ m_lastAssertionInfo = info;
+
+ AssertionResultData data( resultType, LazyExpression( false ) );
+ AssertionResult assertionResult{ info, data };
+ assertionEnded( assertionResult );
+
+ if( !assertionResult.isOk() )
+ populateReaction( reaction );
+ }
+
+
+ IResultCapture& getResultCapture() {
+ if (auto* capture = getCurrentContext().getResultCapture())
+ return *capture;
+ else
+ CATCH_INTERNAL_ERROR("No result capture instance");
+ }
+
+ void seedRng(IConfig const& config) {
+ sharedRng().seed(config.rngSeed());
+ }
+
+ unsigned int rngSeed() {
+ return getCurrentContext().getConfig()->rngSeed();
+ }
+
+}
+
+
+
+namespace Catch {
+
+ Section::Section( SectionInfo&& info ):
+ m_info( CATCH_MOVE( info ) ),
+ m_sectionIncluded(
+ getResultCapture().sectionStarted( m_info, m_assertions ) ) {
+ // Non-"included" sections will not use the timing information
+ // anyway, so don't bother with the potential syscall.
+ if (m_sectionIncluded) {
+ m_timer.start();
+ }
+ }
+
+ Section::~Section() {
+ if( m_sectionIncluded ) {
+ SectionEndInfo endInfo{ m_info, m_assertions, m_timer.getElapsedSeconds() };
+ if( uncaught_exceptions() )
+ getResultCapture().sectionEndedEarly( endInfo );
+ else
+ getResultCapture().sectionEnded( endInfo );
+ }
+ }
+
+ // This indicates whether the section should be executed or not
+ Section::operator bool() const {
+ return m_sectionIncluded;
+ }
+
+
+} // end namespace Catch
+
+
+
+#include <vector>
+
+namespace Catch {
+
+ namespace {
+ static auto getSingletons() -> std::vector<ISingleton*>*& {
+ static std::vector<ISingleton*>* g_singletons = nullptr;
+ if( !g_singletons )
+ g_singletons = new std::vector<ISingleton*>();
+ return g_singletons;
+ }
+ }
+
+ ISingleton::~ISingleton() = default;
+
+ void addSingleton(ISingleton* singleton ) {
+ getSingletons()->push_back( singleton );
+ }
+ void cleanupSingletons() {
+ auto& singletons = getSingletons();
+ for( auto singleton : *singletons )
+ delete singleton;
+ delete singletons;
+ singletons = nullptr;
+ }
+
+} // namespace Catch
+
+
+
+#include <cstring>
+#include <ostream>
+
+namespace Catch {
+
+ bool SourceLineInfo::operator == ( SourceLineInfo const& other ) const noexcept {
+ return line == other.line && (file == other.file || std::strcmp(file, other.file) == 0);
+ }
+ bool SourceLineInfo::operator < ( SourceLineInfo const& other ) const noexcept {
+ // We can assume that the same file will usually have the same pointer.
+ // Thus, if the pointers are the same, there is no point in calling the strcmp
+ return line < other.line || ( line == other.line && file != other.file && (std::strcmp(file, other.file) < 0));
+ }
+
+ std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ) {
+#ifndef __GNUG__
+ os << info.file << '(' << info.line << ')';
+#else
+ os << info.file << ':' << info.line;
+#endif
+ return os;
+ }
+
+} // end namespace Catch
+
+
+
+
+namespace Catch {
+#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
+ void StartupExceptionRegistry::add( std::exception_ptr const& exception ) noexcept {
+ CATCH_TRY {
+ m_exceptions.push_back(exception);
+ } CATCH_CATCH_ALL {
+ // If we run out of memory during start-up there's really not a lot more we can do about it
+ std::terminate();
+ }
+ }
+
+ std::vector<std::exception_ptr> const& StartupExceptionRegistry::getExceptions() const noexcept {
+ return m_exceptions;
+ }
+#endif
+
+} // end namespace Catch
+
+
+
+
+
+#include <iostream>
+
+namespace Catch {
+
+// If you #define this you must implement these functions
+#if !defined( CATCH_CONFIG_NOSTDOUT )
+ std::ostream& cout() { return std::cout; }
+ std::ostream& cerr() { return std::cerr; }
+ std::ostream& clog() { return std::clog; }
+#endif
+
+} // namespace Catch
+
+
+
+#include <algorithm>
+#include <ostream>
+#include <cstring>
+#include <cctype>
+#include <vector>
+
+namespace Catch {
+
+ bool startsWith( std::string const& s, std::string const& prefix ) {
+ return s.size() >= prefix.size() && std::equal(prefix.begin(), prefix.end(), s.begin());
+ }
+ bool startsWith( StringRef s, char prefix ) {
+ return !s.empty() && s[0] == prefix;
+ }
+ bool endsWith( std::string const& s, std::string const& suffix ) {
+ return s.size() >= suffix.size() && std::equal(suffix.rbegin(), suffix.rend(), s.rbegin());
+ }
+ bool endsWith( std::string const& s, char suffix ) {
+ return !s.empty() && s[s.size()-1] == suffix;
+ }
+ bool contains( std::string const& s, std::string const& infix ) {
+ return s.find( infix ) != std::string::npos;
+ }
+ void toLowerInPlace( std::string& s ) {
+ std::transform( s.begin(), s.end(), s.begin(), []( char c ) {
+ return toLower( c );
+ } );
+ }
+ std::string toLower( std::string const& s ) {
+ std::string lc = s;
+ toLowerInPlace( lc );
+ return lc;
+ }
+ char toLower(char c) {
+ return static_cast<char>(std::tolower(static_cast<unsigned char>(c)));
+ }
+
+ std::string trim( std::string const& str ) {
+ static char const* whitespaceChars = "\n\r\t ";
+ std::string::size_type start = str.find_first_not_of( whitespaceChars );
+ std::string::size_type end = str.find_last_not_of( whitespaceChars );
+
+ return start != std::string::npos ? str.substr( start, 1+end-start ) : std::string();
+ }
+
+ StringRef trim(StringRef ref) {
+ const auto is_ws = [](char c) {
+ return c == ' ' || c == '\t' || c == '\n' || c == '\r';
+ };
+ size_t real_begin = 0;
+ while (real_begin < ref.size() && is_ws(ref[real_begin])) { ++real_begin; }
+ size_t real_end = ref.size();
+ while (real_end > real_begin && is_ws(ref[real_end - 1])) { --real_end; }
+
+ return ref.substr(real_begin, real_end - real_begin);
+ }
+
+ bool replaceInPlace( std::string& str, std::string const& replaceThis, std::string const& withThis ) {
+ bool replaced = false;
+ std::size_t i = str.find( replaceThis );
+ while( i != std::string::npos ) {
+ replaced = true;
+ str = str.substr( 0, i ) + withThis + str.substr( i+replaceThis.size() );
+ if( i < str.size()-withThis.size() )
+ i = str.find( replaceThis, i+withThis.size() );
+ else
+ i = std::string::npos;
+ }
+ return replaced;
+ }
+
+ std::vector<StringRef> splitStringRef( StringRef str, char delimiter ) {
+ std::vector<StringRef> subStrings;
+ std::size_t start = 0;
+ for(std::size_t pos = 0; pos < str.size(); ++pos ) {
+ if( str[pos] == delimiter ) {
+ if( pos - start > 1 )
+ subStrings.push_back( str.substr( start, pos-start ) );
+ start = pos+1;
+ }
+ }
+ if( start < str.size() )
+ subStrings.push_back( str.substr( start, str.size()-start ) );
+ return subStrings;
+ }
+
+ std::ostream& operator << ( std::ostream& os, pluralise const& pluraliser ) {
+ os << pluraliser.m_count << ' ' << pluraliser.m_label;
+ if( pluraliser.m_count != 1 )
+ os << 's';
+ return os;
+ }
+
+}
+
+
+
+#include <algorithm>
+#include <ostream>
+#include <cstring>
+#include <cstdint>
+
+namespace Catch {
+ StringRef::StringRef( char const* rawChars ) noexcept
+ : StringRef( rawChars, std::strlen(rawChars) )
+ {}
+
+ auto StringRef::operator == ( StringRef other ) const noexcept -> bool {
+ return m_size == other.m_size
+ && (std::memcmp( m_start, other.m_start, m_size ) == 0);
+ }
+
+ bool StringRef::operator<(StringRef rhs) const noexcept {
+ if (m_size < rhs.m_size) {
+ return strncmp(m_start, rhs.m_start, m_size) <= 0;
+ }
+ return strncmp(m_start, rhs.m_start, rhs.m_size) < 0;
+ }
+
+ int StringRef::compare( StringRef rhs ) const {
+ auto cmpResult =
+ strncmp( m_start, rhs.m_start, std::min( m_size, rhs.m_size ) );
+
+ // This means that strncmp found a difference before the strings
+ // ended, and we can return it directly
+ if ( cmpResult != 0 ) {
+ return cmpResult;
+ }
+
+ // If strings are equal up to length, then their comparison results on
+ // their size
+ if ( m_size < rhs.m_size ) {
+ return -1;
+ } else if ( m_size > rhs.m_size ) {
+ return 1;
+ } else {
+ return 0;
+ }
+ }
+
+ auto operator << ( std::ostream& os, StringRef str ) -> std::ostream& {
+ return os.write(str.data(), static_cast<std::streamsize>(str.size()));
+ }
+
+ std::string operator+(StringRef lhs, StringRef rhs) {
+ std::string ret;
+ ret.reserve(lhs.size() + rhs.size());
+ ret += lhs;
+ ret += rhs;
+ return ret;
+ }
+
+ auto operator+=( std::string& lhs, StringRef rhs ) -> std::string& {
+ lhs.append(rhs.data(), rhs.size());
+ return lhs;
+ }
+
+} // namespace Catch
+
+
+
+namespace Catch {
+
+ TagAliasRegistry::~TagAliasRegistry() {}
+
+ TagAlias const* TagAliasRegistry::find( std::string const& alias ) const {
+ auto it = m_registry.find( alias );
+ if( it != m_registry.end() )
+ return &(it->second);
+ else
+ return nullptr;
+ }
+
+ std::string TagAliasRegistry::expandAliases( std::string const& unexpandedTestSpec ) const {
+ std::string expandedTestSpec = unexpandedTestSpec;
+ for( auto const& registryKvp : m_registry ) {
+ std::size_t pos = expandedTestSpec.find( registryKvp.first );
+ if( pos != std::string::npos ) {
+ expandedTestSpec = expandedTestSpec.substr( 0, pos ) +
+ registryKvp.second.tag +
+ expandedTestSpec.substr( pos + registryKvp.first.size() );
+ }
+ }
+ return expandedTestSpec;
+ }
+
+ void TagAliasRegistry::add( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ) {
+ CATCH_ENFORCE( startsWith(alias, "[@") && endsWith(alias, ']'),
+ "error: tag alias, '" << alias << "' is not of the form [@alias name].\n" << lineInfo );
+
+ CATCH_ENFORCE( m_registry.insert(std::make_pair(alias, TagAlias(tag, lineInfo))).second,
+ "error: tag alias, '" << alias << "' already registered.\n"
+ << "\tFirst seen at: " << find(alias)->lineInfo << "\n"
+ << "\tRedefined at: " << lineInfo );
+ }
+
+ ITagAliasRegistry::~ITagAliasRegistry() = default;
+
+ ITagAliasRegistry const& ITagAliasRegistry::get() {
+ return getRegistryHub().getTagAliasRegistry();
+ }
+
+} // end namespace Catch
+
+
+
+
+namespace Catch {
+ TestCaseInfoHasher::TestCaseInfoHasher( hash_t seed ): m_seed( seed ) {}
+
+ uint32_t TestCaseInfoHasher::operator()( TestCaseInfo const& t ) const {
+ // FNV-1a hash algorithm that is designed for uniqueness:
+ const hash_t prime = 1099511628211u;
+ hash_t hash = 14695981039346656037u;
+ for ( const char c : t.name ) {
+ hash ^= c;
+ hash *= prime;
+ }
+ for ( const char c : t.className ) {
+ hash ^= c;
+ hash *= prime;
+ }
+ for ( const Tag& tag : t.tags ) {
+ for ( const char c : tag.original ) {
+ hash ^= c;
+ hash *= prime;
+ }
+ }
+ hash ^= m_seed;
+ hash *= prime;
+ const uint32_t low{ static_cast<uint32_t>( hash ) };
+ const uint32_t high{ static_cast<uint32_t>( hash >> 32 ) };
+ return low * high;
+ }
+} // namespace Catch
+
+
+
+
+#include <algorithm>
+#include <set>
+
+namespace Catch {
+
+ std::vector<TestCaseHandle> sortTests( IConfig const& config, std::vector<TestCaseHandle> const& unsortedTestCases ) {
+ switch (config.runOrder()) {
+ case TestRunOrder::Declared:
+ return unsortedTestCases;
+
+ case TestRunOrder::LexicographicallySorted: {
+ std::vector<TestCaseHandle> sorted = unsortedTestCases;
+ std::sort(
+ sorted.begin(),
+ sorted.end(),
+ []( TestCaseHandle const& lhs, TestCaseHandle const& rhs ) {
+ return lhs.getTestCaseInfo() < rhs.getTestCaseInfo();
+ }
+ );
+ return sorted;
+ }
+ case TestRunOrder::Randomized: {
+ seedRng(config);
+ using TestWithHash = std::pair<TestCaseInfoHasher::hash_t, TestCaseHandle>;
+
+ TestCaseInfoHasher h{ config.rngSeed() };
+ std::vector<TestWithHash> indexed_tests;
+ indexed_tests.reserve(unsortedTestCases.size());
+
+ for (auto const& handle : unsortedTestCases) {
+ indexed_tests.emplace_back(h(handle.getTestCaseInfo()), handle);
+ }
+
+ std::sort( indexed_tests.begin(),
+ indexed_tests.end(),
+ []( TestWithHash const& lhs, TestWithHash const& rhs ) {
+ if ( lhs.first == rhs.first ) {
+ return lhs.second.getTestCaseInfo() <
+ rhs.second.getTestCaseInfo();
+ }
+ return lhs.first < rhs.first;
+ } );
+
+ std::vector<TestCaseHandle> randomized;
+ randomized.reserve(indexed_tests.size());
+
+ for (auto const& indexed : indexed_tests) {
+ randomized.push_back(indexed.second);
+ }
+
+ return randomized;
+ }
+ }
+
+ CATCH_INTERNAL_ERROR("Unknown test order value!");
+ }
+
+ bool isThrowSafe( TestCaseHandle const& testCase, IConfig const& config ) {
+ return !testCase.getTestCaseInfo().throws() || config.allowThrows();
+ }
+
+ bool matchTest( TestCaseHandle const& testCase, TestSpec const& testSpec, IConfig const& config ) {
+ return testSpec.matches( testCase.getTestCaseInfo() ) && isThrowSafe( testCase, config );
+ }
+
+ void
+ enforceNoDuplicateTestCases( std::vector<TestCaseHandle> const& tests ) {
+ auto testInfoCmp = []( TestCaseInfo const* lhs,
+ TestCaseInfo const* rhs ) {
+ return *lhs < *rhs;
+ };
+ std::set<TestCaseInfo const*, decltype(testInfoCmp)> seenTests(testInfoCmp);
+ for ( auto const& test : tests ) {
+ const auto infoPtr = &test.getTestCaseInfo();
+ const auto prev = seenTests.insert( infoPtr );
+ CATCH_ENFORCE(
+ prev.second,
+ "error: test case \"" << infoPtr->name << "\", with tags \""
+ << infoPtr->tagsAsString() << "\" already defined.\n"
+ << "\tFirst seen at " << ( *prev.first )->lineInfo << "\n"
+ << "\tRedefined at " << infoPtr->lineInfo );
+ }
+ }
+
+ std::vector<TestCaseHandle> filterTests( std::vector<TestCaseHandle> const& testCases, TestSpec const& testSpec, IConfig const& config ) {
+ std::vector<TestCaseHandle> filtered;
+ filtered.reserve( testCases.size() );
+ for (auto const& testCase : testCases) {
+ if ((!testSpec.hasFilters() && !testCase.getTestCaseInfo().isHidden()) ||
+ (testSpec.hasFilters() && matchTest(testCase, testSpec, config))) {
+ filtered.push_back(testCase);
+ }
+ }
+ return createShard(filtered, config.shardCount(), config.shardIndex());
+ }
+ std::vector<TestCaseHandle> const& getAllTestCasesSorted( IConfig const& config ) {
+ return getRegistryHub().getTestCaseRegistry().getAllTestsSorted( config );
+ }
+
+ void TestRegistry::registerTest(Detail::unique_ptr<TestCaseInfo> testInfo, Detail::unique_ptr<ITestInvoker> testInvoker) {
+ m_handles.emplace_back(testInfo.get(), testInvoker.get());
+ m_viewed_test_infos.push_back(testInfo.get());
+ m_owned_test_infos.push_back(CATCH_MOVE(testInfo));
+ m_invokers.push_back(CATCH_MOVE(testInvoker));
+ }
+
+ std::vector<TestCaseInfo*> const& TestRegistry::getAllInfos() const {
+ return m_viewed_test_infos;
+ }
+
+ std::vector<TestCaseHandle> const& TestRegistry::getAllTests() const {
+ return m_handles;
+ }
+ std::vector<TestCaseHandle> const& TestRegistry::getAllTestsSorted( IConfig const& config ) const {
+ if( m_sortedFunctions.empty() )
+ enforceNoDuplicateTestCases( m_handles );
+
+ if( m_currentSortOrder != config.runOrder() || m_sortedFunctions.empty() ) {
+ m_sortedFunctions = sortTests( config, m_handles );
+ m_currentSortOrder = config.runOrder();
+ }
+ return m_sortedFunctions;
+ }
+
+
+
+ ///////////////////////////////////////////////////////////////////////////
+ void TestInvokerAsFunction::invoke() const {
+ m_testAsFunction();
+ }
+
+} // end namespace Catch
+
+
+
+
+#include <algorithm>
+#include <cassert>
+
+#if defined(__clang__)
+# pragma clang diagnostic push
+# pragma clang diagnostic ignored "-Wexit-time-destructors"
+#endif
+
+namespace Catch {
+namespace TestCaseTracking {
+
+ NameAndLocation::NameAndLocation( std::string const& _name, SourceLineInfo const& _location )
+ : name( _name ),
+ location( _location )
+ {}
+
+
+ ITracker::~ITracker() = default;
+
+ void ITracker::markAsNeedingAnotherRun() {
+ m_runState = NeedsAnotherRun;
+ }
+
+ void ITracker::addChild( ITrackerPtr&& child ) {
+ m_children.push_back( CATCH_MOVE(child) );
+ }
+
+ ITracker* ITracker::findChild( NameAndLocation const& nameAndLocation ) {
+ auto it = std::find_if(
+ m_children.begin(),
+ m_children.end(),
+ [&nameAndLocation]( ITrackerPtr const& tracker ) {
+ return tracker->nameAndLocation().location ==
+ nameAndLocation.location &&
+ tracker->nameAndLocation().name == nameAndLocation.name;
+ } );
+ return ( it != m_children.end() ) ? it->get() : nullptr;
+ }
+
+ bool ITracker::isSectionTracker() const { return false; }
+ bool ITracker::isGeneratorTracker() const { return false; }
+
+ bool ITracker::isSuccessfullyCompleted() const {
+ return m_runState == CompletedSuccessfully;
+ }
+
+ bool ITracker::isOpen() const {
+ return m_runState != NotStarted && !isComplete();
+ }
+
+ bool ITracker::hasStarted() const { return m_runState != NotStarted; }
+
+ void ITracker::openChild() {
+ if (m_runState != ExecutingChildren) {
+ m_runState = ExecutingChildren;
+ if (m_parent) {
+ m_parent->openChild();
+ }
+ }
+ }
+
+ ITracker& TrackerContext::startRun() {
+ using namespace std::string_literals;
+ m_rootTracker = Catch::Detail::make_unique<SectionTracker>(
+ NameAndLocation( "{root}"s, CATCH_INTERNAL_LINEINFO ),
+ *this,
+ nullptr );
+ m_currentTracker = nullptr;
+ m_runState = Executing;
+ return *m_rootTracker;
+ }
+
+ void TrackerContext::endRun() {
+ m_rootTracker.reset();
+ m_currentTracker = nullptr;
+ m_runState = NotStarted;
+ }
+
+ void TrackerContext::startCycle() {
+ m_currentTracker = m_rootTracker.get();
+ m_runState = Executing;
+ }
+ void TrackerContext::completeCycle() {
+ m_runState = CompletedCycle;
+ }
+
+ bool TrackerContext::completedCycle() const {
+ return m_runState == CompletedCycle;
+ }
+ ITracker& TrackerContext::currentTracker() {
+ return *m_currentTracker;
+ }
+ void TrackerContext::setCurrentTracker( ITracker* tracker ) {
+ m_currentTracker = tracker;
+ }
+
+
+ TrackerBase::TrackerBase( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent ):
+ ITracker(nameAndLocation, parent),
+ m_ctx( ctx )
+ {}
+
+ bool TrackerBase::isComplete() const {
+ return m_runState == CompletedSuccessfully || m_runState == Failed;
+ }
+
+ void TrackerBase::open() {
+ m_runState = Executing;
+ moveToThis();
+ if( m_parent )
+ m_parent->openChild();
+ }
+
+ void TrackerBase::close() {
+
+ // Close any still open children (e.g. generators)
+ while( &m_ctx.currentTracker() != this )
+ m_ctx.currentTracker().close();
+
+ switch( m_runState ) {
+ case NeedsAnotherRun:
+ break;
+
+ case Executing:
+ m_runState = CompletedSuccessfully;
+ break;
+ case ExecutingChildren:
+ if( std::all_of(m_children.begin(), m_children.end(), [](ITrackerPtr const& t){ return t->isComplete(); }) )
+ m_runState = CompletedSuccessfully;
+ break;
+
+ case NotStarted:
+ case CompletedSuccessfully:
+ case Failed:
+ CATCH_INTERNAL_ERROR( "Illogical state: " << m_runState );
+
+ default:
+ CATCH_INTERNAL_ERROR( "Unknown state: " << m_runState );
+ }
+ moveToParent();
+ m_ctx.completeCycle();
+ }
+ void TrackerBase::fail() {
+ m_runState = Failed;
+ if( m_parent )
+ m_parent->markAsNeedingAnotherRun();
+ moveToParent();
+ m_ctx.completeCycle();
+ }
+
+ void TrackerBase::moveToParent() {
+ assert( m_parent );
+ m_ctx.setCurrentTracker( m_parent );
+ }
+ void TrackerBase::moveToThis() {
+ m_ctx.setCurrentTracker( this );
+ }
+
+ SectionTracker::SectionTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent )
+ : TrackerBase( nameAndLocation, ctx, parent ),
+ m_trimmed_name(trim(nameAndLocation.name))
+ {
+ if( parent ) {
+ while( !parent->isSectionTracker() )
+ parent = parent->parent();
+
+ SectionTracker& parentSection = static_cast<SectionTracker&>( *parent );
+ addNextFilters( parentSection.m_filters );
+ }
+ }
+
+ bool SectionTracker::isComplete() const {
+ bool complete = true;
+
+ if (m_filters.empty()
+ || m_filters[0].empty()
+ || std::find(m_filters.begin(), m_filters.end(), m_trimmed_name) != m_filters.end()) {
+ complete = TrackerBase::isComplete();
+ }
+ return complete;
+ }
+
+ bool SectionTracker::isSectionTracker() const { return true; }
+
+ SectionTracker& SectionTracker::acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation ) {
+ SectionTracker* section;
+
+ ITracker& currentTracker = ctx.currentTracker();
+ if ( ITracker* childTracker =
+ currentTracker.findChild( nameAndLocation ) ) {
+ assert( childTracker );
+ assert( childTracker->isSectionTracker() );
+ section = static_cast<SectionTracker*>( childTracker );
+ } else {
+ auto newSection = Catch::Detail::make_unique<SectionTracker>(
+ nameAndLocation, ctx, &currentTracker );
+ section = newSection.get();
+ currentTracker.addChild( CATCH_MOVE( newSection ) );
+ }
+ if( !ctx.completedCycle() )
+ section->tryOpen();
+ return *section;
+ }
+
+ void SectionTracker::tryOpen() {
+ if( !isComplete() )
+ open();
+ }
+
+ void SectionTracker::addInitialFilters( std::vector<std::string> const& filters ) {
+ if( !filters.empty() ) {
+ m_filters.reserve( m_filters.size() + filters.size() + 2 );
+ m_filters.emplace_back(StringRef{}); // Root - should never be consulted
+ m_filters.emplace_back(StringRef{}); // Test Case - not a section filter
+ m_filters.insert( m_filters.end(), filters.begin(), filters.end() );
+ }
+ }
+ void SectionTracker::addNextFilters( std::vector<StringRef> const& filters ) {
+ if( filters.size() > 1 )
+ m_filters.insert( m_filters.end(), filters.begin()+1, filters.end() );
+ }
+
+ std::vector<StringRef> const& SectionTracker::getFilters() const {
+ return m_filters;
+ }
+
+ StringRef SectionTracker::trimmedName() const {
+ return m_trimmed_name;
+ }
+
+} // namespace TestCaseTracking
+
+} // namespace Catch
+
+#if defined(__clang__)
+# pragma clang diagnostic pop
+#endif
+
+
+
+#include <algorithm>
+#include <iterator>
+
+namespace Catch {
+
+ namespace {
+ StringRef extractClassName( StringRef classOrMethodName ) {
+ if ( !startsWith( classOrMethodName, '&' ) ) {
+ return classOrMethodName;
+ }
+
+ // Remove the leading '&' to avoid having to special case it later
+ const auto methodName =
+ classOrMethodName.substr( 1, classOrMethodName.size() );
+
+ auto reverseStart = std::make_reverse_iterator( methodName.end() );
+ auto reverseEnd = std::make_reverse_iterator( methodName.begin() );
+
+ // We make a simplifying assumption that ":" is only present
+ // in the input as part of "::" from C++ typenames (this is
+ // relatively safe assumption because the input is generated
+ // as stringification of type through preprocessor).
+ auto lastColons = std::find( reverseStart, reverseEnd, ':' ) + 1;
+ auto secondLastColons =
+ std::find( lastColons + 1, reverseEnd, ':' );
+
+ auto const startIdx = reverseEnd - secondLastColons;
+ auto const classNameSize = secondLastColons - lastColons - 1;
+
+ return methodName.substr(
+ static_cast<std::size_t>( startIdx ),
+ static_cast<std::size_t>( classNameSize ) );
+ }
+ } // namespace
+
+ Detail::unique_ptr<ITestInvoker> makeTestInvoker( void(*testAsFunction)() ) {
+ return Detail::make_unique<TestInvokerAsFunction>( testAsFunction );
+ }
+
+ AutoReg::AutoReg( Detail::unique_ptr<ITestInvoker> invoker, SourceLineInfo const& lineInfo, StringRef classOrMethod, NameAndTags const& nameAndTags ) noexcept {
+ CATCH_TRY {
+ getMutableRegistryHub()
+ .registerTest(
+ makeTestCaseInfo(
+ extractClassName( classOrMethod ),
+ nameAndTags,
+ lineInfo),
+ CATCH_MOVE(invoker)
+ );
+ } CATCH_CATCH_ALL {
+ // Do not throw when constructing global objects, instead register the exception to be processed later
+ getMutableRegistryHub().registerStartupException();
+ }
+ }
+}
+
+
+
+
+
+namespace Catch {
+
+ TestSpecParser::TestSpecParser( ITagAliasRegistry const& tagAliases ) : m_tagAliases( &tagAliases ) {}
+
+ TestSpecParser& TestSpecParser::parse( std::string const& arg ) {
+ m_mode = None;
+ m_exclusion = false;
+ m_arg = m_tagAliases->expandAliases( arg );
+ m_escapeChars.clear();
+ m_substring.reserve(m_arg.size());
+ m_patternName.reserve(m_arg.size());
+ m_realPatternPos = 0;
+
+ for( m_pos = 0; m_pos < m_arg.size(); ++m_pos )
+ //if visitChar fails
+ if( !visitChar( m_arg[m_pos] ) ){
+ m_testSpec.m_invalidSpecs.push_back(arg);
+ break;
+ }
+ endMode();
+ return *this;
+ }
+ TestSpec TestSpecParser::testSpec() {
+ addFilter();
+ return CATCH_MOVE(m_testSpec);
+ }
+ bool TestSpecParser::visitChar( char c ) {
+ if( (m_mode != EscapedName) && (c == '\\') ) {
+ escape();
+ addCharToPattern(c);
+ return true;
+ }else if((m_mode != EscapedName) && (c == ',') ) {
+ return separate();
+ }
+
+ switch( m_mode ) {
+ case None:
+ if( processNoneChar( c ) )
+ return true;
+ break;
+ case Name:
+ processNameChar( c );
+ break;
+ case EscapedName:
+ endMode();
+ addCharToPattern(c);
+ return true;
+ default:
+ case Tag:
+ case QuotedName:
+ if( processOtherChar( c ) )
+ return true;
+ break;
+ }
+
+ m_substring += c;
+ if( !isControlChar( c ) ) {
+ m_patternName += c;
+ m_realPatternPos++;
+ }
+ return true;
+ }
+ // Two of the processing methods return true to signal the caller to return
+ // without adding the given character to the current pattern strings
+ bool TestSpecParser::processNoneChar( char c ) {
+ switch( c ) {
+ case ' ':
+ return true;
+ case '~':
+ m_exclusion = true;
+ return false;
+ case '[':
+ startNewMode( Tag );
+ return false;
+ case '"':
+ startNewMode( QuotedName );
+ return false;
+ default:
+ startNewMode( Name );
+ return false;
+ }
+ }
+ void TestSpecParser::processNameChar( char c ) {
+ if( c == '[' ) {
+ if( m_substring == "exclude:" )
+ m_exclusion = true;
+ else
+ endMode();
+ startNewMode( Tag );
+ }
+ }
+ bool TestSpecParser::processOtherChar( char c ) {
+ if( !isControlChar( c ) )
+ return false;
+ m_substring += c;
+ endMode();
+ return true;
+ }
+ void TestSpecParser::startNewMode( Mode mode ) {
+ m_mode = mode;
+ }
+ void TestSpecParser::endMode() {
+ switch( m_mode ) {
+ case Name:
+ case QuotedName:
+ return addNamePattern();
+ case Tag:
+ return addTagPattern();
+ case EscapedName:
+ revertBackToLastMode();
+ return;
+ case None:
+ default:
+ return startNewMode( None );
+ }
+ }
+ void TestSpecParser::escape() {
+ saveLastMode();
+ m_mode = EscapedName;
+ m_escapeChars.push_back(m_realPatternPos);
+ }
+ bool TestSpecParser::isControlChar( char c ) const {
+ switch( m_mode ) {
+ default:
+ return false;
+ case None:
+ return c == '~';
+ case Name:
+ return c == '[';
+ case EscapedName:
+ return true;
+ case QuotedName:
+ return c == '"';
+ case Tag:
+ return c == '[' || c == ']';
+ }
+ }
+
+ void TestSpecParser::addFilter() {
+ if( !m_currentFilter.m_required.empty() || !m_currentFilter.m_forbidden.empty() ) {
+ m_testSpec.m_filters.push_back( CATCH_MOVE(m_currentFilter) );
+ m_currentFilter = TestSpec::Filter();
+ }
+ }
+
+ void TestSpecParser::saveLastMode() {
+ lastMode = m_mode;
+ }
+
+ void TestSpecParser::revertBackToLastMode() {
+ m_mode = lastMode;
+ }
+
+ bool TestSpecParser::separate() {
+ if( (m_mode==QuotedName) || (m_mode==Tag) ){
+ //invalid argument, signal failure to previous scope.
+ m_mode = None;
+ m_pos = m_arg.size();
+ m_substring.clear();
+ m_patternName.clear();
+ m_realPatternPos = 0;
+ return false;
+ }
+ endMode();
+ addFilter();
+ return true; //success
+ }
+
+ std::string TestSpecParser::preprocessPattern() {
+ std::string token = m_patternName;
+ for (std::size_t i = 0; i < m_escapeChars.size(); ++i)
+ token = token.substr(0, m_escapeChars[i] - i) + token.substr(m_escapeChars[i] - i + 1);
+ m_escapeChars.clear();
+ if (startsWith(token, "exclude:")) {
+ m_exclusion = true;
+ token = token.substr(8);
+ }
+
+ m_patternName.clear();
+ m_realPatternPos = 0;
+
+ return token;
+ }
+
+ void TestSpecParser::addNamePattern() {
+ auto token = preprocessPattern();
+
+ if (!token.empty()) {
+ if (m_exclusion) {
+ m_currentFilter.m_forbidden.emplace_back(Detail::make_unique<TestSpec::NamePattern>(token, m_substring));
+ } else {
+ m_currentFilter.m_required.emplace_back(Detail::make_unique<TestSpec::NamePattern>(token, m_substring));
+ }
+ }
+ m_substring.clear();
+ m_exclusion = false;
+ m_mode = None;
+ }
+
+ void TestSpecParser::addTagPattern() {
+ auto token = preprocessPattern();
+
+ if (!token.empty()) {
+ // If the tag pattern is the "hide and tag" shorthand (e.g. [.foo])
+ // we have to create a separate hide tag and shorten the real one
+ if (token.size() > 1 && token[0] == '.') {
+ token.erase(token.begin());
+ if (m_exclusion) {
+ m_currentFilter.m_forbidden.emplace_back(Detail::make_unique<TestSpec::TagPattern>(".", m_substring));
+ m_currentFilter.m_forbidden.emplace_back(Detail::make_unique<TestSpec::TagPattern>(token, m_substring));
+ } else {
+ m_currentFilter.m_required.emplace_back(Detail::make_unique<TestSpec::TagPattern>(".", m_substring));
+ m_currentFilter.m_required.emplace_back(Detail::make_unique<TestSpec::TagPattern>(token, m_substring));
+ }
+ }
+ if (m_exclusion) {
+ m_currentFilter.m_forbidden.emplace_back(Detail::make_unique<TestSpec::TagPattern>(token, m_substring));
+ } else {
+ m_currentFilter.m_required.emplace_back(Detail::make_unique<TestSpec::TagPattern>(token, m_substring));
+ }
+ }
+ m_substring.clear();
+ m_exclusion = false;
+ m_mode = None;
+ }
+
+ TestSpec parseTestSpec( std::string const& arg ) {
+ return TestSpecParser( ITagAliasRegistry::get() ).parse( arg ).testSpec();
+ }
+
+} // namespace Catch
+
+
+
+#include <algorithm>
+#include <cstring>
+#include <ostream>
+
+namespace {
+ bool isWhitespace( char c ) {
+ return c == ' ' || c == '\t' || c == '\n' || c == '\r';
+ }
+
+ bool isBreakableBefore( char c ) {
+ static const char chars[] = "[({<|";
+ return std::memchr( chars, c, sizeof( chars ) - 1 ) != nullptr;
+ }
+
+ bool isBreakableAfter( char c ) {
+ static const char chars[] = "])}>.,:;*+-=&/\\";
+ return std::memchr( chars, c, sizeof( chars ) - 1 ) != nullptr;
+ }
+
+ bool isBoundary( std::string const& line, size_t at ) {
+ assert( at > 0 );
+ assert( at <= line.size() );
+
+ return at == line.size() ||
+ ( isWhitespace( line[at] ) && !isWhitespace( line[at - 1] ) ) ||
+ isBreakableBefore( line[at] ) ||
+ isBreakableAfter( line[at - 1] );
+ }
+
+} // namespace
+
+namespace Catch {
+ namespace TextFlow {
+
+ void Column::const_iterator::calcLength() {
+ m_addHyphen = false;
+ m_parsedTo = m_lineStart;
+
+ std::string const& current_line = m_column.m_string;
+ if ( current_line[m_lineStart] == '\n' ) {
+ ++m_parsedTo;
+ }
+
+ const auto maxLineLength = m_column.m_width - indentSize();
+ const auto maxParseTo = std::min(current_line.size(), m_lineStart + maxLineLength);
+ while ( m_parsedTo < maxParseTo &&
+ current_line[m_parsedTo] != '\n' ) {
+ ++m_parsedTo;
+ }
+
+ // If we encountered a newline before the column is filled,
+ // then we linebreak at the newline and consider this line
+ // finished.
+ if ( m_parsedTo < m_lineStart + maxLineLength ) {
+ m_lineLength = m_parsedTo - m_lineStart;
+ } else {
+ // Look for a natural linebreak boundary in the column
+ // (We look from the end, so that the first found boundary is
+ // the right one)
+ size_t newLineLength = maxLineLength;
+ while ( newLineLength > 0 && !isBoundary( current_line, m_lineStart + newLineLength ) ) {
+ --newLineLength;
+ }
+ while ( newLineLength > 0 &&
+ isWhitespace( current_line[m_lineStart + newLineLength - 1] ) ) {
+ --newLineLength;
+ }
+
+ // If we found one, then that is where we linebreak
+ if ( newLineLength > 0 ) {
+ m_lineLength = newLineLength;
+ } else {
+ // Otherwise we have to split text with a hyphen
+ m_addHyphen = true;
+ m_lineLength = maxLineLength - 1;
+ }
+ }
+ }
+
+ size_t Column::const_iterator::indentSize() const {
+ auto initial =
+ m_lineStart == 0 ? m_column.m_initialIndent : std::string::npos;
+ return initial == std::string::npos ? m_column.m_indent : initial;
+ }
+
+ std::string
+ Column::const_iterator::addIndentAndSuffix( size_t position,
+ size_t length ) const {
+ std::string ret;
+ const auto desired_indent = indentSize();
+ ret.reserve( desired_indent + length + m_addHyphen );
+ ret.append( desired_indent, ' ' );
+ ret.append( m_column.m_string, position, length );
+ if ( m_addHyphen ) {
+ ret.push_back( '-' );
+ }
+
+ return ret;
+ }
+
+ Column::const_iterator::const_iterator( Column const& column ): m_column( column ) {
+ assert( m_column.m_width > m_column.m_indent );
+ assert( m_column.m_initialIndent == std::string::npos ||
+ m_column.m_width > m_column.m_initialIndent );
+ calcLength();
+ if ( m_lineLength == 0 ) {
+ m_lineStart = m_column.m_string.size();
+ }
+ }
+
+ std::string Column::const_iterator::operator*() const {
+ assert( m_lineStart <= m_parsedTo );
+ return addIndentAndSuffix( m_lineStart, m_lineLength );
+ }
+
+ Column::const_iterator& Column::const_iterator::operator++() {
+ m_lineStart += m_lineLength;
+ std::string const& current_line = m_column.m_string;
+ if ( m_lineStart < current_line.size() && current_line[m_lineStart] == '\n' ) {
+ m_lineStart += 1;
+ } else {
+ while ( m_lineStart < current_line.size() &&
+ isWhitespace( current_line[m_lineStart] ) ) {
+ ++m_lineStart;
+ }
+ }
+
+ if ( m_lineStart != current_line.size() ) {
+ calcLength();
+ }
+ return *this;
+ }
+
+ Column::const_iterator Column::const_iterator::operator++( int ) {
+ const_iterator prev( *this );
+ operator++();
+ return prev;
+ }
+
+ std::ostream& operator<<( std::ostream& os, Column const& col ) {
+ bool first = true;
+ for ( auto line : col ) {
+ if ( first ) {
+ first = false;
+ } else {
+ os << '\n';
+ }
+ os << line;
+ }
+ return os;
+ }
+
+ Column Spacer( size_t spaceWidth ) {
+ Column ret{ "" };
+ ret.width( spaceWidth );
+ return ret;
+ }
+
+ Columns::iterator::iterator( Columns const& columns, EndTag ):
+ m_columns( columns.m_columns ), m_activeIterators( 0 ) {
+
+ m_iterators.reserve( m_columns.size() );
+ for ( auto const& col : m_columns ) {
+ m_iterators.push_back( col.end() );
+ }
+ }
+
+ Columns::iterator::iterator( Columns const& columns ):
+ m_columns( columns.m_columns ),
+ m_activeIterators( m_columns.size() ) {
+
+ m_iterators.reserve( m_columns.size() );
+ for ( auto const& col : m_columns ) {
+ m_iterators.push_back( col.begin() );
+ }
+ }
+
+ std::string Columns::iterator::operator*() const {
+ std::string row, padding;
+
+ for ( size_t i = 0; i < m_columns.size(); ++i ) {
+ const auto width = m_columns[i].width();
+ if ( m_iterators[i] != m_columns[i].end() ) {
+ std::string col = *m_iterators[i];
+ row += padding;
+ row += col;
+
+ padding.clear();
+ if ( col.size() < width ) {
+ padding.append( width - col.size(), ' ' );
+ }
+ } else {
+ padding.append( width, ' ' );
+ }
+ }
+ return row;
+ }
+
+ Columns::iterator& Columns::iterator::operator++() {
+ for ( size_t i = 0; i < m_columns.size(); ++i ) {
+ if ( m_iterators[i] != m_columns[i].end() ) {
+ ++m_iterators[i];
+ }
+ }
+ return *this;
+ }
+
+ Columns::iterator Columns::iterator::operator++( int ) {
+ iterator prev( *this );
+ operator++();
+ return prev;
+ }
+
+ std::ostream& operator<<( std::ostream& os, Columns const& cols ) {
+ bool first = true;
+ for ( auto line : cols ) {
+ if ( first ) {
+ first = false;
+ } else {
+ os << '\n';
+ }
+ os << line;
+ }
+ return os;
+ }
+
+ Columns Column::operator+( Column const& other ) {
+ Columns cols;
+ cols += *this;
+ cols += other;
+ return cols;
+ }
+
+ Columns& Columns::operator+=( Column const& col ) {
+ m_columns.push_back( col );
+ return *this;
+ }
+
+ Columns Columns::operator+( Column const& col ) {
+ Columns combined = *this;
+ combined += col;
+ return combined;
+ }
+
+ } // namespace TextFlow
+} // namespace Catch
+
+
+
+
+#include <exception>
+
+namespace Catch {
+ bool uncaught_exceptions() {
+#if defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
+ return false;
+#elif defined(CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS)
+ return std::uncaught_exceptions() > 0;
+#else
+ return std::uncaught_exception();
+#endif
+ }
+} // end namespace Catch
+
+
+
+namespace Catch {
+
+ WildcardPattern::WildcardPattern( std::string const& pattern,
+ CaseSensitive caseSensitivity )
+ : m_caseSensitivity( caseSensitivity ),
+ m_pattern( normaliseString( pattern ) )
+ {
+ if( startsWith( m_pattern, '*' ) ) {
+ m_pattern = m_pattern.substr( 1 );
+ m_wildcard = WildcardAtStart;
+ }
+ if( endsWith( m_pattern, '*' ) ) {
+ m_pattern = m_pattern.substr( 0, m_pattern.size()-1 );
+ m_wildcard = static_cast<WildcardPosition>( m_wildcard | WildcardAtEnd );
+ }
+ }
+
+ bool WildcardPattern::matches( std::string const& str ) const {
+ switch( m_wildcard ) {
+ case NoWildcard:
+ return m_pattern == normaliseString( str );
+ case WildcardAtStart:
+ return endsWith( normaliseString( str ), m_pattern );
+ case WildcardAtEnd:
+ return startsWith( normaliseString( str ), m_pattern );
+ case WildcardAtBothEnds:
+ return contains( normaliseString( str ), m_pattern );
+ default:
+ CATCH_INTERNAL_ERROR( "Unknown enum" );
+ }
+ }
+
+ std::string WildcardPattern::normaliseString( std::string const& str ) const {
+ return trim( m_caseSensitivity == CaseSensitive::No ? toLower( str ) : str );
+ }
+}
+
+
+// Note: swapping these two includes around causes MSVC to error out
+// while in /permissive- mode. No, I don't know why.
+// Tested on VS 2019, 18.{3, 4}.x
+
+#include <iomanip>
+#include <type_traits>
+
+namespace Catch {
+
+namespace {
+
+ size_t trailingBytes(unsigned char c) {
+ if ((c & 0xE0) == 0xC0) {
+ return 2;
+ }
+ if ((c & 0xF0) == 0xE0) {
+ return 3;
+ }
+ if ((c & 0xF8) == 0xF0) {
+ return 4;
+ }
+ CATCH_INTERNAL_ERROR("Invalid multibyte utf-8 start byte encountered");
+ }
+
+ uint32_t headerValue(unsigned char c) {
+ if ((c & 0xE0) == 0xC0) {
+ return c & 0x1F;
+ }
+ if ((c & 0xF0) == 0xE0) {
+ return c & 0x0F;
+ }
+ if ((c & 0xF8) == 0xF0) {
+ return c & 0x07;
+ }
+ CATCH_INTERNAL_ERROR("Invalid multibyte utf-8 start byte encountered");
+ }
+
+ void hexEscapeChar(std::ostream& os, unsigned char c) {
+ std::ios_base::fmtflags f(os.flags());
+ os << "\\x"
+ << std::uppercase << std::hex << std::setfill('0') << std::setw(2)
+ << static_cast<int>(c);
+ os.flags(f);
+ }
+
+ bool shouldNewline(XmlFormatting fmt) {
+ return !!(static_cast<std::underlying_type_t<XmlFormatting>>(fmt & XmlFormatting::Newline));
+ }
+
+ bool shouldIndent(XmlFormatting fmt) {
+ return !!(static_cast<std::underlying_type_t<XmlFormatting>>(fmt & XmlFormatting::Indent));
+ }
+
+} // anonymous namespace
+
+ XmlFormatting operator | (XmlFormatting lhs, XmlFormatting rhs) {
+ return static_cast<XmlFormatting>(
+ static_cast<std::underlying_type_t<XmlFormatting>>(lhs) |
+ static_cast<std::underlying_type_t<XmlFormatting>>(rhs)
+ );
+ }
+
+ XmlFormatting operator & (XmlFormatting lhs, XmlFormatting rhs) {
+ return static_cast<XmlFormatting>(
+ static_cast<std::underlying_type_t<XmlFormatting>>(lhs) &
+ static_cast<std::underlying_type_t<XmlFormatting>>(rhs)
+ );
+ }
+
+
+ XmlEncode::XmlEncode( StringRef str, ForWhat forWhat )
+ : m_str( str ),
+ m_forWhat( forWhat )
+ {}
+
+ void XmlEncode::encodeTo( std::ostream& os ) const {
+ // Apostrophe escaping not necessary if we always use " to write attributes
+ // (see: http://www.w3.org/TR/xml/#syntax)
+
+ for( std::size_t idx = 0; idx < m_str.size(); ++ idx ) {
+ unsigned char c = static_cast<unsigned char>(m_str[idx]);
+ switch (c) {
+ case '<': os << "&lt;"; break;
+ case '&': os << "&amp;"; break;
+
+ case '>':
+ // See: http://www.w3.org/TR/xml/#syntax
+ if (idx > 2 && m_str[idx - 1] == ']' && m_str[idx - 2] == ']')
+ os << "&gt;";
+ else
+ os << c;
+ break;
+
+ case '\"':
+ if (m_forWhat == ForAttributes)
+ os << "&quot;";
+ else
+ os << c;
+ break;
+
+ default:
+ // Check for control characters and invalid utf-8
+
+ // Escape control characters in standard ascii
+ // see http://stackoverflow.com/questions/404107/why-are-control-characters-illegal-in-xml-1-0
+ if (c < 0x09 || (c > 0x0D && c < 0x20) || c == 0x7F) {
+ hexEscapeChar(os, c);
+ break;
+ }
+
+ // Plain ASCII: Write it to stream
+ if (c < 0x7F) {
+ os << c;
+ break;
+ }
+
+ // UTF-8 territory
+ // Check if the encoding is valid and if it is not, hex escape bytes.
+ // Important: We do not check the exact decoded values for validity, only the encoding format
+ // First check that this bytes is a valid lead byte:
+ // This means that it is not encoded as 1111 1XXX
+ // Or as 10XX XXXX
+ if (c < 0xC0 ||
+ c >= 0xF8) {
+ hexEscapeChar(os, c);
+ break;
+ }
+
+ auto encBytes = trailingBytes(c);
+ // Are there enough bytes left to avoid accessing out-of-bounds memory?
+ if (idx + encBytes - 1 >= m_str.size()) {
+ hexEscapeChar(os, c);
+ break;
+ }
+ // The header is valid, check data
+ // The next encBytes bytes must together be a valid utf-8
+ // This means: bitpattern 10XX XXXX and the extracted value is sane (ish)
+ bool valid = true;
+ uint32_t value = headerValue(c);
+ for (std::size_t n = 1; n < encBytes; ++n) {
+ unsigned char nc = static_cast<unsigned char>(m_str[idx + n]);
+ valid &= ((nc & 0xC0) == 0x80);
+ value = (value << 6) | (nc & 0x3F);
+ }
+
+ if (
+ // Wrong bit pattern of following bytes
+ (!valid) ||
+ // Overlong encodings
+ (value < 0x80) ||
+ (0x80 <= value && value < 0x800 && encBytes > 2) ||
+ (0x800 < value && value < 0x10000 && encBytes > 3) ||
+ // Encoded value out of range
+ (value >= 0x110000)
+ ) {
+ hexEscapeChar(os, c);
+ break;
+ }
+
+ // If we got here, this is in fact a valid(ish) utf-8 sequence
+ for (std::size_t n = 0; n < encBytes; ++n) {
+ os << m_str[idx + n];
+ }
+ idx += encBytes - 1;
+ break;
+ }
+ }
+ }
+
+ std::ostream& operator << ( std::ostream& os, XmlEncode const& xmlEncode ) {
+ xmlEncode.encodeTo( os );
+ return os;
+ }
+
+ XmlWriter::ScopedElement::ScopedElement( XmlWriter* writer, XmlFormatting fmt )
+ : m_writer( writer ),
+ m_fmt(fmt)
+ {}
+
+ XmlWriter::ScopedElement::ScopedElement( ScopedElement&& other ) noexcept
+ : m_writer( other.m_writer ),
+ m_fmt(other.m_fmt)
+ {
+ other.m_writer = nullptr;
+ other.m_fmt = XmlFormatting::None;
+ }
+ XmlWriter::ScopedElement& XmlWriter::ScopedElement::operator=( ScopedElement&& other ) noexcept {
+ if ( m_writer ) {
+ m_writer->endElement();
+ }
+ m_writer = other.m_writer;
+ other.m_writer = nullptr;
+ m_fmt = other.m_fmt;
+ other.m_fmt = XmlFormatting::None;
+ return *this;
+ }
+
+
+ XmlWriter::ScopedElement::~ScopedElement() {
+ if (m_writer) {
+ m_writer->endElement(m_fmt);
+ }
+ }
+
+ XmlWriter::ScopedElement&
+ XmlWriter::ScopedElement::writeText( StringRef text, XmlFormatting fmt ) {
+ m_writer->writeText( text, fmt );
+ return *this;
+ }
+
+ XmlWriter::ScopedElement&
+ XmlWriter::ScopedElement::writeAttribute( StringRef name,
+ StringRef attribute ) {
+ m_writer->writeAttribute( name, attribute );
+ return *this;
+ }
+
+
+ XmlWriter::XmlWriter( std::ostream& os ) : m_os( os )
+ {
+ writeDeclaration();
+ }
+
+ XmlWriter::~XmlWriter() {
+ while (!m_tags.empty()) {
+ endElement();
+ }
+ newlineIfNecessary();
+ }
+
+ XmlWriter& XmlWriter::startElement( std::string const& name, XmlFormatting fmt ) {
+ ensureTagClosed();
+ newlineIfNecessary();
+ if (shouldIndent(fmt)) {
+ m_os << m_indent;
+ m_indent += " ";
+ }
+ m_os << '<' << name;
+ m_tags.push_back( name );
+ m_tagIsOpen = true;
+ applyFormatting(fmt);
+ return *this;
+ }
+
+ XmlWriter::ScopedElement XmlWriter::scopedElement( std::string const& name, XmlFormatting fmt ) {
+ ScopedElement scoped( this, fmt );
+ startElement( name, fmt );
+ return scoped;
+ }
+
+ XmlWriter& XmlWriter::endElement(XmlFormatting fmt) {
+ m_indent = m_indent.substr(0, m_indent.size() - 2);
+
+ if( m_tagIsOpen ) {
+ m_os << "/>";
+ m_tagIsOpen = false;
+ } else {
+ newlineIfNecessary();
+ if (shouldIndent(fmt)) {
+ m_os << m_indent;
+ }
+ m_os << "</" << m_tags.back() << '>';
+ }
+ m_os << std::flush;
+ applyFormatting(fmt);
+ m_tags.pop_back();
+ return *this;
+ }
+
+ XmlWriter& XmlWriter::writeAttribute( StringRef name,
+ StringRef attribute ) {
+ if( !name.empty() && !attribute.empty() )
+ m_os << ' ' << name << "=\"" << XmlEncode( attribute, XmlEncode::ForAttributes ) << '"';
+ return *this;
+ }
+
+ XmlWriter& XmlWriter::writeAttribute( StringRef name, bool attribute ) {
+ writeAttribute(name, (attribute ? "true"_sr : "false"_sr));
+ return *this;
+ }
+
+ XmlWriter& XmlWriter::writeAttribute( StringRef name,
+ char const* attribute ) {
+ writeAttribute( name, StringRef( attribute ) );
+ return *this;
+ }
+
+ XmlWriter& XmlWriter::writeText( StringRef text, XmlFormatting fmt ) {
+ CATCH_ENFORCE(!m_tags.empty(), "Cannot write text as top level element");
+ if( !text.empty() ){
+ bool tagWasOpen = m_tagIsOpen;
+ ensureTagClosed();
+ if (tagWasOpen && shouldIndent(fmt)) {
+ m_os << m_indent;
+ }
+ m_os << XmlEncode( text, XmlEncode::ForTextNodes );
+ applyFormatting(fmt);
+ }
+ return *this;
+ }
+
+ XmlWriter& XmlWriter::writeComment( StringRef text, XmlFormatting fmt ) {
+ ensureTagClosed();
+ if (shouldIndent(fmt)) {
+ m_os << m_indent;
+ }
+ m_os << "<!-- " << text << " -->";
+ applyFormatting(fmt);
+ return *this;
+ }
+
+ void XmlWriter::writeStylesheetRef( StringRef url ) {
+ m_os << R"(<?xml-stylesheet type="text/xsl" href=")" << url << R"("?>)" << '\n';
+ }
+
+ void XmlWriter::ensureTagClosed() {
+ if( m_tagIsOpen ) {
+ m_os << '>' << std::flush;
+ newlineIfNecessary();
+ m_tagIsOpen = false;
+ }
+ }
+
+ void XmlWriter::applyFormatting(XmlFormatting fmt) {
+ m_needsNewline = shouldNewline(fmt);
+ }
+
+ void XmlWriter::writeDeclaration() {
+ m_os << R"(<?xml version="1.0" encoding="UTF-8"?>)" << '\n';
+ }
+
+ void XmlWriter::newlineIfNecessary() {
+ if( m_needsNewline ) {
+ m_os << '\n' << std::flush;
+ m_needsNewline = false;
+ }
+ }
+}
+
+
+
+
+
+namespace Catch {
+namespace Matchers {
+
+ std::string MatcherUntypedBase::toString() const {
+ if (m_cachedToString.empty()) {
+ m_cachedToString = describe();
+ }
+ return m_cachedToString;
+ }
+
+ MatcherUntypedBase::~MatcherUntypedBase() = default;
+
+} // namespace Matchers
+} // namespace Catch
+
+
+
+
+namespace Catch {
+namespace Matchers {
+
+ std::string IsEmptyMatcher::describe() const {
+ return "is empty";
+ }
+
+ std::string HasSizeMatcher::describe() const {
+ ReusableStringStream sstr;
+ sstr << "has size == " << m_target_size;
+ return sstr.str();
+ }
+
+ IsEmptyMatcher IsEmpty() {
+ return {};
+ }
+
+ HasSizeMatcher SizeIs(std::size_t sz) {
+ return HasSizeMatcher{ sz };
+ }
+
+} // end namespace Matchers
+} // end namespace Catch
+
+
+
+namespace Catch {
+namespace Matchers {
+
+bool ExceptionMessageMatcher::match(std::exception const& ex) const {
+ return ex.what() == m_message;
+}
+
+std::string ExceptionMessageMatcher::describe() const {
+ return "exception message matches \"" + m_message + '"';
+}
+
+ExceptionMessageMatcher Message(std::string const& message) {
+ return ExceptionMessageMatcher(message);
+}
+
+} // namespace Matchers
+} // namespace Catch
+
+
+
+#include <algorithm>
+#include <cmath>
+#include <cstdlib>
+#include <cstdint>
+#include <sstream>
+#include <iomanip>
+#include <limits>
+
+
+namespace Catch {
+namespace {
+
+ template <typename FP>
+ bool almostEqualUlps(FP lhs, FP rhs, uint64_t maxUlpDiff) {
+ // Comparison with NaN should always be false.
+ // This way we can rule it out before getting into the ugly details
+ if (Catch::isnan(lhs) || Catch::isnan(rhs)) {
+ return false;
+ }
+
+ // This should also handle positive and negative zeros, infinities
+ const auto ulpDist = ulpDistance(lhs, rhs);
+
+ return ulpDist <= maxUlpDiff;
+ }
+
+#if defined(CATCH_CONFIG_GLOBAL_NEXTAFTER)
+
+ float nextafter(float x, float y) {
+ return ::nextafterf(x, y);
+ }
+
+ double nextafter(double x, double y) {
+ return ::nextafter(x, y);
+ }
+
+#endif // ^^^ CATCH_CONFIG_GLOBAL_NEXTAFTER ^^^
+
+template <typename FP>
+FP step(FP start, FP direction, uint64_t steps) {
+ for (uint64_t i = 0; i < steps; ++i) {
+#if defined(CATCH_CONFIG_GLOBAL_NEXTAFTER)
+ start = Catch::nextafter(start, direction);
+#else
+ start = std::nextafter(start, direction);
+#endif
+ }
+ return start;
+}
+
+// Performs equivalent check of std::fabs(lhs - rhs) <= margin
+// But without the subtraction to allow for INFINITY in comparison
+bool marginComparison(double lhs, double rhs, double margin) {
+ return (lhs + margin >= rhs) && (rhs + margin >= lhs);
+}
+
+template <typename FloatingPoint>
+void write(std::ostream& out, FloatingPoint num) {
+ out << std::scientific
+ << std::setprecision(std::numeric_limits<FloatingPoint>::max_digits10 - 1)
+ << num;
+}
+
+} // end anonymous namespace
+
+namespace Matchers {
+namespace Detail {
+
+ enum class FloatingPointKind : uint8_t {
+ Float,
+ Double
+ };
+
+} // end namespace Detail
+
+
+ WithinAbsMatcher::WithinAbsMatcher(double target, double margin)
+ :m_target{ target }, m_margin{ margin } {
+ CATCH_ENFORCE(margin >= 0, "Invalid margin: " << margin << '.'
+ << " Margin has to be non-negative.");
+ }
+
+ // Performs equivalent check of std::fabs(lhs - rhs) <= margin
+ // But without the subtraction to allow for INFINITY in comparison
+ bool WithinAbsMatcher::match(double const& matchee) const {
+ return (matchee + m_margin >= m_target) && (m_target + m_margin >= matchee);
+ }
+
+ std::string WithinAbsMatcher::describe() const {
+ return "is within " + ::Catch::Detail::stringify(m_margin) + " of " + ::Catch::Detail::stringify(m_target);
+ }
+
+
+ WithinUlpsMatcher::WithinUlpsMatcher(double target, uint64_t ulps, Detail::FloatingPointKind baseType)
+ :m_target{ target }, m_ulps{ ulps }, m_type{ baseType } {
+ CATCH_ENFORCE(m_type == Detail::FloatingPointKind::Double
+ || m_ulps < (std::numeric_limits<uint32_t>::max)(),
+ "Provided ULP is impossibly large for a float comparison.");
+ CATCH_ENFORCE( std::numeric_limits<double>::is_iec559,
+ "WithinUlp matcher only supports platforms with "
+ "IEEE-754 compatible floating point representation" );
+ }
+
+#if defined(__clang__)
+#pragma clang diagnostic push
+// Clang <3.5 reports on the default branch in the switch below
+#pragma clang diagnostic ignored "-Wunreachable-code"
+#endif
+
+ bool WithinUlpsMatcher::match(double const& matchee) const {
+ switch (m_type) {
+ case Detail::FloatingPointKind::Float:
+ return almostEqualUlps<float>(static_cast<float>(matchee), static_cast<float>(m_target), m_ulps);
+ case Detail::FloatingPointKind::Double:
+ return almostEqualUlps<double>(matchee, m_target, m_ulps);
+ default:
+ CATCH_INTERNAL_ERROR( "Unknown Detail::FloatingPointKind value" );
+ }
+ }
+
+#if defined(__clang__)
+#pragma clang diagnostic pop
+#endif
+
+ std::string WithinUlpsMatcher::describe() const {
+ std::stringstream ret;
+
+ ret << "is within " << m_ulps << " ULPs of ";
+
+ if (m_type == Detail::FloatingPointKind::Float) {
+ write(ret, static_cast<float>(m_target));
+ ret << 'f';
+ } else {
+ write(ret, m_target);
+ }
+
+ ret << " ([";
+ if (m_type == Detail::FloatingPointKind::Double) {
+ write( ret,
+ step( m_target,
+ -std::numeric_limits<double>::infinity(),
+ m_ulps ) );
+ ret << ", ";
+ write( ret,
+ step( m_target,
+ std::numeric_limits<double>::infinity(),
+ m_ulps ) );
+ } else {
+ // We have to cast INFINITY to float because of MinGW, see #1782
+ write( ret,
+ step( static_cast<float>( m_target ),
+ -std::numeric_limits<float>::infinity(),
+ m_ulps ) );
+ ret << ", ";
+ write( ret,
+ step( static_cast<float>( m_target ),
+ std::numeric_limits<float>::infinity(),
+ m_ulps ) );
+ }
+ ret << "])";
+
+ return ret.str();
+ }
+
+ WithinRelMatcher::WithinRelMatcher(double target, double epsilon):
+ m_target(target),
+ m_epsilon(epsilon){
+ CATCH_ENFORCE(m_epsilon >= 0., "Relative comparison with epsilon < 0 does not make sense.");
+ CATCH_ENFORCE(m_epsilon < 1., "Relative comparison with epsilon >= 1 does not make sense.");
+ }
+
+ bool WithinRelMatcher::match(double const& matchee) const {
+ const auto relMargin = m_epsilon * (std::max)(std::fabs(matchee), std::fabs(m_target));
+ return marginComparison(matchee, m_target,
+ std::isinf(relMargin)? 0 : relMargin);
+ }
+
+ std::string WithinRelMatcher::describe() const {
+ Catch::ReusableStringStream sstr;
+ sstr << "and " << m_target << " are within " << m_epsilon * 100. << "% of each other";
+ return sstr.str();
+ }
+
+
+WithinUlpsMatcher WithinULP(double target, uint64_t maxUlpDiff) {
+ return WithinUlpsMatcher(target, maxUlpDiff, Detail::FloatingPointKind::Double);
+}
+
+WithinUlpsMatcher WithinULP(float target, uint64_t maxUlpDiff) {
+ return WithinUlpsMatcher(target, maxUlpDiff, Detail::FloatingPointKind::Float);
+}
+
+WithinAbsMatcher WithinAbs(double target, double margin) {
+ return WithinAbsMatcher(target, margin);
+}
+
+WithinRelMatcher WithinRel(double target, double eps) {
+ return WithinRelMatcher(target, eps);
+}
+
+WithinRelMatcher WithinRel(double target) {
+ return WithinRelMatcher(target, std::numeric_limits<double>::epsilon() * 100);
+}
+
+WithinRelMatcher WithinRel(float target, float eps) {
+ return WithinRelMatcher(target, eps);
+}
+
+WithinRelMatcher WithinRel(float target) {
+ return WithinRelMatcher(target, std::numeric_limits<float>::epsilon() * 100);
+}
+
+
+} // namespace Matchers
+} // namespace Catch
+
+
+
+
+std::string Catch::Matchers::Detail::finalizeDescription(const std::string& desc) {
+ if (desc.empty()) {
+ return "matches undescribed predicate";
+ } else {
+ return "matches predicate: \"" + desc + '"';
+ }
+}
+
+
+
+namespace Catch {
+ namespace Matchers {
+ std::string AllTrueMatcher::describe() const { return "contains only true"; }
+
+ AllTrueMatcher AllTrue() { return AllTrueMatcher{}; }
+
+ std::string NoneTrueMatcher::describe() const { return "contains no true"; }
+
+ NoneTrueMatcher NoneTrue() { return NoneTrueMatcher{}; }
+
+ std::string AnyTrueMatcher::describe() const { return "contains at least one true"; }
+
+ AnyTrueMatcher AnyTrue() { return AnyTrueMatcher{}; }
+ } // namespace Matchers
+} // namespace Catch
+
+
+
+#include <regex>
+
+namespace Catch {
+namespace Matchers {
+
+ CasedString::CasedString( std::string const& str, CaseSensitive caseSensitivity )
+ : m_caseSensitivity( caseSensitivity ),
+ m_str( adjustString( str ) )
+ {}
+ std::string CasedString::adjustString( std::string const& str ) const {
+ return m_caseSensitivity == CaseSensitive::No
+ ? toLower( str )
+ : str;
+ }
+ StringRef CasedString::caseSensitivitySuffix() const {
+ return m_caseSensitivity == CaseSensitive::Yes
+ ? StringRef()
+ : " (case insensitive)"_sr;
+ }
+
+
+ StringMatcherBase::StringMatcherBase( StringRef operation, CasedString const& comparator )
+ : m_comparator( comparator ),
+ m_operation( operation ) {
+ }
+
+ std::string StringMatcherBase::describe() const {
+ std::string description;
+ description.reserve(5 + m_operation.size() + m_comparator.m_str.size() +
+ m_comparator.caseSensitivitySuffix().size());
+ description += m_operation;
+ description += ": \"";
+ description += m_comparator.m_str;
+ description += '"';
+ description += m_comparator.caseSensitivitySuffix();
+ return description;
+ }
+
+ StringEqualsMatcher::StringEqualsMatcher( CasedString const& comparator ) : StringMatcherBase( "equals"_sr, comparator ) {}
+
+ bool StringEqualsMatcher::match( std::string const& source ) const {
+ return m_comparator.adjustString( source ) == m_comparator.m_str;
+ }
+
+
+ StringContainsMatcher::StringContainsMatcher( CasedString const& comparator ) : StringMatcherBase( "contains"_sr, comparator ) {}
+
+ bool StringContainsMatcher::match( std::string const& source ) const {
+ return contains( m_comparator.adjustString( source ), m_comparator.m_str );
+ }
+
+
+ StartsWithMatcher::StartsWithMatcher( CasedString const& comparator ) : StringMatcherBase( "starts with"_sr, comparator ) {}
+
+ bool StartsWithMatcher::match( std::string const& source ) const {
+ return startsWith( m_comparator.adjustString( source ), m_comparator.m_str );
+ }
+
+
+ EndsWithMatcher::EndsWithMatcher( CasedString const& comparator ) : StringMatcherBase( "ends with"_sr, comparator ) {}
+
+ bool EndsWithMatcher::match( std::string const& source ) const {
+ return endsWith( m_comparator.adjustString( source ), m_comparator.m_str );
+ }
+
+
+
+ RegexMatcher::RegexMatcher(std::string regex, CaseSensitive caseSensitivity): m_regex(CATCH_MOVE(regex)), m_caseSensitivity(caseSensitivity) {}
+
+ bool RegexMatcher::match(std::string const& matchee) const {
+ auto flags = std::regex::ECMAScript; // ECMAScript is the default syntax option anyway
+ if (m_caseSensitivity == CaseSensitive::No) {
+ flags |= std::regex::icase;
+ }
+ auto reg = std::regex(m_regex, flags);
+ return std::regex_match(matchee, reg);
+ }
+
+ std::string RegexMatcher::describe() const {
+ return "matches " + ::Catch::Detail::stringify(m_regex) + ((m_caseSensitivity == CaseSensitive::Yes)? " case sensitively" : " case insensitively");
+ }
+
+
+ StringEqualsMatcher Equals( std::string const& str, CaseSensitive caseSensitivity ) {
+ return StringEqualsMatcher( CasedString( str, caseSensitivity) );
+ }
+ StringContainsMatcher ContainsSubstring( std::string const& str, CaseSensitive caseSensitivity ) {
+ return StringContainsMatcher( CasedString( str, caseSensitivity) );
+ }
+ EndsWithMatcher EndsWith( std::string const& str, CaseSensitive caseSensitivity ) {
+ return EndsWithMatcher( CasedString( str, caseSensitivity) );
+ }
+ StartsWithMatcher StartsWith( std::string const& str, CaseSensitive caseSensitivity ) {
+ return StartsWithMatcher( CasedString( str, caseSensitivity) );
+ }
+
+ RegexMatcher Matches(std::string const& regex, CaseSensitive caseSensitivity) {
+ return RegexMatcher(regex, caseSensitivity);
+ }
+
+} // namespace Matchers
+} // namespace Catch
+
+
+
+namespace Catch {
+namespace Matchers {
+ MatcherGenericBase::~MatcherGenericBase() = default;
+
+ namespace Detail {
+
+ std::string describe_multi_matcher(StringRef combine, std::string const* descriptions_begin, std::string const* descriptions_end) {
+ std::string description;
+ std::size_t combined_size = 4;
+ for ( auto desc = descriptions_begin; desc != descriptions_end; ++desc ) {
+ combined_size += desc->size();
+ }
+ combined_size += static_cast<size_t>(descriptions_end - descriptions_begin - 1) * combine.size();
+
+ description.reserve(combined_size);
+
+ description += "( ";
+ bool first = true;
+ for( auto desc = descriptions_begin; desc != descriptions_end; ++desc ) {
+ if( first )
+ first = false;
+ else
+ description += combine;
+ description += *desc;
+ }
+ description += " )";
+ return description;
+ }
+
+ } // namespace Detail
+} // namespace Matchers
+} // namespace Catch
+
+
+
+
+namespace Catch {
+
+ // This is the general overload that takes a any string matcher
+ // There is another overload, in catch_assertionhandler.h/.cpp, that only takes a string and infers
+ // the Equals matcher (so the header does not mention matchers)
+ void handleExceptionMatchExpr( AssertionHandler& handler, StringMatcher const& matcher, StringRef matcherString ) {
+ std::string exceptionMessage = Catch::translateActiveException();
+ MatchExpr<std::string, StringMatcher const&> expr( CATCH_MOVE(exceptionMessage), matcher, matcherString );
+ handler.handleExpr( expr );
+ }
+
+} // namespace Catch
+
+
+
+#include <ostream>
+
+namespace Catch {
+
+ AutomakeReporter::~AutomakeReporter() {}
+
+ void AutomakeReporter::testCaseEnded(TestCaseStats const& _testCaseStats) {
+ // Possible values to emit are PASS, XFAIL, SKIP, FAIL, XPASS and ERROR.
+ m_stream << ":test-result: ";
+ if (_testCaseStats.totals.assertions.allPassed()) {
+ m_stream << "PASS";
+ } else if (_testCaseStats.totals.assertions.allOk()) {
+ m_stream << "XFAIL";
+ } else {
+ m_stream << "FAIL";
+ }
+ m_stream << ' ' << _testCaseStats.testInfo->name << '\n';
+ StreamingReporterBase::testCaseEnded(_testCaseStats);
+ }
+
+ void AutomakeReporter::skipTest(TestCaseInfo const& testInfo) {
+ m_stream << ":test-result: SKIP " << testInfo.name << '\n';
+ }
+
+} // end namespace Catch
+
+
+
+
+
+
+namespace Catch {
+ ReporterBase::ReporterBase( ReporterConfig&& config ):
+ IEventListener( config.fullConfig() ),
+ m_wrapped_stream( CATCH_MOVE(config).takeStream() ),
+ m_stream( m_wrapped_stream->stream() ),
+ m_colour( makeColourImpl( config.colourMode(), m_wrapped_stream.get() ) ),
+ m_customOptions( config.customOptions() )
+ {}
+
+ ReporterBase::~ReporterBase() = default;
+
+ void ReporterBase::listReporters(
+ std::vector<ReporterDescription> const& descriptions ) {
+ defaultListReporters(m_stream, descriptions, m_config->verbosity());
+ }
+
+ void ReporterBase::listListeners(
+ std::vector<ListenerDescription> const& descriptions ) {
+ defaultListListeners( m_stream, descriptions );
+ }
+
+ void ReporterBase::listTests(std::vector<TestCaseHandle> const& tests) {
+ defaultListTests(m_stream,
+ m_colour.get(),
+ tests,
+ m_config->hasTestFilters(),
+ m_config->verbosity());
+ }
+
+ void ReporterBase::listTags(std::vector<TagInfo> const& tags) {
+ defaultListTags( m_stream, tags, m_config->hasTestFilters() );
+ }
+
+} // namespace Catch
+
+
+
+
+#include <ostream>
+
+namespace {
+
+ constexpr Catch::StringRef bothOrAll( std::uint64_t count ) {
+ switch (count) {
+ case 1:
+ return Catch::StringRef{};
+ case 2:
+ return "both "_catch_sr;
+ default:
+ return "all "_catch_sr;
+ }
+ }
+
+} // anon namespace
+
+
+namespace Catch {
+namespace {
+
+ // Colour::LightGrey
+ static constexpr Colour::Code compactDimColour = Colour::FileName;
+
+#ifdef CATCH_PLATFORM_MAC
+ static constexpr Catch::StringRef compactFailedString = "FAILED"_sr;
+ static constexpr Catch::StringRef compactPassedString = "PASSED"_sr;
+#else
+ static constexpr Catch::StringRef compactFailedString = "failed"_sr;
+ static constexpr Catch::StringRef compactPassedString = "passed"_sr;
+#endif
+
+// Colour, message variants:
+// - white: No tests ran.
+// - red: Failed [both/all] N test cases, failed [both/all] M assertions.
+// - white: Passed [both/all] N test cases (no assertions).
+// - red: Failed N tests cases, failed M assertions.
+// - green: Passed [both/all] N tests cases with M assertions.
+void printTotals(std::ostream& out, const Totals& totals, ColourImpl* colourImpl) {
+ if (totals.testCases.total() == 0) {
+ out << "No tests ran.";
+ } else if (totals.testCases.failed == totals.testCases.total()) {
+ auto guard = colourImpl->guardColour( Colour::ResultError ).engage( out );
+ const StringRef qualify_assertions_failed =
+ totals.assertions.failed == totals.assertions.total() ?
+ bothOrAll(totals.assertions.failed) : StringRef{};
+ out <<
+ "Failed " << bothOrAll(totals.testCases.failed)
+ << pluralise(totals.testCases.failed, "test case"_sr) << ", "
+ "failed " << qualify_assertions_failed <<
+ pluralise(totals.assertions.failed, "assertion"_sr) << '.';
+ } else if (totals.assertions.total() == 0) {
+ out <<
+ "Passed " << bothOrAll(totals.testCases.total())
+ << pluralise(totals.testCases.total(), "test case"_sr)
+ << " (no assertions).";
+ } else if (totals.assertions.failed) {
+ out << colourImpl->guardColour( Colour::ResultError ) <<
+ "Failed " << pluralise(totals.testCases.failed, "test case"_sr) << ", "
+ "failed " << pluralise(totals.assertions.failed, "assertion"_sr) << '.';
+ } else {
+ out << colourImpl->guardColour( Colour::ResultSuccess ) <<
+ "Passed " << bothOrAll(totals.testCases.passed)
+ << pluralise(totals.testCases.passed, "test case"_sr) <<
+ " with " << pluralise(totals.assertions.passed, "assertion"_sr) << '.';
+ }
+}
+
+// Implementation of CompactReporter formatting
+class AssertionPrinter {
+public:
+ AssertionPrinter& operator= (AssertionPrinter const&) = delete;
+ AssertionPrinter(AssertionPrinter const&) = delete;
+ AssertionPrinter(std::ostream& _stream, AssertionStats const& _stats, bool _printInfoMessages, ColourImpl* colourImpl_)
+ : stream(_stream)
+ , result(_stats.assertionResult)
+ , messages(_stats.infoMessages)
+ , itMessage(_stats.infoMessages.begin())
+ , printInfoMessages(_printInfoMessages)
+ , colourImpl(colourImpl_)
+ {}
+
+ void print() {
+ printSourceInfo();
+
+ itMessage = messages.begin();
+
+ switch (result.getResultType()) {
+ case ResultWas::Ok:
+ printResultType(Colour::ResultSuccess, compactPassedString);
+ printOriginalExpression();
+ printReconstructedExpression();
+ if (!result.hasExpression())
+ printRemainingMessages(Colour::None);
+ else
+ printRemainingMessages();
+ break;
+ case ResultWas::ExpressionFailed:
+ if (result.isOk())
+ printResultType(Colour::ResultSuccess, compactFailedString + " - but was ok"_sr);
+ else
+ printResultType(Colour::Error, compactFailedString);
+ printOriginalExpression();
+ printReconstructedExpression();
+ printRemainingMessages();
+ break;
+ case ResultWas::ThrewException:
+ printResultType(Colour::Error, compactFailedString);
+ printIssue("unexpected exception with message:");
+ printMessage();
+ printExpressionWas();
+ printRemainingMessages();
+ break;
+ case ResultWas::FatalErrorCondition:
+ printResultType(Colour::Error, compactFailedString);
+ printIssue("fatal error condition with message:");
+ printMessage();
+ printExpressionWas();
+ printRemainingMessages();
+ break;
+ case ResultWas::DidntThrowException:
+ printResultType(Colour::Error, compactFailedString);
+ printIssue("expected exception, got none");
+ printExpressionWas();
+ printRemainingMessages();
+ break;
+ case ResultWas::Info:
+ printResultType(Colour::None, "info"_sr);
+ printMessage();
+ printRemainingMessages();
+ break;
+ case ResultWas::Warning:
+ printResultType(Colour::None, "warning"_sr);
+ printMessage();
+ printRemainingMessages();
+ break;
+ case ResultWas::ExplicitFailure:
+ printResultType(Colour::Error, compactFailedString);
+ printIssue("explicitly");
+ printRemainingMessages(Colour::None);
+ break;
+ // These cases are here to prevent compiler warnings
+ case ResultWas::Unknown:
+ case ResultWas::FailureBit:
+ case ResultWas::Exception:
+ printResultType(Colour::Error, "** internal error **");
+ break;
+ }
+ }
+
+private:
+ void printSourceInfo() const {
+ stream << colourImpl->guardColour( Colour::FileName )
+ << result.getSourceInfo() << ':';
+ }
+
+ void printResultType(Colour::Code colour, StringRef passOrFail) const {
+ if (!passOrFail.empty()) {
+ stream << colourImpl->guardColour(colour) << ' ' << passOrFail;
+ stream << ':';
+ }
+ }
+
+ void printIssue(char const* issue) const {
+ stream << ' ' << issue;
+ }
+
+ void printExpressionWas() {
+ if (result.hasExpression()) {
+ stream << ';';
+ {
+ stream << colourImpl->guardColour(compactDimColour) << " expression was:";
+ }
+ printOriginalExpression();
+ }
+ }
+
+ void printOriginalExpression() const {
+ if (result.hasExpression()) {
+ stream << ' ' << result.getExpression();
+ }
+ }
+
+ void printReconstructedExpression() const {
+ if (result.hasExpandedExpression()) {
+ stream << colourImpl->guardColour(compactDimColour) << " for: ";
+ stream << result.getExpandedExpression();
+ }
+ }
+
+ void printMessage() {
+ if (itMessage != messages.end()) {
+ stream << " '" << itMessage->message << '\'';
+ ++itMessage;
+ }
+ }
+
+ void printRemainingMessages(Colour::Code colour = compactDimColour) {
+ if (itMessage == messages.end())
+ return;
+
+ const auto itEnd = messages.cend();
+ const auto N = static_cast<std::size_t>(std::distance(itMessage, itEnd));
+
+ stream << colourImpl->guardColour( colour ) << " with "
+ << pluralise( N, "message"_sr ) << ':';
+
+ while (itMessage != itEnd) {
+ // If this assertion is a warning ignore any INFO messages
+ if (printInfoMessages || itMessage->type != ResultWas::Info) {
+ printMessage();
+ if (itMessage != itEnd) {
+ stream << colourImpl->guardColour(compactDimColour) << " and";
+ }
+ continue;
+ }
+ ++itMessage;
+ }
+ }
+
+private:
+ std::ostream& stream;
+ AssertionResult const& result;
+ std::vector<MessageInfo> messages;
+ std::vector<MessageInfo>::const_iterator itMessage;
+ bool printInfoMessages;
+ ColourImpl* colourImpl;
+};
+
+} // anon namespace
+
+ std::string CompactReporter::getDescription() {
+ return "Reports test results on a single line, suitable for IDEs";
+ }
+
+ void CompactReporter::noMatchingTestCases( StringRef unmatchedSpec ) {
+ m_stream << "No test cases matched '" << unmatchedSpec << "'\n";
+ }
+
+ void CompactReporter::testRunStarting( TestRunInfo const& ) {
+ if ( m_config->testSpec().hasFilters() ) {
+ m_stream << m_colour->guardColour( Colour::BrightYellow )
+ << "Filters: "
+ << serializeFilters( m_config->getTestsOrTags() )
+ << '\n';
+ }
+ m_stream << "RNG seed: " << m_config->rngSeed() << '\n';
+ }
+
+ void CompactReporter::assertionEnded( AssertionStats const& _assertionStats ) {
+ AssertionResult const& result = _assertionStats.assertionResult;
+
+ bool printInfoMessages = true;
+
+ // Drop out if result was successful and we're not printing those
+ if( !m_config->includeSuccessfulResults() && result.isOk() ) {
+ if( result.getResultType() != ResultWas::Warning )
+ return;
+ printInfoMessages = false;
+ }
+
+ AssertionPrinter printer( m_stream, _assertionStats, printInfoMessages, m_colour.get() );
+ printer.print();
+
+ m_stream << '\n' << std::flush;
+ }
+
+ void CompactReporter::sectionEnded(SectionStats const& _sectionStats) {
+ double dur = _sectionStats.durationInSeconds;
+ if ( shouldShowDuration( *m_config, dur ) ) {
+ m_stream << getFormattedDuration( dur ) << " s: " << _sectionStats.sectionInfo.name << '\n' << std::flush;
+ }
+ }
+
+ void CompactReporter::testRunEnded( TestRunStats const& _testRunStats ) {
+ printTotals( m_stream, _testRunStats.totals, m_colour.get() );
+ m_stream << "\n\n" << std::flush;
+ StreamingReporterBase::testRunEnded( _testRunStats );
+ }
+
+ CompactReporter::~CompactReporter() {}
+
+} // end namespace Catch
+
+
+
+
+#include <cstdio>
+
+#if defined(_MSC_VER)
+#pragma warning(push)
+#pragma warning(disable:4061) // Not all labels are EXPLICITLY handled in switch
+ // Note that 4062 (not all labels are handled and default is missing) is enabled
+#endif
+
+#if defined(__clang__)
+# pragma clang diagnostic push
+// For simplicity, benchmarking-only helpers are always enabled
+# pragma clang diagnostic ignored "-Wunused-function"
+#endif
+
+
+
+namespace Catch {
+
+namespace {
+
+// Formatter impl for ConsoleReporter
+class ConsoleAssertionPrinter {
+public:
+ ConsoleAssertionPrinter& operator= (ConsoleAssertionPrinter const&) = delete;
+ ConsoleAssertionPrinter(ConsoleAssertionPrinter const&) = delete;
+ ConsoleAssertionPrinter(std::ostream& _stream, AssertionStats const& _stats, ColourImpl* colourImpl_, bool _printInfoMessages)
+ : stream(_stream),
+ stats(_stats),
+ result(_stats.assertionResult),
+ colour(Colour::None),
+ message(result.getMessage()),
+ messages(_stats.infoMessages),
+ colourImpl(colourImpl_),
+ printInfoMessages(_printInfoMessages) {
+ switch (result.getResultType()) {
+ case ResultWas::Ok:
+ colour = Colour::Success;
+ passOrFail = "PASSED"_sr;
+ //if( result.hasMessage() )
+ if (_stats.infoMessages.size() == 1)
+ messageLabel = "with message";
+ if (_stats.infoMessages.size() > 1)
+ messageLabel = "with messages";
+ break;
+ case ResultWas::ExpressionFailed:
+ if (result.isOk()) {
+ colour = Colour::Success;
+ passOrFail = "FAILED - but was ok"_sr;
+ } else {
+ colour = Colour::Error;
+ passOrFail = "FAILED"_sr;
+ }
+ if (_stats.infoMessages.size() == 1)
+ messageLabel = "with message";
+ if (_stats.infoMessages.size() > 1)
+ messageLabel = "with messages";
+ break;
+ case ResultWas::ThrewException:
+ colour = Colour::Error;
+ passOrFail = "FAILED"_sr;
+ messageLabel = "due to unexpected exception with ";
+ if (_stats.infoMessages.size() == 1)
+ messageLabel += "message";
+ if (_stats.infoMessages.size() > 1)
+ messageLabel += "messages";
+ break;
+ case ResultWas::FatalErrorCondition:
+ colour = Colour::Error;
+ passOrFail = "FAILED"_sr;
+ messageLabel = "due to a fatal error condition";
+ break;
+ case ResultWas::DidntThrowException:
+ colour = Colour::Error;
+ passOrFail = "FAILED"_sr;
+ messageLabel = "because no exception was thrown where one was expected";
+ break;
+ case ResultWas::Info:
+ messageLabel = "info";
+ break;
+ case ResultWas::Warning:
+ messageLabel = "warning";
+ break;
+ case ResultWas::ExplicitFailure:
+ passOrFail = "FAILED"_sr;
+ colour = Colour::Error;
+ if (_stats.infoMessages.size() == 1)
+ messageLabel = "explicitly with message";
+ if (_stats.infoMessages.size() > 1)
+ messageLabel = "explicitly with messages";
+ break;
+ // These cases are here to prevent compiler warnings
+ case ResultWas::Unknown:
+ case ResultWas::FailureBit:
+ case ResultWas::Exception:
+ passOrFail = "** internal error **"_sr;
+ colour = Colour::Error;
+ break;
+ }
+ }
+
+ void print() const {
+ printSourceInfo();
+ if (stats.totals.assertions.total() > 0) {
+ printResultType();
+ printOriginalExpression();
+ printReconstructedExpression();
+ } else {
+ stream << '\n';
+ }
+ printMessage();
+ }
+
+private:
+ void printResultType() const {
+ if (!passOrFail.empty()) {
+ stream << colourImpl->guardColour(colour) << passOrFail << ":\n";
+ }
+ }
+ void printOriginalExpression() const {
+ if (result.hasExpression()) {
+ stream << colourImpl->guardColour( Colour::OriginalExpression )
+ << " " << result.getExpressionInMacro() << '\n';
+ }
+ }
+ void printReconstructedExpression() const {
+ if (result.hasExpandedExpression()) {
+ stream << "with expansion:\n";
+ stream << colourImpl->guardColour( Colour::ReconstructedExpression )
+ << TextFlow::Column( result.getExpandedExpression() )
+ .indent( 2 )
+ << '\n';
+ }
+ }
+ void printMessage() const {
+ if (!messageLabel.empty())
+ stream << messageLabel << ':' << '\n';
+ for (auto const& msg : messages) {
+ // If this assertion is a warning ignore any INFO messages
+ if (printInfoMessages || msg.type != ResultWas::Info)
+ stream << TextFlow::Column(msg.message).indent(2) << '\n';
+ }
+ }
+ void printSourceInfo() const {
+ stream << colourImpl->guardColour( Colour::FileName )
+ << result.getSourceInfo() << ": ";
+ }
+
+ std::ostream& stream;
+ AssertionStats const& stats;
+ AssertionResult const& result;
+ Colour::Code colour;
+ StringRef passOrFail;
+ std::string messageLabel;
+ std::string message;
+ std::vector<MessageInfo> messages;
+ ColourImpl* colourImpl;
+ bool printInfoMessages;
+};
+
+std::size_t makeRatio( std::uint64_t number, std::uint64_t total ) {
+ const auto ratio = total > 0 ? CATCH_CONFIG_CONSOLE_WIDTH * number / total : 0;
+ return (ratio == 0 && number > 0) ? 1 : static_cast<std::size_t>(ratio);
+}
+
+std::size_t& findMax( std::size_t& i, std::size_t& j, std::size_t& k ) {
+ if (i > j && i > k)
+ return i;
+ else if (j > k)
+ return j;
+ else
+ return k;
+}
+
+enum class Justification { Left, Right };
+
+struct ColumnInfo {
+ std::string name;
+ std::size_t width;
+ Justification justification;
+};
+struct ColumnBreak {};
+struct RowBreak {};
+
+class Duration {
+ enum class Unit {
+ Auto,
+ Nanoseconds,
+ Microseconds,
+ Milliseconds,
+ Seconds,
+ Minutes
+ };
+ static const uint64_t s_nanosecondsInAMicrosecond = 1000;
+ static const uint64_t s_nanosecondsInAMillisecond = 1000 * s_nanosecondsInAMicrosecond;
+ static const uint64_t s_nanosecondsInASecond = 1000 * s_nanosecondsInAMillisecond;
+ static const uint64_t s_nanosecondsInAMinute = 60 * s_nanosecondsInASecond;
+
+ double m_inNanoseconds;
+ Unit m_units;
+
+public:
+ explicit Duration(double inNanoseconds, Unit units = Unit::Auto)
+ : m_inNanoseconds(inNanoseconds),
+ m_units(units) {
+ if (m_units == Unit::Auto) {
+ if (m_inNanoseconds < s_nanosecondsInAMicrosecond)
+ m_units = Unit::Nanoseconds;
+ else if (m_inNanoseconds < s_nanosecondsInAMillisecond)
+ m_units = Unit::Microseconds;
+ else if (m_inNanoseconds < s_nanosecondsInASecond)
+ m_units = Unit::Milliseconds;
+ else if (m_inNanoseconds < s_nanosecondsInAMinute)
+ m_units = Unit::Seconds;
+ else
+ m_units = Unit::Minutes;
+ }
+
+ }
+
+ auto value() const -> double {
+ switch (m_units) {
+ case Unit::Microseconds:
+ return m_inNanoseconds / static_cast<double>(s_nanosecondsInAMicrosecond);
+ case Unit::Milliseconds:
+ return m_inNanoseconds / static_cast<double>(s_nanosecondsInAMillisecond);
+ case Unit::Seconds:
+ return m_inNanoseconds / static_cast<double>(s_nanosecondsInASecond);
+ case Unit::Minutes:
+ return m_inNanoseconds / static_cast<double>(s_nanosecondsInAMinute);
+ default:
+ return m_inNanoseconds;
+ }
+ }
+ StringRef unitsAsString() const {
+ switch (m_units) {
+ case Unit::Nanoseconds:
+ return "ns"_sr;
+ case Unit::Microseconds:
+ return "us"_sr;
+ case Unit::Milliseconds:
+ return "ms"_sr;
+ case Unit::Seconds:
+ return "s"_sr;
+ case Unit::Minutes:
+ return "m"_sr;
+ default:
+ return "** internal error **"_sr;
+ }
+
+ }
+ friend auto operator << (std::ostream& os, Duration const& duration) -> std::ostream& {
+ return os << duration.value() << ' ' << duration.unitsAsString();
+ }
+};
+} // end anon namespace
+
+class TablePrinter {
+ std::ostream& m_os;
+ std::vector<ColumnInfo> m_columnInfos;
+ ReusableStringStream m_oss;
+ int m_currentColumn = -1;
+ bool m_isOpen = false;
+
+public:
+ TablePrinter( std::ostream& os, std::vector<ColumnInfo> columnInfos )
+ : m_os( os ),
+ m_columnInfos( CATCH_MOVE( columnInfos ) ) {}
+
+ auto columnInfos() const -> std::vector<ColumnInfo> const& {
+ return m_columnInfos;
+ }
+
+ void open() {
+ if (!m_isOpen) {
+ m_isOpen = true;
+ *this << RowBreak();
+
+ TextFlow::Columns headerCols;
+ auto spacer = TextFlow::Spacer(2);
+ for (auto const& info : m_columnInfos) {
+ assert(info.width > 2);
+ headerCols += TextFlow::Column(info.name).width(info.width - 2);
+ headerCols += spacer;
+ }
+ m_os << headerCols << '\n';
+
+ m_os << lineOfChars('-') << '\n';
+ }
+ }
+ void close() {
+ if (m_isOpen) {
+ *this << RowBreak();
+ m_os << '\n' << std::flush;
+ m_isOpen = false;
+ }
+ }
+
+ template<typename T>
+ friend TablePrinter& operator << (TablePrinter& tp, T const& value) {
+ tp.m_oss << value;
+ return tp;
+ }
+
+ friend TablePrinter& operator << (TablePrinter& tp, ColumnBreak) {
+ auto colStr = tp.m_oss.str();
+ const auto strSize = colStr.size();
+ tp.m_oss.str("");
+ tp.open();
+ if (tp.m_currentColumn == static_cast<int>(tp.m_columnInfos.size() - 1)) {
+ tp.m_currentColumn = -1;
+ tp.m_os << '\n';
+ }
+ tp.m_currentColumn++;
+
+ auto colInfo = tp.m_columnInfos[tp.m_currentColumn];
+ auto padding = (strSize + 1 < colInfo.width)
+ ? std::string(colInfo.width - (strSize + 1), ' ')
+ : std::string();
+ if (colInfo.justification == Justification::Left)
+ tp.m_os << colStr << padding << ' ';
+ else
+ tp.m_os << padding << colStr << ' ';
+ return tp;
+ }
+
+ friend TablePrinter& operator << (TablePrinter& tp, RowBreak) {
+ if (tp.m_currentColumn > 0) {
+ tp.m_os << '\n';
+ tp.m_currentColumn = -1;
+ }
+ return tp;
+ }
+};
+
+ConsoleReporter::ConsoleReporter(ReporterConfig&& config):
+ StreamingReporterBase( CATCH_MOVE( config ) ),
+ m_tablePrinter(Detail::make_unique<TablePrinter>(m_stream,
+ [&config]() -> std::vector<ColumnInfo> {
+ if (config.fullConfig()->benchmarkNoAnalysis())
+ {
+ return{
+ { "benchmark name", CATCH_CONFIG_CONSOLE_WIDTH - 43, Justification::Left },
+ { " samples", 14, Justification::Right },
+ { " iterations", 14, Justification::Right },
+ { " mean", 14, Justification::Right }
+ };
+ }
+ else
+ {
+ return{
+ { "benchmark name", CATCH_CONFIG_CONSOLE_WIDTH - 43, Justification::Left },
+ { "samples mean std dev", 14, Justification::Right },
+ { "iterations low mean low std dev", 14, Justification::Right },
+ { "estimated high mean high std dev", 14, Justification::Right }
+ };
+ }
+ }())) {}
+ConsoleReporter::~ConsoleReporter() = default;
+
+std::string ConsoleReporter::getDescription() {
+ return "Reports test results as plain lines of text";
+}
+
+void ConsoleReporter::noMatchingTestCases( StringRef unmatchedSpec ) {
+ m_stream << "No test cases matched '" << unmatchedSpec << "'\n";
+}
+
+void ConsoleReporter::reportInvalidTestSpec( StringRef arg ) {
+ m_stream << "Invalid Filter: " << arg << '\n';
+}
+
+void ConsoleReporter::assertionStarting(AssertionInfo const&) {}
+
+void ConsoleReporter::assertionEnded(AssertionStats const& _assertionStats) {
+ AssertionResult const& result = _assertionStats.assertionResult;
+
+ bool includeResults = m_config->includeSuccessfulResults() || !result.isOk();
+
+ // Drop out if result was successful but we're not printing them.
+ if (!includeResults && result.getResultType() != ResultWas::Warning)
+ return;
+
+ lazyPrint();
+
+ ConsoleAssertionPrinter printer(m_stream, _assertionStats, m_colour.get(), includeResults);
+ printer.print();
+ m_stream << '\n' << std::flush;
+}
+
+void ConsoleReporter::sectionStarting(SectionInfo const& _sectionInfo) {
+ m_tablePrinter->close();
+ m_headerPrinted = false;
+ StreamingReporterBase::sectionStarting(_sectionInfo);
+}
+void ConsoleReporter::sectionEnded(SectionStats const& _sectionStats) {
+ m_tablePrinter->close();
+ if (_sectionStats.missingAssertions) {
+ lazyPrint();
+ auto guard =
+ m_colour->guardColour( Colour::ResultError ).engage( m_stream );
+ if (m_sectionStack.size() > 1)
+ m_stream << "\nNo assertions in section";
+ else
+ m_stream << "\nNo assertions in test case";
+ m_stream << " '" << _sectionStats.sectionInfo.name << "'\n\n" << std::flush;
+ }
+ double dur = _sectionStats.durationInSeconds;
+ if (shouldShowDuration(*m_config, dur)) {
+ m_stream << getFormattedDuration(dur) << " s: " << _sectionStats.sectionInfo.name << '\n' << std::flush;
+ }
+ if (m_headerPrinted) {
+ m_headerPrinted = false;
+ }
+ StreamingReporterBase::sectionEnded(_sectionStats);
+}
+
+void ConsoleReporter::benchmarkPreparing( StringRef name ) {
+ lazyPrintWithoutClosingBenchmarkTable();
+
+ auto nameCol = TextFlow::Column( static_cast<std::string>( name ) )
+ .width( m_tablePrinter->columnInfos()[0].width - 2 );
+
+ bool firstLine = true;
+ for (auto line : nameCol) {
+ if (!firstLine)
+ (*m_tablePrinter) << ColumnBreak() << ColumnBreak() << ColumnBreak();
+ else
+ firstLine = false;
+
+ (*m_tablePrinter) << line << ColumnBreak();
+ }
+}
+
+void ConsoleReporter::benchmarkStarting(BenchmarkInfo const& info) {
+ (*m_tablePrinter) << info.samples << ColumnBreak()
+ << info.iterations << ColumnBreak();
+ if (!m_config->benchmarkNoAnalysis())
+ (*m_tablePrinter) << Duration(info.estimatedDuration) << ColumnBreak();
+}
+void ConsoleReporter::benchmarkEnded(BenchmarkStats<> const& stats) {
+ if (m_config->benchmarkNoAnalysis())
+ {
+ (*m_tablePrinter) << Duration(stats.mean.point.count()) << ColumnBreak();
+ }
+ else
+ {
+ (*m_tablePrinter) << ColumnBreak()
+ << Duration(stats.mean.point.count()) << ColumnBreak()
+ << Duration(stats.mean.lower_bound.count()) << ColumnBreak()
+ << Duration(stats.mean.upper_bound.count()) << ColumnBreak() << ColumnBreak()
+ << Duration(stats.standardDeviation.point.count()) << ColumnBreak()
+ << Duration(stats.standardDeviation.lower_bound.count()) << ColumnBreak()
+ << Duration(stats.standardDeviation.upper_bound.count()) << ColumnBreak() << ColumnBreak() << ColumnBreak() << ColumnBreak() << ColumnBreak();
+ }
+}
+
+void ConsoleReporter::benchmarkFailed( StringRef error ) {
+ auto guard = m_colour->guardColour( Colour::Red ).engage( m_stream );
+ (*m_tablePrinter)
+ << "Benchmark failed (" << error << ')'
+ << ColumnBreak() << RowBreak();
+}
+
+void ConsoleReporter::testCaseEnded(TestCaseStats const& _testCaseStats) {
+ m_tablePrinter->close();
+ StreamingReporterBase::testCaseEnded(_testCaseStats);
+ m_headerPrinted = false;
+}
+void ConsoleReporter::testRunEnded(TestRunStats const& _testRunStats) {
+ printTotalsDivider(_testRunStats.totals);
+ printTotals(_testRunStats.totals);
+ m_stream << '\n' << std::flush;
+ StreamingReporterBase::testRunEnded(_testRunStats);
+}
+void ConsoleReporter::testRunStarting(TestRunInfo const& _testInfo) {
+ StreamingReporterBase::testRunStarting(_testInfo);
+ if ( m_config->testSpec().hasFilters() ) {
+ m_stream << m_colour->guardColour( Colour::BrightYellow ) << "Filters: "
+ << serializeFilters( m_config->getTestsOrTags() ) << '\n';
+ }
+ m_stream << "Randomness seeded to: " << m_config->rngSeed() << '\n';
+}
+
+void ConsoleReporter::lazyPrint() {
+
+ m_tablePrinter->close();
+ lazyPrintWithoutClosingBenchmarkTable();
+}
+
+void ConsoleReporter::lazyPrintWithoutClosingBenchmarkTable() {
+
+ if ( !m_testRunInfoPrinted ) {
+ lazyPrintRunInfo();
+ }
+ if (!m_headerPrinted) {
+ printTestCaseAndSectionHeader();
+ m_headerPrinted = true;
+ }
+}
+void ConsoleReporter::lazyPrintRunInfo() {
+ m_stream << '\n'
+ << lineOfChars( '~' ) << '\n'
+ << m_colour->guardColour( Colour::SecondaryText )
+ << currentTestRunInfo.name << " is a Catch2 v" << libraryVersion()
+ << " host application.\n"
+ << "Run with -? for options\n\n";
+
+ m_testRunInfoPrinted = true;
+}
+void ConsoleReporter::printTestCaseAndSectionHeader() {
+ assert(!m_sectionStack.empty());
+ printOpenHeader(currentTestCaseInfo->name);
+
+ if (m_sectionStack.size() > 1) {
+ auto guard = m_colour->guardColour( Colour::Headers ).engage( m_stream );
+
+ auto
+ it = m_sectionStack.begin() + 1, // Skip first section (test case)
+ itEnd = m_sectionStack.end();
+ for (; it != itEnd; ++it)
+ printHeaderString(it->name, 2);
+ }
+
+ SourceLineInfo lineInfo = m_sectionStack.back().lineInfo;
+
+
+ m_stream << lineOfChars( '-' ) << '\n'
+ << m_colour->guardColour( Colour::FileName ) << lineInfo << '\n'
+ << lineOfChars( '.' ) << "\n\n"
+ << std::flush;
+}
+
+void ConsoleReporter::printClosedHeader(std::string const& _name) {
+ printOpenHeader(_name);
+ m_stream << lineOfChars('.') << '\n';
+}
+void ConsoleReporter::printOpenHeader(std::string const& _name) {
+ m_stream << lineOfChars('-') << '\n';
+ {
+ auto guard = m_colour->guardColour( Colour::Headers ).engage( m_stream );
+ printHeaderString(_name);
+ }
+}
+
+void ConsoleReporter::printHeaderString(std::string const& _string, std::size_t indent) {
+ // We want to get a bit fancy with line breaking here, so that subsequent
+ // lines start after ":" if one is present, e.g.
+ // ```
+ // blablabla: Fancy
+ // linebreaking
+ // ```
+ // but we also want to avoid problems with overly long indentation causing
+ // the text to take up too many lines, e.g.
+ // ```
+ // blablabla: F
+ // a
+ // n
+ // c
+ // y
+ // .
+ // .
+ // .
+ // ```
+ // So we limit the prefix indentation check to first quarter of the possible
+ // width
+ std::size_t idx = _string.find( ": " );
+ if ( idx != std::string::npos && idx < CATCH_CONFIG_CONSOLE_WIDTH / 4 ) {
+ idx += 2;
+ } else {
+ idx = 0;
+ }
+ m_stream << TextFlow::Column( _string )
+ .indent( indent + idx )
+ .initialIndent( indent )
+ << '\n';
+}
+
+struct SummaryColumn {
+
+ SummaryColumn( std::string _label, Colour::Code _colour )
+ : label( CATCH_MOVE( _label ) ),
+ colour( _colour ) {}
+ SummaryColumn addRow( std::uint64_t count ) {
+ ReusableStringStream rss;
+ rss << count;
+ std::string row = rss.str();
+ for (auto& oldRow : rows) {
+ while (oldRow.size() < row.size())
+ oldRow = ' ' + oldRow;
+ while (oldRow.size() > row.size())
+ row = ' ' + row;
+ }
+ rows.push_back(row);
+ return *this;
+ }
+
+ std::string label;
+ Colour::Code colour;
+ std::vector<std::string> rows;
+
+};
+
+void ConsoleReporter::printTotals( Totals const& totals ) {
+ if (totals.testCases.total() == 0) {
+ m_stream << m_colour->guardColour( Colour::Warning )
+ << "No tests ran\n";
+ } else if (totals.assertions.total() > 0 && totals.testCases.allPassed()) {
+ m_stream << m_colour->guardColour( Colour::ResultSuccess )
+ << "All tests passed";
+ m_stream << " ("
+ << pluralise(totals.assertions.passed, "assertion"_sr) << " in "
+ << pluralise(totals.testCases.passed, "test case"_sr) << ')'
+ << '\n';
+ } else {
+
+ std::vector<SummaryColumn> columns;
+ columns.push_back(SummaryColumn("", Colour::None)
+ .addRow(totals.testCases.total())
+ .addRow(totals.assertions.total()));
+ columns.push_back(SummaryColumn("passed", Colour::Success)
+ .addRow(totals.testCases.passed)
+ .addRow(totals.assertions.passed));
+ columns.push_back(SummaryColumn("failed", Colour::ResultError)
+ .addRow(totals.testCases.failed)
+ .addRow(totals.assertions.failed));
+ columns.push_back(SummaryColumn("failed as expected", Colour::ResultExpectedFailure)
+ .addRow(totals.testCases.failedButOk)
+ .addRow(totals.assertions.failedButOk));
+
+ printSummaryRow("test cases"_sr, columns, 0);
+ printSummaryRow("assertions"_sr, columns, 1);
+ }
+}
+void ConsoleReporter::printSummaryRow(StringRef label, std::vector<SummaryColumn> const& cols, std::size_t row) {
+ for (auto col : cols) {
+ std::string const& value = col.rows[row];
+ if (col.label.empty()) {
+ m_stream << label << ": ";
+ if ( value != "0" ) {
+ m_stream << value;
+ } else {
+ m_stream << m_colour->guardColour( Colour::Warning )
+ << "- none -";
+ }
+ } else if (value != "0") {
+ m_stream << m_colour->guardColour( Colour::LightGrey ) << " | "
+ << m_colour->guardColour( col.colour ) << value << ' '
+ << col.label;
+ }
+ }
+ m_stream << '\n';
+}
+
+void ConsoleReporter::printTotalsDivider(Totals const& totals) {
+ if (totals.testCases.total() > 0) {
+ std::size_t failedRatio = makeRatio(totals.testCases.failed, totals.testCases.total());
+ std::size_t failedButOkRatio = makeRatio(totals.testCases.failedButOk, totals.testCases.total());
+ std::size_t passedRatio = makeRatio(totals.testCases.passed, totals.testCases.total());
+ while (failedRatio + failedButOkRatio + passedRatio < CATCH_CONFIG_CONSOLE_WIDTH - 1)
+ findMax(failedRatio, failedButOkRatio, passedRatio)++;
+ while (failedRatio + failedButOkRatio + passedRatio > CATCH_CONFIG_CONSOLE_WIDTH - 1)
+ findMax(failedRatio, failedButOkRatio, passedRatio)--;
+
+ m_stream << m_colour->guardColour( Colour::Error )
+ << std::string( failedRatio, '=' )
+ << m_colour->guardColour( Colour::ResultExpectedFailure )
+ << std::string( failedButOkRatio, '=' );
+ if ( totals.testCases.allPassed() ) {
+ m_stream << m_colour->guardColour( Colour::ResultSuccess )
+ << std::string( passedRatio, '=' );
+ } else {
+ m_stream << m_colour->guardColour( Colour::Success )
+ << std::string( passedRatio, '=' );
+ }
+ } else {
+ m_stream << m_colour->guardColour( Colour::Warning )
+ << std::string( CATCH_CONFIG_CONSOLE_WIDTH - 1, '=' );
+ }
+ m_stream << '\n';
+}
+void ConsoleReporter::printSummaryDivider() {
+ m_stream << lineOfChars('-') << '\n';
+}
+
+} // end namespace Catch
+
+#if defined(_MSC_VER)
+#pragma warning(pop)
+#endif
+
+#if defined(__clang__)
+# pragma clang diagnostic pop
+#endif
+
+
+
+
+#include <algorithm>
+#include <cassert>
+
+namespace Catch {
+ namespace {
+ struct BySectionInfo {
+ BySectionInfo( SectionInfo const& other ): m_other( other ) {}
+ BySectionInfo( BySectionInfo const& other ):
+ m_other( other.m_other ) {}
+ bool operator()(
+ Detail::unique_ptr<CumulativeReporterBase::SectionNode> const&
+ node ) const {
+ return (
+ ( node->stats.sectionInfo.name == m_other.name ) &&
+ ( node->stats.sectionInfo.lineInfo == m_other.lineInfo ) );
+ }
+ void operator=( BySectionInfo const& ) = delete;
+
+ private:
+ SectionInfo const& m_other;
+ };
+
+ } // namespace
+
+ namespace Detail {
+ AssertionOrBenchmarkResult::AssertionOrBenchmarkResult(
+ AssertionStats const& assertion ):
+ m_assertion( assertion ) {}
+
+ AssertionOrBenchmarkResult::AssertionOrBenchmarkResult(
+ BenchmarkStats<> const& benchmark ):
+ m_benchmark( benchmark ) {}
+
+ bool AssertionOrBenchmarkResult::isAssertion() const {
+ return m_assertion.some();
+ }
+ bool AssertionOrBenchmarkResult::isBenchmark() const {
+ return m_benchmark.some();
+ }
+
+ AssertionStats const& AssertionOrBenchmarkResult::asAssertion() const {
+ assert(m_assertion.some());
+
+ return *m_assertion;
+ }
+ BenchmarkStats<> const& AssertionOrBenchmarkResult::asBenchmark() const {
+ assert(m_benchmark.some());
+
+ return *m_benchmark;
+ }
+
+ }
+
+ CumulativeReporterBase::~CumulativeReporterBase() = default;
+
+ void CumulativeReporterBase::benchmarkEnded(BenchmarkStats<> const& benchmarkStats) {
+ m_sectionStack.back()->assertionsAndBenchmarks.emplace_back(benchmarkStats);
+ }
+
+ void
+ CumulativeReporterBase::sectionStarting( SectionInfo const& sectionInfo ) {
+ SectionStats incompleteStats( sectionInfo, Counts(), 0, false );
+ SectionNode* node;
+ if ( m_sectionStack.empty() ) {
+ if ( !m_rootSection ) {
+ m_rootSection =
+ Detail::make_unique<SectionNode>( incompleteStats );
+ }
+ node = m_rootSection.get();
+ } else {
+ SectionNode& parentNode = *m_sectionStack.back();
+ auto it = std::find_if( parentNode.childSections.begin(),
+ parentNode.childSections.end(),
+ BySectionInfo( sectionInfo ) );
+ if ( it == parentNode.childSections.end() ) {
+ auto newNode =
+ Detail::make_unique<SectionNode>( incompleteStats );
+ node = newNode.get();
+ parentNode.childSections.push_back( CATCH_MOVE( newNode ) );
+ } else {
+ node = it->get();
+ }
+ }
+
+ m_deepestSection = node;
+ m_sectionStack.push_back( node );
+ }
+
+ void CumulativeReporterBase::assertionEnded(
+ AssertionStats const& assertionStats ) {
+ assert( !m_sectionStack.empty() );
+ // AssertionResult holds a pointer to a temporary DecomposedExpression,
+ // which getExpandedExpression() calls to build the expression string.
+ // Our section stack copy of the assertionResult will likely outlive the
+ // temporary, so it must be expanded or discarded now to avoid calling
+ // a destroyed object later.
+ if ( m_shouldStoreFailedAssertions &&
+ !assertionStats.assertionResult.isOk() ) {
+ static_cast<void>(
+ assertionStats.assertionResult.getExpandedExpression() );
+ }
+ if ( m_shouldStoreSuccesfulAssertions &&
+ assertionStats.assertionResult.isOk() ) {
+ static_cast<void>(
+ assertionStats.assertionResult.getExpandedExpression() );
+ }
+ SectionNode& sectionNode = *m_sectionStack.back();
+ sectionNode.assertionsAndBenchmarks.emplace_back( assertionStats );
+ }
+
+ void CumulativeReporterBase::sectionEnded( SectionStats const& sectionStats ) {
+ assert( !m_sectionStack.empty() );
+ SectionNode& node = *m_sectionStack.back();
+ node.stats = sectionStats;
+ m_sectionStack.pop_back();
+ }
+
+ void CumulativeReporterBase::testCaseEnded(
+ TestCaseStats const& testCaseStats ) {
+ auto node = Detail::make_unique<TestCaseNode>( testCaseStats );
+ assert( m_sectionStack.size() == 0 );
+ node->children.push_back( CATCH_MOVE(m_rootSection) );
+ m_testCases.push_back( CATCH_MOVE(node) );
+
+ assert( m_deepestSection );
+ m_deepestSection->stdOut = testCaseStats.stdOut;
+ m_deepestSection->stdErr = testCaseStats.stdErr;
+ }
+
+
+ void CumulativeReporterBase::testRunEnded( TestRunStats const& testRunStats ) {
+ assert(!m_testRun && "CumulativeReporterBase assumes there can only be one test run");
+ m_testRun = Detail::make_unique<TestRunNode>( testRunStats );
+ m_testRun->children.swap( m_testCases );
+ testRunEndedCumulative();
+ }
+
+ bool CumulativeReporterBase::SectionNode::hasAnyAssertions() const {
+ return std::any_of(
+ assertionsAndBenchmarks.begin(),
+ assertionsAndBenchmarks.end(),
+ []( Detail::AssertionOrBenchmarkResult const& res ) {
+ return res.isAssertion();
+ } );
+ }
+
+} // end namespace Catch
+
+
+
+
+namespace Catch {
+
+ void EventListenerBase::fatalErrorEncountered( StringRef ) {}
+
+ void EventListenerBase::benchmarkPreparing( StringRef ) {}
+ void EventListenerBase::benchmarkStarting( BenchmarkInfo const& ) {}
+ void EventListenerBase::benchmarkEnded( BenchmarkStats<> const& ) {}
+ void EventListenerBase::benchmarkFailed( StringRef ) {}
+
+ void EventListenerBase::assertionStarting( AssertionInfo const& ) {}
+
+ void EventListenerBase::assertionEnded( AssertionStats const& ) {}
+ void EventListenerBase::listReporters(
+ std::vector<ReporterDescription> const& ) {}
+ void EventListenerBase::listListeners(
+ std::vector<ListenerDescription> const& ) {}
+ void EventListenerBase::listTests( std::vector<TestCaseHandle> const& ) {}
+ void EventListenerBase::listTags( std::vector<TagInfo> const& ) {}
+ void EventListenerBase::noMatchingTestCases( StringRef ) {}
+ void EventListenerBase::reportInvalidTestSpec( StringRef ) {}
+ void EventListenerBase::testRunStarting( TestRunInfo const& ) {}
+ void EventListenerBase::testCaseStarting( TestCaseInfo const& ) {}
+ void EventListenerBase::testCasePartialStarting(TestCaseInfo const&, uint64_t) {}
+ void EventListenerBase::sectionStarting( SectionInfo const& ) {}
+ void EventListenerBase::sectionEnded( SectionStats const& ) {}
+ void EventListenerBase::testCasePartialEnded(TestCaseStats const&, uint64_t) {}
+ void EventListenerBase::testCaseEnded( TestCaseStats const& ) {}
+ void EventListenerBase::testRunEnded( TestRunStats const& ) {}
+ void EventListenerBase::skipTest( TestCaseInfo const& ) {}
+} // namespace Catch
+
+
+
+
+#include <algorithm>
+#include <cfloat>
+#include <cstdio>
+#include <ostream>
+#include <iomanip>
+
+namespace Catch {
+
+ namespace {
+ void listTestNamesOnly(std::ostream& out,
+ std::vector<TestCaseHandle> const& tests) {
+ for (auto const& test : tests) {
+ auto const& testCaseInfo = test.getTestCaseInfo();
+
+ if (startsWith(testCaseInfo.name, '#')) {
+ out << '"' << testCaseInfo.name << '"';
+ } else {
+ out << testCaseInfo.name;
+ }
+
+ out << '\n';
+ }
+ out << std::flush;
+ }
+ } // end unnamed namespace
+
+
+ // Because formatting using c++ streams is stateful, drop down to C is
+ // required Alternatively we could use stringstream, but its performance
+ // is... not good.
+ std::string getFormattedDuration( double duration ) {
+ // Max exponent + 1 is required to represent the whole part
+ // + 1 for decimal point
+ // + 3 for the 3 decimal places
+ // + 1 for null terminator
+ const std::size_t maxDoubleSize = DBL_MAX_10_EXP + 1 + 1 + 3 + 1;
+ char buffer[maxDoubleSize];
+
+ // Save previous errno, to prevent sprintf from overwriting it
+ ErrnoGuard guard;
+#ifdef _MSC_VER
+ size_t printedLength = static_cast<size_t>(
+ sprintf_s( buffer, "%.3f", duration ) );
+#else
+ size_t printedLength = static_cast<size_t>(
+ std::snprintf( buffer, maxDoubleSize, "%.3f", duration ) );
+#endif
+ return std::string( buffer, printedLength );
+ }
+
+ bool shouldShowDuration( IConfig const& config, double duration ) {
+ if ( config.showDurations() == ShowDurations::Always ) {
+ return true;
+ }
+ if ( config.showDurations() == ShowDurations::Never ) {
+ return false;
+ }
+ const double min = config.minDuration();
+ return min >= 0 && duration >= min;
+ }
+
+ std::string serializeFilters( std::vector<std::string> const& filters ) {
+ // We add a ' ' separator between each filter
+ size_t serialized_size = filters.size() - 1;
+ for (auto const& filter : filters) {
+ serialized_size += filter.size();
+ }
+
+ std::string serialized;
+ serialized.reserve(serialized_size);
+ bool first = true;
+
+ for (auto const& filter : filters) {
+ if (!first) {
+ serialized.push_back(' ');
+ }
+ first = false;
+ serialized.append(filter);
+ }
+
+ return serialized;
+ }
+
+ std::ostream& operator<<( std::ostream& out, lineOfChars value ) {
+ for ( size_t idx = 0; idx < CATCH_CONFIG_CONSOLE_WIDTH - 1; ++idx ) {
+ out.put( value.c );
+ }
+ return out;
+ }
+
+ void
+ defaultListReporters( std::ostream& out,
+ std::vector<ReporterDescription> const& descriptions,
+ Verbosity verbosity ) {
+ out << "Available reporters:\n";
+ const auto maxNameLen =
+ std::max_element( descriptions.begin(),
+ descriptions.end(),
+ []( ReporterDescription const& lhs,
+ ReporterDescription const& rhs ) {
+ return lhs.name.size() < rhs.name.size();
+ } )
+ ->name.size();
+
+ for ( auto const& desc : descriptions ) {
+ if ( verbosity == Verbosity::Quiet ) {
+ out << TextFlow::Column( desc.name )
+ .indent( 2 )
+ .width( 5 + maxNameLen )
+ << '\n';
+ } else {
+ out << TextFlow::Column( desc.name + ':' )
+ .indent( 2 )
+ .width( 5 + maxNameLen ) +
+ TextFlow::Column( desc.description )
+ .initialIndent( 0 )
+ .indent( 2 )
+ .width( CATCH_CONFIG_CONSOLE_WIDTH - maxNameLen - 8 )
+ << '\n';
+ }
+ }
+ out << '\n' << std::flush;
+ }
+
+ void defaultListListeners( std::ostream& out,
+ std::vector<ListenerDescription> const& descriptions ) {
+ out << "Registered listeners:\n";
+
+ if(descriptions.empty()) {
+ return;
+ }
+
+ const auto maxNameLen =
+ std::max_element( descriptions.begin(),
+ descriptions.end(),
+ []( ListenerDescription const& lhs,
+ ListenerDescription const& rhs ) {
+ return lhs.name.size() < rhs.name.size();
+ } )
+ ->name.size();
+
+ for ( auto const& desc : descriptions ) {
+ out << TextFlow::Column( static_cast<std::string>( desc.name ) +
+ ':' )
+ .indent( 2 )
+ .width( maxNameLen + 5 ) +
+ TextFlow::Column( desc.description )
+ .initialIndent( 0 )
+ .indent( 2 )
+ .width( CATCH_CONFIG_CONSOLE_WIDTH - maxNameLen - 8 )
+ << '\n';
+ }
+
+ out << '\n' << std::flush;
+ }
+
+ void defaultListTags( std::ostream& out,
+ std::vector<TagInfo> const& tags,
+ bool isFiltered ) {
+ if ( isFiltered ) {
+ out << "Tags for matching test cases:\n";
+ } else {
+ out << "All available tags:\n";
+ }
+
+ for ( auto const& tagCount : tags ) {
+ ReusableStringStream rss;
+ rss << " " << std::setw( 2 ) << tagCount.count << " ";
+ auto str = rss.str();
+ auto wrapper = TextFlow::Column( tagCount.all() )
+ .initialIndent( 0 )
+ .indent( str.size() )
+ .width( CATCH_CONFIG_CONSOLE_WIDTH - 10 );
+ out << str << wrapper << '\n';
+ }
+ out << pluralise(tags.size(), "tag"_sr) << "\n\n" << std::flush;
+ }
+
+ void defaultListTests(std::ostream& out, ColourImpl* streamColour, std::vector<TestCaseHandle> const& tests, bool isFiltered, Verbosity verbosity) {
+ // We special case this to provide the equivalent of old
+ // `--list-test-names-only`, which could then be used by the
+ // `--input-file` option.
+ if (verbosity == Verbosity::Quiet) {
+ listTestNamesOnly(out, tests);
+ return;
+ }
+
+ if (isFiltered) {
+ out << "Matching test cases:\n";
+ } else {
+ out << "All available test cases:\n";
+ }
+
+ for (auto const& test : tests) {
+ auto const& testCaseInfo = test.getTestCaseInfo();
+ Colour::Code colour = testCaseInfo.isHidden()
+ ? Colour::SecondaryText
+ : Colour::None;
+ auto colourGuard = streamColour->guardColour( colour ).engage( out );
+
+ out << TextFlow::Column(testCaseInfo.name).indent(2) << '\n';
+ if (verbosity >= Verbosity::High) {
+ out << TextFlow::Column(Catch::Detail::stringify(testCaseInfo.lineInfo)).indent(4) << '\n';
+ }
+ if (!testCaseInfo.tags.empty() &&
+ verbosity > Verbosity::Quiet) {
+ out << TextFlow::Column(testCaseInfo.tagsAsString()).indent(6) << '\n';
+ }
+ }
+
+ if (isFiltered) {
+ out << pluralise(tests.size(), "matching test case"_sr);
+ } else {
+ out << pluralise(tests.size(), "test case"_sr);
+ }
+ out << "\n\n" << std::flush;
+ }
+
+} // namespace Catch
+
+
+
+
+#include <cassert>
+#include <ctime>
+#include <algorithm>
+#include <iomanip>
+
+namespace Catch {
+
+ namespace {
+ std::string getCurrentTimestamp() {
+ time_t rawtime;
+ std::time(&rawtime);
+
+ std::tm timeInfo = {};
+#if defined (_MSC_VER) || defined (__MINGW32__)
+ gmtime_s(&timeInfo, &rawtime);
+#else
+ gmtime_r(&rawtime, &timeInfo);
+#endif
+
+ auto const timeStampSize = sizeof("2017-01-16T17:06:45Z");
+ char timeStamp[timeStampSize];
+ const char * const fmt = "%Y-%m-%dT%H:%M:%SZ";
+
+ std::strftime(timeStamp, timeStampSize, fmt, &timeInfo);
+
+ return std::string(timeStamp, timeStampSize - 1);
+ }
+
+ std::string fileNameTag(std::vector<Tag> const& tags) {
+ auto it = std::find_if(begin(tags),
+ end(tags),
+ [] (Tag const& tag) {
+ return tag.original.size() > 0
+ && tag.original[0] == '#'; });
+ if (it != tags.end()) {
+ return static_cast<std::string>(
+ it->original.substr(1, it->original.size() - 1)
+ );
+ }
+ return std::string();
+ }
+
+ // Formats the duration in seconds to 3 decimal places.
+ // This is done because some genius defined Maven Surefire schema
+ // in a way that only accepts 3 decimal places, and tools like
+ // Jenkins use that schema for validation JUnit reporter output.
+ std::string formatDuration( double seconds ) {
+ ReusableStringStream rss;
+ rss << std::fixed << std::setprecision( 3 ) << seconds;
+ return rss.str();
+ }
+
+ static void normalizeNamespaceMarkers(std::string& str) {
+ std::size_t pos = str.find( "::" );
+ while ( pos != str.npos ) {
+ str.replace( pos, 2, "." );
+ pos += 1;
+ pos = str.find( "::", pos );
+ }
+ }
+
+ } // anonymous namespace
+
+ JunitReporter::JunitReporter( ReporterConfig&& _config )
+ : CumulativeReporterBase( CATCH_MOVE(_config) ),
+ xml( m_stream )
+ {
+ m_preferences.shouldRedirectStdOut = true;
+ m_preferences.shouldReportAllAssertions = true;
+ m_shouldStoreSuccesfulAssertions = false;
+ }
+
+ std::string JunitReporter::getDescription() {
+ return "Reports test results in an XML format that looks like Ant's junitreport target";
+ }
+
+ void JunitReporter::testRunStarting( TestRunInfo const& runInfo ) {
+ CumulativeReporterBase::testRunStarting( runInfo );
+ xml.startElement( "testsuites" );
+ suiteTimer.start();
+ stdOutForSuite.clear();
+ stdErrForSuite.clear();
+ unexpectedExceptions = 0;
+ }
+
+ void JunitReporter::testCaseStarting( TestCaseInfo const& testCaseInfo ) {
+ m_okToFail = testCaseInfo.okToFail();
+ }
+
+ void JunitReporter::assertionEnded( AssertionStats const& assertionStats ) {
+ if( assertionStats.assertionResult.getResultType() == ResultWas::ThrewException && !m_okToFail )
+ unexpectedExceptions++;
+ CumulativeReporterBase::assertionEnded( assertionStats );
+ }
+
+ void JunitReporter::testCaseEnded( TestCaseStats const& testCaseStats ) {
+ stdOutForSuite += testCaseStats.stdOut;
+ stdErrForSuite += testCaseStats.stdErr;
+ CumulativeReporterBase::testCaseEnded( testCaseStats );
+ }
+
+ void JunitReporter::testRunEndedCumulative() {
+ const auto suiteTime = suiteTimer.getElapsedSeconds();
+ writeRun( *m_testRun, suiteTime );
+ xml.endElement();
+ }
+
+ void JunitReporter::writeRun( TestRunNode const& testRunNode, double suiteTime ) {
+ XmlWriter::ScopedElement e = xml.scopedElement( "testsuite" );
+
+ TestRunStats const& stats = testRunNode.value;
+ xml.writeAttribute( "name"_sr, stats.runInfo.name );
+ xml.writeAttribute( "errors"_sr, unexpectedExceptions );
+ xml.writeAttribute( "failures"_sr, stats.totals.assertions.failed-unexpectedExceptions );
+ xml.writeAttribute( "tests"_sr, stats.totals.assertions.total() );
+ xml.writeAttribute( "hostname"_sr, "tbd"_sr ); // !TBD
+ if( m_config->showDurations() == ShowDurations::Never )
+ xml.writeAttribute( "time"_sr, ""_sr );
+ else
+ xml.writeAttribute( "time"_sr, formatDuration( suiteTime ) );
+ xml.writeAttribute( "timestamp"_sr, getCurrentTimestamp() );
+
+ // Write properties
+ {
+ auto properties = xml.scopedElement("properties");
+ xml.scopedElement("property")
+ .writeAttribute("name"_sr, "random-seed"_sr)
+ .writeAttribute("value"_sr, m_config->rngSeed());
+ if (m_config->hasTestFilters()) {
+ xml.scopedElement("property")
+ .writeAttribute("name"_sr, "filters"_sr)
+ .writeAttribute("value"_sr, serializeFilters(m_config->getTestsOrTags()));
+ }
+ }
+
+ // Write test cases
+ for( auto const& child : testRunNode.children )
+ writeTestCase( *child );
+
+ xml.scopedElement( "system-out" ).writeText( trim( stdOutForSuite ), XmlFormatting::Newline );
+ xml.scopedElement( "system-err" ).writeText( trim( stdErrForSuite ), XmlFormatting::Newline );
+ }
+
+ void JunitReporter::writeTestCase( TestCaseNode const& testCaseNode ) {
+ TestCaseStats const& stats = testCaseNode.value;
+
+ // All test cases have exactly one section - which represents the
+ // test case itself. That section may have 0-n nested sections
+ assert( testCaseNode.children.size() == 1 );
+ SectionNode const& rootSection = *testCaseNode.children.front();
+
+ std::string className =
+ static_cast<std::string>( stats.testInfo->className );
+
+ if( className.empty() ) {
+ className = fileNameTag(stats.testInfo->tags);
+ if ( className.empty() ) {
+ className = "global";
+ }
+ }
+
+ if ( !m_config->name().empty() )
+ className = static_cast<std::string>(m_config->name()) + '.' + className;
+
+ normalizeNamespaceMarkers(className);
+
+ writeSection( className, "", rootSection, stats.testInfo->okToFail() );
+ }
+
+ void JunitReporter::writeSection( std::string const& className,
+ std::string const& rootName,
+ SectionNode const& sectionNode,
+ bool testOkToFail) {
+ std::string name = trim( sectionNode.stats.sectionInfo.name );
+ if( !rootName.empty() )
+ name = rootName + '/' + name;
+
+ if( sectionNode.hasAnyAssertions()
+ || !sectionNode.stdOut.empty()
+ || !sectionNode.stdErr.empty() ) {
+ XmlWriter::ScopedElement e = xml.scopedElement( "testcase" );
+ if( className.empty() ) {
+ xml.writeAttribute( "classname"_sr, name );
+ xml.writeAttribute( "name"_sr, "root"_sr );
+ }
+ else {
+ xml.writeAttribute( "classname"_sr, className );
+ xml.writeAttribute( "name"_sr, name );
+ }
+ xml.writeAttribute( "time"_sr, formatDuration( sectionNode.stats.durationInSeconds ) );
+ // This is not ideal, but it should be enough to mimic gtest's
+ // junit output.
+ // Ideally the JUnit reporter would also handle `skipTest`
+ // events and write those out appropriately.
+ xml.writeAttribute( "status"_sr, "run"_sr );
+
+ if (sectionNode.stats.assertions.failedButOk) {
+ xml.scopedElement("skipped")
+ .writeAttribute("message", "TEST_CASE tagged with !mayfail");
+ }
+
+ writeAssertions( sectionNode );
+
+
+ if( !sectionNode.stdOut.empty() )
+ xml.scopedElement( "system-out" ).writeText( trim( sectionNode.stdOut ), XmlFormatting::Newline );
+ if( !sectionNode.stdErr.empty() )
+ xml.scopedElement( "system-err" ).writeText( trim( sectionNode.stdErr ), XmlFormatting::Newline );
+ }
+ for( auto const& childNode : sectionNode.childSections )
+ if( className.empty() )
+ writeSection( name, "", *childNode, testOkToFail );
+ else
+ writeSection( className, name, *childNode, testOkToFail );
+ }
+
+ void JunitReporter::writeAssertions( SectionNode const& sectionNode ) {
+ for (auto const& assertionOrBenchmark : sectionNode.assertionsAndBenchmarks) {
+ if (assertionOrBenchmark.isAssertion()) {
+ writeAssertion(assertionOrBenchmark.asAssertion());
+ }
+ }
+ }
+
+ void JunitReporter::writeAssertion( AssertionStats const& stats ) {
+ AssertionResult const& result = stats.assertionResult;
+ if( !result.isOk() ) {
+ std::string elementName;
+ switch( result.getResultType() ) {
+ case ResultWas::ThrewException:
+ case ResultWas::FatalErrorCondition:
+ elementName = "error";
+ break;
+ case ResultWas::ExplicitFailure:
+ case ResultWas::ExpressionFailed:
+ case ResultWas::DidntThrowException:
+ elementName = "failure";
+ break;
+
+ // We should never see these here:
+ case ResultWas::Info:
+ case ResultWas::Warning:
+ case ResultWas::Ok:
+ case ResultWas::Unknown:
+ case ResultWas::FailureBit:
+ case ResultWas::Exception:
+ elementName = "internalError";
+ break;
+ }
+
+ XmlWriter::ScopedElement e = xml.scopedElement( elementName );
+
+ xml.writeAttribute( "message"_sr, result.getExpression() );
+ xml.writeAttribute( "type"_sr, result.getTestMacroName() );
+
+ ReusableStringStream rss;
+ if (stats.totals.assertions.total() > 0) {
+ rss << "FAILED" << ":\n";
+ if (result.hasExpression()) {
+ rss << " ";
+ rss << result.getExpressionInMacro();
+ rss << '\n';
+ }
+ if (result.hasExpandedExpression()) {
+ rss << "with expansion:\n";
+ rss << TextFlow::Column(result.getExpandedExpression()).indent(2) << '\n';
+ }
+ } else {
+ rss << '\n';
+ }
+
+ if( !result.getMessage().empty() )
+ rss << result.getMessage() << '\n';
+ for( auto const& msg : stats.infoMessages )
+ if( msg.type == ResultWas::Info )
+ rss << msg.message << '\n';
+
+ rss << "at " << result.getSourceInfo();
+ xml.writeText( rss.str(), XmlFormatting::Newline );
+ }
+ }
+
+} // end namespace Catch
+
+
+
+
+#include <ostream>
+
+namespace Catch {
+ void MultiReporter::updatePreferences(IEventListener const& reporterish) {
+ m_preferences.shouldRedirectStdOut |=
+ reporterish.getPreferences().shouldRedirectStdOut;
+ m_preferences.shouldReportAllAssertions |=
+ reporterish.getPreferences().shouldReportAllAssertions;
+ }
+
+ void MultiReporter::addListener( IEventListenerPtr&& listener ) {
+ updatePreferences(*listener);
+ m_reporterLikes.insert(m_reporterLikes.begin() + m_insertedListeners, CATCH_MOVE(listener) );
+ ++m_insertedListeners;
+ }
+
+ void MultiReporter::addReporter( IEventListenerPtr&& reporter ) {
+ updatePreferences(*reporter);
+
+ // We will need to output the captured stdout if there are reporters
+ // that do not want it captured.
+ // We do not consider listeners, because it is generally assumed that
+ // listeners are output-transparent, even though they can ask for stdout
+ // capture to do something with it.
+ m_haveNoncapturingReporters |= !reporter->getPreferences().shouldRedirectStdOut;
+
+ // Reporters can always be placed to the back without breaking the
+ // reporting order
+ m_reporterLikes.push_back( CATCH_MOVE( reporter ) );
+ }
+
+ void MultiReporter::noMatchingTestCases( StringRef unmatchedSpec ) {
+ for ( auto& reporterish : m_reporterLikes ) {
+ reporterish->noMatchingTestCases( unmatchedSpec );
+ }
+ }
+
+ void MultiReporter::fatalErrorEncountered( StringRef error ) {
+ for ( auto& reporterish : m_reporterLikes ) {
+ reporterish->fatalErrorEncountered( error );
+ }
+ }
+
+ void MultiReporter::reportInvalidTestSpec( StringRef arg ) {
+ for ( auto& reporterish : m_reporterLikes ) {
+ reporterish->reportInvalidTestSpec( arg );
+ }
+ }
+
+ void MultiReporter::benchmarkPreparing( StringRef name ) {
+ for (auto& reporterish : m_reporterLikes) {
+ reporterish->benchmarkPreparing(name);
+ }
+ }
+ void MultiReporter::benchmarkStarting( BenchmarkInfo const& benchmarkInfo ) {
+ for ( auto& reporterish : m_reporterLikes ) {
+ reporterish->benchmarkStarting( benchmarkInfo );
+ }
+ }
+ void MultiReporter::benchmarkEnded( BenchmarkStats<> const& benchmarkStats ) {
+ for ( auto& reporterish : m_reporterLikes ) {
+ reporterish->benchmarkEnded( benchmarkStats );
+ }
+ }
+
+ void MultiReporter::benchmarkFailed( StringRef error ) {
+ for (auto& reporterish : m_reporterLikes) {
+ reporterish->benchmarkFailed(error);
+ }
+ }
+
+ void MultiReporter::testRunStarting( TestRunInfo const& testRunInfo ) {
+ for ( auto& reporterish : m_reporterLikes ) {
+ reporterish->testRunStarting( testRunInfo );
+ }
+ }
+
+ void MultiReporter::testCaseStarting( TestCaseInfo const& testInfo ) {
+ for ( auto& reporterish : m_reporterLikes ) {
+ reporterish->testCaseStarting( testInfo );
+ }
+ }
+
+ void
+ MultiReporter::testCasePartialStarting( TestCaseInfo const& testInfo,
+ uint64_t partNumber ) {
+ for ( auto& reporterish : m_reporterLikes ) {
+ reporterish->testCasePartialStarting( testInfo, partNumber );
+ }
+ }
+
+ void MultiReporter::sectionStarting( SectionInfo const& sectionInfo ) {
+ for ( auto& reporterish : m_reporterLikes ) {
+ reporterish->sectionStarting( sectionInfo );
+ }
+ }
+
+ void MultiReporter::assertionStarting( AssertionInfo const& assertionInfo ) {
+ for ( auto& reporterish : m_reporterLikes ) {
+ reporterish->assertionStarting( assertionInfo );
+ }
+ }
+
+ // The return value indicates if the messages buffer should be cleared:
+ void MultiReporter::assertionEnded( AssertionStats const& assertionStats ) {
+ const bool reportByDefault =
+ assertionStats.assertionResult.getResultType() != ResultWas::Ok ||
+ m_config->includeSuccessfulResults();
+
+ for ( auto & reporterish : m_reporterLikes ) {
+ if ( reportByDefault ||
+ reporterish->getPreferences().shouldReportAllAssertions ) {
+ reporterish->assertionEnded( assertionStats );
+ }
+ }
+ }
+
+ void MultiReporter::sectionEnded( SectionStats const& sectionStats ) {
+ for ( auto& reporterish : m_reporterLikes ) {
+ reporterish->sectionEnded( sectionStats );
+ }
+ }
+
+ void MultiReporter::testCasePartialEnded( TestCaseStats const& testStats,
+ uint64_t partNumber ) {
+ if ( m_preferences.shouldRedirectStdOut &&
+ m_haveNoncapturingReporters ) {
+ if ( !testStats.stdOut.empty() ) {
+ Catch::cout() << testStats.stdOut << std::flush;
+ }
+ if ( !testStats.stdErr.empty() ) {
+ Catch::cerr() << testStats.stdErr << std::flush;
+ }
+ }
+
+ for ( auto& reporterish : m_reporterLikes ) {
+ reporterish->testCasePartialEnded( testStats, partNumber );
+ }
+ }
+
+ void MultiReporter::testCaseEnded( TestCaseStats const& testCaseStats ) {
+ for ( auto& reporterish : m_reporterLikes ) {
+ reporterish->testCaseEnded( testCaseStats );
+ }
+ }
+
+ void MultiReporter::testRunEnded( TestRunStats const& testRunStats ) {
+ for ( auto& reporterish : m_reporterLikes ) {
+ reporterish->testRunEnded( testRunStats );
+ }
+ }
+
+
+ void MultiReporter::skipTest( TestCaseInfo const& testInfo ) {
+ for ( auto& reporterish : m_reporterLikes ) {
+ reporterish->skipTest( testInfo );
+ }
+ }
+
+ void MultiReporter::listReporters(std::vector<ReporterDescription> const& descriptions) {
+ for (auto& reporterish : m_reporterLikes) {
+ reporterish->listReporters(descriptions);
+ }
+ }
+
+ void MultiReporter::listListeners(
+ std::vector<ListenerDescription> const& descriptions ) {
+ for ( auto& reporterish : m_reporterLikes ) {
+ reporterish->listListeners( descriptions );
+ }
+ }
+
+ void MultiReporter::listTests(std::vector<TestCaseHandle> const& tests) {
+ for (auto& reporterish : m_reporterLikes) {
+ reporterish->listTests(tests);
+ }
+ }
+
+ void MultiReporter::listTags(std::vector<TagInfo> const& tags) {
+ for (auto& reporterish : m_reporterLikes) {
+ reporterish->listTags(tags);
+ }
+ }
+
+} // end namespace Catch
+
+
+
+
+
+namespace Catch {
+ namespace Detail {
+
+ void registerReporterImpl( std::string const& name,
+ IReporterFactoryPtr reporterPtr ) {
+ CATCH_TRY {
+ getMutableRegistryHub().registerReporter(
+ name, CATCH_MOVE( reporterPtr ) );
+ }
+ CATCH_CATCH_ALL {
+ // Do not throw when constructing global objects, instead
+ // register the exception to be processed later
+ getMutableRegistryHub().registerStartupException();
+ }
+ }
+
+ } // namespace Detail
+} // namespace Catch
+
+
+
+
+#include <map>
+
+namespace Catch {
+
+ namespace {
+ std::string createRngSeedString(uint32_t seed) {
+ ReusableStringStream sstr;
+ sstr << "rng-seed=" << seed;
+ return sstr.str();
+ }
+ }
+
+ void SonarQubeReporter::testRunStarting(TestRunInfo const& testRunInfo) {
+ CumulativeReporterBase::testRunStarting(testRunInfo);
+
+ xml.writeComment( createRngSeedString( m_config->rngSeed() ) );
+ xml.startElement("testExecutions");
+ xml.writeAttribute("version"_sr, '1');
+ }
+
+ void SonarQubeReporter::writeRun( TestRunNode const& runNode ) {
+ std::map<std::string, std::vector<TestCaseNode const*>> testsPerFile;
+
+ for ( auto const& child : runNode.children ) {
+ testsPerFile[child->value.testInfo->lineInfo.file].push_back(
+ child.get() );
+ }
+
+ for ( auto const& kv : testsPerFile ) {
+ writeTestFile( kv.first, kv.second );
+ }
+ }
+
+ void SonarQubeReporter::writeTestFile(std::string const& filename, std::vector<TestCaseNode const*> const& testCaseNodes) {
+ XmlWriter::ScopedElement e = xml.scopedElement("file");
+ xml.writeAttribute("path"_sr, filename);
+
+ for (auto const& child : testCaseNodes)
+ writeTestCase(*child);
+ }
+
+ void SonarQubeReporter::writeTestCase(TestCaseNode const& testCaseNode) {
+ // All test cases have exactly one section - which represents the
+ // test case itself. That section may have 0-n nested sections
+ assert(testCaseNode.children.size() == 1);
+ SectionNode const& rootSection = *testCaseNode.children.front();
+ writeSection("", rootSection, testCaseNode.value.testInfo->okToFail());
+ }
+
+ void SonarQubeReporter::writeSection(std::string const& rootName, SectionNode const& sectionNode, bool okToFail) {
+ std::string name = trim(sectionNode.stats.sectionInfo.name);
+ if (!rootName.empty())
+ name = rootName + '/' + name;
+
+ if ( sectionNode.hasAnyAssertions()
+ || !sectionNode.stdOut.empty()
+ || !sectionNode.stdErr.empty() ) {
+ XmlWriter::ScopedElement e = xml.scopedElement("testCase");
+ xml.writeAttribute("name"_sr, name);
+ xml.writeAttribute("duration"_sr, static_cast<long>(sectionNode.stats.durationInSeconds * 1000));
+
+ writeAssertions(sectionNode, okToFail);
+ }
+
+ for (auto const& childNode : sectionNode.childSections)
+ writeSection(name, *childNode, okToFail);
+ }
+
+ void SonarQubeReporter::writeAssertions(SectionNode const& sectionNode, bool okToFail) {
+ for (auto const& assertionOrBenchmark : sectionNode.assertionsAndBenchmarks) {
+ if (assertionOrBenchmark.isAssertion()) {
+ writeAssertion(assertionOrBenchmark.asAssertion(), okToFail);
+ }
+ }
+ }
+
+ void SonarQubeReporter::writeAssertion(AssertionStats const& stats, bool okToFail) {
+ AssertionResult const& result = stats.assertionResult;
+ if (!result.isOk()) {
+ std::string elementName;
+ if (okToFail) {
+ elementName = "skipped";
+ } else {
+ switch (result.getResultType()) {
+ case ResultWas::ThrewException:
+ case ResultWas::FatalErrorCondition:
+ elementName = "error";
+ break;
+ case ResultWas::ExplicitFailure:
+ elementName = "failure";
+ break;
+ case ResultWas::ExpressionFailed:
+ elementName = "failure";
+ break;
+ case ResultWas::DidntThrowException:
+ elementName = "failure";
+ break;
+
+ // We should never see these here:
+ case ResultWas::Info:
+ case ResultWas::Warning:
+ case ResultWas::Ok:
+ case ResultWas::Unknown:
+ case ResultWas::FailureBit:
+ case ResultWas::Exception:
+ elementName = "internalError";
+ break;
+ }
+ }
+
+ XmlWriter::ScopedElement e = xml.scopedElement(elementName);
+
+ ReusableStringStream messageRss;
+ messageRss << result.getTestMacroName() << '(' << result.getExpression() << ')';
+ xml.writeAttribute("message"_sr, messageRss.str());
+
+ ReusableStringStream textRss;
+ if (stats.totals.assertions.total() > 0) {
+ textRss << "FAILED:\n";
+ if (result.hasExpression()) {
+ textRss << '\t' << result.getExpressionInMacro() << '\n';
+ }
+ if (result.hasExpandedExpression()) {
+ textRss << "with expansion:\n\t" << result.getExpandedExpression() << '\n';
+ }
+ }
+
+ if (!result.getMessage().empty())
+ textRss << result.getMessage() << '\n';
+
+ for (auto const& msg : stats.infoMessages)
+ if (msg.type == ResultWas::Info)
+ textRss << msg.message << '\n';
+
+ textRss << "at " << result.getSourceInfo();
+ xml.writeText(textRss.str(), XmlFormatting::Newline);
+ }
+ }
+
+} // end namespace Catch
+
+
+
+namespace Catch {
+
+ StreamingReporterBase::~StreamingReporterBase() = default;
+
+ void
+ StreamingReporterBase::testRunStarting( TestRunInfo const& _testRunInfo ) {
+ currentTestRunInfo = _testRunInfo;
+ }
+
+ void StreamingReporterBase::testRunEnded( TestRunStats const& ) {
+ currentTestCaseInfo = nullptr;
+ }
+
+} // end namespace Catch
+
+
+
+#include <algorithm>
+#include <iterator>
+#include <ostream>
+
+namespace Catch {
+
+ namespace {
+ // Yes, this has to be outside the class and namespaced by naming.
+ // Making older compiler happy is hard.
+ static constexpr StringRef tapFailedString = "not ok"_sr;
+ static constexpr StringRef tapPassedString = "ok"_sr;
+ static constexpr Colour::Code tapDimColour = Colour::FileName;
+
+ class TapAssertionPrinter {
+ public:
+ TapAssertionPrinter& operator= (TapAssertionPrinter const&) = delete;
+ TapAssertionPrinter(TapAssertionPrinter const&) = delete;
+ TapAssertionPrinter(std::ostream& _stream, AssertionStats const& _stats, std::size_t _counter, ColourImpl* colour_)
+ : stream(_stream)
+ , result(_stats.assertionResult)
+ , messages(_stats.infoMessages)
+ , itMessage(_stats.infoMessages.begin())
+ , printInfoMessages(true)
+ , counter(_counter)
+ , colourImpl( colour_ ) {}
+
+ void print() {
+ itMessage = messages.begin();
+
+ switch (result.getResultType()) {
+ case ResultWas::Ok:
+ printResultType(tapPassedString);
+ printOriginalExpression();
+ printReconstructedExpression();
+ if (!result.hasExpression())
+ printRemainingMessages(Colour::None);
+ else
+ printRemainingMessages();
+ break;
+ case ResultWas::ExpressionFailed:
+ if (result.isOk()) {
+ printResultType(tapPassedString);
+ } else {
+ printResultType(tapFailedString);
+ }
+ printOriginalExpression();
+ printReconstructedExpression();
+ if (result.isOk()) {
+ printIssue(" # TODO");
+ }
+ printRemainingMessages();
+ break;
+ case ResultWas::ThrewException:
+ printResultType(tapFailedString);
+ printIssue("unexpected exception with message:"_sr);
+ printMessage();
+ printExpressionWas();
+ printRemainingMessages();
+ break;
+ case ResultWas::FatalErrorCondition:
+ printResultType(tapFailedString);
+ printIssue("fatal error condition with message:"_sr);
+ printMessage();
+ printExpressionWas();
+ printRemainingMessages();
+ break;
+ case ResultWas::DidntThrowException:
+ printResultType(tapFailedString);
+ printIssue("expected exception, got none"_sr);
+ printExpressionWas();
+ printRemainingMessages();
+ break;
+ case ResultWas::Info:
+ printResultType("info"_sr);
+ printMessage();
+ printRemainingMessages();
+ break;
+ case ResultWas::Warning:
+ printResultType("warning"_sr);
+ printMessage();
+ printRemainingMessages();
+ break;
+ case ResultWas::ExplicitFailure:
+ printResultType(tapFailedString);
+ printIssue("explicitly"_sr);
+ printRemainingMessages(Colour::None);
+ break;
+ // These cases are here to prevent compiler warnings
+ case ResultWas::Unknown:
+ case ResultWas::FailureBit:
+ case ResultWas::Exception:
+ printResultType("** internal error **"_sr);
+ break;
+ }
+ }
+
+ private:
+ void printResultType(StringRef passOrFail) const {
+ if (!passOrFail.empty()) {
+ stream << passOrFail << ' ' << counter << " -";
+ }
+ }
+
+ void printIssue(StringRef issue) const {
+ stream << ' ' << issue;
+ }
+
+ void printExpressionWas() {
+ if (result.hasExpression()) {
+ stream << ';';
+ stream << colourImpl->guardColour( tapDimColour )
+ << " expression was:";
+ printOriginalExpression();
+ }
+ }
+
+ void printOriginalExpression() const {
+ if (result.hasExpression()) {
+ stream << ' ' << result.getExpression();
+ }
+ }
+
+ void printReconstructedExpression() const {
+ if (result.hasExpandedExpression()) {
+ stream << colourImpl->guardColour( tapDimColour ) << " for: ";
+
+ std::string expr = result.getExpandedExpression();
+ std::replace(expr.begin(), expr.end(), '\n', ' ');
+ stream << expr;
+ }
+ }
+
+ void printMessage() {
+ if (itMessage != messages.end()) {
+ stream << " '" << itMessage->message << '\'';
+ ++itMessage;
+ }
+ }
+
+ void printRemainingMessages(Colour::Code colour = tapDimColour) {
+ if (itMessage == messages.end()) {
+ return;
+ }
+
+ // using messages.end() directly (or auto) yields compilation error:
+ std::vector<MessageInfo>::const_iterator itEnd = messages.end();
+ const std::size_t N = static_cast<std::size_t>(std::distance(itMessage, itEnd));
+
+ stream << colourImpl->guardColour( colour ) << " with "
+ << pluralise( N, "message"_sr ) << ':';
+
+ for (; itMessage != itEnd; ) {
+ // If this assertion is a warning ignore any INFO messages
+ if (printInfoMessages || itMessage->type != ResultWas::Info) {
+ stream << " '" << itMessage->message << '\'';
+ if (++itMessage != itEnd) {
+ stream << colourImpl->guardColour(tapDimColour) << " and";
+ }
+ }
+ }
+ }
+
+ private:
+ std::ostream& stream;
+ AssertionResult const& result;
+ std::vector<MessageInfo> messages;
+ std::vector<MessageInfo>::const_iterator itMessage;
+ bool printInfoMessages;
+ std::size_t counter;
+ ColourImpl* colourImpl;
+ };
+
+ } // End anonymous namespace
+
+ void TAPReporter::testRunStarting( TestRunInfo const& ) {
+ m_stream << "# rng-seed: " << m_config->rngSeed() << '\n';
+ }
+
+ void TAPReporter::noMatchingTestCases( StringRef unmatchedSpec ) {
+ m_stream << "# No test cases matched '" << unmatchedSpec << "'\n";
+ }
+
+ void TAPReporter::assertionEnded(AssertionStats const& _assertionStats) {
+ ++counter;
+
+ m_stream << "# " << currentTestCaseInfo->name << '\n';
+ TapAssertionPrinter printer(m_stream, _assertionStats, counter, m_colour.get());
+ printer.print();
+
+ m_stream << '\n' << std::flush;
+ }
+
+ void TAPReporter::testRunEnded(TestRunStats const& _testRunStats) {
+ m_stream << "1.." << _testRunStats.totals.assertions.total();
+ if (_testRunStats.totals.testCases.total() == 0) {
+ m_stream << " # Skipped: No tests ran.";
+ }
+ m_stream << "\n\n" << std::flush;
+ StreamingReporterBase::testRunEnded(_testRunStats);
+ }
+
+
+
+
+} // end namespace Catch
+
+
+
+
+#include <cassert>
+#include <ostream>
+
+namespace Catch {
+
+ namespace {
+ // if string has a : in first line will set indent to follow it on
+ // subsequent lines
+ void printHeaderString(std::ostream& os, std::string const& _string, std::size_t indent = 0) {
+ std::size_t i = _string.find(": ");
+ if (i != std::string::npos)
+ i += 2;
+ else
+ i = 0;
+ os << TextFlow::Column(_string)
+ .indent(indent + i)
+ .initialIndent(indent) << '\n';
+ }
+
+ std::string escape(StringRef str) {
+ std::string escaped = static_cast<std::string>(str);
+ replaceInPlace(escaped, "|", "||");
+ replaceInPlace(escaped, "'", "|'");
+ replaceInPlace(escaped, "\n", "|n");
+ replaceInPlace(escaped, "\r", "|r");
+ replaceInPlace(escaped, "[", "|[");
+ replaceInPlace(escaped, "]", "|]");
+ return escaped;
+ }
+ } // end anonymous namespace
+
+
+ TeamCityReporter::~TeamCityReporter() {}
+
+ void TeamCityReporter::testRunStarting( TestRunInfo const& runInfo ) {
+ m_stream << "##teamcity[testSuiteStarted name='" << escape( runInfo.name )
+ << "']\n";
+ }
+
+ void TeamCityReporter::testRunEnded( TestRunStats const& runStats ) {
+ m_stream << "##teamcity[testSuiteFinished name='"
+ << escape( runStats.runInfo.name ) << "']\n";
+ }
+
+ void TeamCityReporter::assertionEnded(AssertionStats const& assertionStats) {
+ AssertionResult const& result = assertionStats.assertionResult;
+ if (!result.isOk()) {
+
+ ReusableStringStream msg;
+ if (!m_headerPrintedForThisSection)
+ printSectionHeader(msg.get());
+ m_headerPrintedForThisSection = true;
+
+ msg << result.getSourceInfo() << '\n';
+
+ switch (result.getResultType()) {
+ case ResultWas::ExpressionFailed:
+ msg << "expression failed";
+ break;
+ case ResultWas::ThrewException:
+ msg << "unexpected exception";
+ break;
+ case ResultWas::FatalErrorCondition:
+ msg << "fatal error condition";
+ break;
+ case ResultWas::DidntThrowException:
+ msg << "no exception was thrown where one was expected";
+ break;
+ case ResultWas::ExplicitFailure:
+ msg << "explicit failure";
+ break;
+
+ // We shouldn't get here because of the isOk() test
+ case ResultWas::Ok:
+ case ResultWas::Info:
+ case ResultWas::Warning:
+ CATCH_ERROR("Internal error in TeamCity reporter");
+ // These cases are here to prevent compiler warnings
+ case ResultWas::Unknown:
+ case ResultWas::FailureBit:
+ case ResultWas::Exception:
+ CATCH_ERROR("Not implemented");
+ }
+ if (assertionStats.infoMessages.size() == 1)
+ msg << " with message:";
+ if (assertionStats.infoMessages.size() > 1)
+ msg << " with messages:";
+ for (auto const& messageInfo : assertionStats.infoMessages)
+ msg << "\n \"" << messageInfo.message << '"';
+
+
+ if (result.hasExpression()) {
+ msg <<
+ "\n " << result.getExpressionInMacro() << "\n"
+ "with expansion:\n"
+ " " << result.getExpandedExpression() << '\n';
+ }
+
+ if (currentTestCaseInfo->okToFail()) {
+ msg << "- failure ignore as test marked as 'ok to fail'\n";
+ m_stream << "##teamcity[testIgnored"
+ << " name='" << escape(currentTestCaseInfo->name) << '\''
+ << " message='" << escape(msg.str()) << '\''
+ << "]\n";
+ } else {
+ m_stream << "##teamcity[testFailed"
+ << " name='" << escape(currentTestCaseInfo->name) << '\''
+ << " message='" << escape(msg.str()) << '\''
+ << "]\n";
+ }
+ }
+ m_stream.flush();
+ }
+
+ void TeamCityReporter::testCaseStarting(TestCaseInfo const& testInfo) {
+ m_testTimer.start();
+ StreamingReporterBase::testCaseStarting(testInfo);
+ m_stream << "##teamcity[testStarted name='"
+ << escape(testInfo.name) << "']\n";
+ m_stream.flush();
+ }
+
+ void TeamCityReporter::testCaseEnded(TestCaseStats const& testCaseStats) {
+ StreamingReporterBase::testCaseEnded(testCaseStats);
+ auto const& testCaseInfo = *testCaseStats.testInfo;
+ if (!testCaseStats.stdOut.empty())
+ m_stream << "##teamcity[testStdOut name='"
+ << escape(testCaseInfo.name)
+ << "' out='" << escape(testCaseStats.stdOut) << "']\n";
+ if (!testCaseStats.stdErr.empty())
+ m_stream << "##teamcity[testStdErr name='"
+ << escape(testCaseInfo.name)
+ << "' out='" << escape(testCaseStats.stdErr) << "']\n";
+ m_stream << "##teamcity[testFinished name='"
+ << escape(testCaseInfo.name) << "' duration='"
+ << m_testTimer.getElapsedMilliseconds() << "']\n";
+ m_stream.flush();
+ }
+
+ void TeamCityReporter::printSectionHeader(std::ostream& os) {
+ assert(!m_sectionStack.empty());
+
+ if (m_sectionStack.size() > 1) {
+ os << lineOfChars('-') << '\n';
+
+ std::vector<SectionInfo>::const_iterator
+ it = m_sectionStack.begin() + 1, // Skip first section (test case)
+ itEnd = m_sectionStack.end();
+ for (; it != itEnd; ++it)
+ printHeaderString(os, it->name);
+ os << lineOfChars('-') << '\n';
+ }
+
+ SourceLineInfo lineInfo = m_sectionStack.front().lineInfo;
+
+ os << lineInfo << '\n';
+ os << lineOfChars('.') << "\n\n";
+ }
+
+} // end namespace Catch
+
+
+
+
+#if defined(_MSC_VER)
+#pragma warning(push)
+#pragma warning(disable:4061) // Not all labels are EXPLICITLY handled in switch
+ // Note that 4062 (not all labels are handled
+ // and default is missing) is enabled
+#endif
+
+namespace Catch {
+ XmlReporter::XmlReporter( ReporterConfig&& _config )
+ : StreamingReporterBase( CATCH_MOVE(_config) ),
+ m_xml(m_stream)
+ {
+ m_preferences.shouldRedirectStdOut = true;
+ m_preferences.shouldReportAllAssertions = true;
+ }
+
+ XmlReporter::~XmlReporter() = default;
+
+ std::string XmlReporter::getDescription() {
+ return "Reports test results as an XML document";
+ }
+
+ std::string XmlReporter::getStylesheetRef() const {
+ return std::string();
+ }
+
+ void XmlReporter::writeSourceInfo( SourceLineInfo const& sourceInfo ) {
+ m_xml
+ .writeAttribute( "filename"_sr, sourceInfo.file )
+ .writeAttribute( "line"_sr, sourceInfo.line );
+ }
+
+ void XmlReporter::testRunStarting( TestRunInfo const& testInfo ) {
+ StreamingReporterBase::testRunStarting( testInfo );
+ std::string stylesheetRef = getStylesheetRef();
+ if( !stylesheetRef.empty() )
+ m_xml.writeStylesheetRef( stylesheetRef );
+ m_xml.startElement("Catch2TestRun")
+ .writeAttribute("name"_sr, m_config->name())
+ .writeAttribute("rng-seed"_sr, m_config->rngSeed())
+ .writeAttribute("catch2-version"_sr, libraryVersion());
+ if (m_config->testSpec().hasFilters())
+ m_xml.writeAttribute( "filters"_sr, serializeFilters( m_config->getTestsOrTags() ) );
+ }
+
+ void XmlReporter::testCaseStarting( TestCaseInfo const& testInfo ) {
+ StreamingReporterBase::testCaseStarting(testInfo);
+ m_xml.startElement( "TestCase" )
+ .writeAttribute( "name"_sr, trim( testInfo.name ) )
+ .writeAttribute( "tags"_sr, testInfo.tagsAsString() );
+
+ writeSourceInfo( testInfo.lineInfo );
+
+ if ( m_config->showDurations() == ShowDurations::Always )
+ m_testCaseTimer.start();
+ m_xml.ensureTagClosed();
+ }
+
+ void XmlReporter::sectionStarting( SectionInfo const& sectionInfo ) {
+ StreamingReporterBase::sectionStarting( sectionInfo );
+ if( m_sectionDepth++ > 0 ) {
+ m_xml.startElement( "Section" )
+ .writeAttribute( "name"_sr, trim( sectionInfo.name ) );
+ writeSourceInfo( sectionInfo.lineInfo );
+ m_xml.ensureTagClosed();
+ }
+ }
+
+ void XmlReporter::assertionStarting( AssertionInfo const& ) { }
+
+ void XmlReporter::assertionEnded( AssertionStats const& assertionStats ) {
+
+ AssertionResult const& result = assertionStats.assertionResult;
+
+ bool includeResults = m_config->includeSuccessfulResults() || !result.isOk();
+
+ if( includeResults || result.getResultType() == ResultWas::Warning ) {
+ // Print any info messages in <Info> tags.
+ for( auto const& msg : assertionStats.infoMessages ) {
+ if( msg.type == ResultWas::Info && includeResults ) {
+ m_xml.scopedElement( "Info" )
+ .writeText( msg.message );
+ } else if ( msg.type == ResultWas::Warning ) {
+ m_xml.scopedElement( "Warning" )
+ .writeText( msg.message );
+ }
+ }
+ }
+
+ // Drop out if result was successful but we're not printing them.
+ if( !includeResults && result.getResultType() != ResultWas::Warning )
+ return;
+
+
+ // Print the expression if there is one.
+ if( result.hasExpression() ) {
+ m_xml.startElement( "Expression" )
+ .writeAttribute( "success"_sr, result.succeeded() )
+ .writeAttribute( "type"_sr, result.getTestMacroName() );
+
+ writeSourceInfo( result.getSourceInfo() );
+
+ m_xml.scopedElement( "Original" )
+ .writeText( result.getExpression() );
+ m_xml.scopedElement( "Expanded" )
+ .writeText( result.getExpandedExpression() );
+ }
+
+ // And... Print a result applicable to each result type.
+ switch( result.getResultType() ) {
+ case ResultWas::ThrewException:
+ m_xml.startElement( "Exception" );
+ writeSourceInfo( result.getSourceInfo() );
+ m_xml.writeText( result.getMessage() );
+ m_xml.endElement();
+ break;
+ case ResultWas::FatalErrorCondition:
+ m_xml.startElement( "FatalErrorCondition" );
+ writeSourceInfo( result.getSourceInfo() );
+ m_xml.writeText( result.getMessage() );
+ m_xml.endElement();
+ break;
+ case ResultWas::Info:
+ m_xml.scopedElement( "Info" )
+ .writeText( result.getMessage() );
+ break;
+ case ResultWas::Warning:
+ // Warning will already have been written
+ break;
+ case ResultWas::ExplicitFailure:
+ m_xml.startElement( "Failure" );
+ writeSourceInfo( result.getSourceInfo() );
+ m_xml.writeText( result.getMessage() );
+ m_xml.endElement();
+ break;
+ default:
+ break;
+ }
+
+ if( result.hasExpression() )
+ m_xml.endElement();
+ }
+
+ void XmlReporter::sectionEnded( SectionStats const& sectionStats ) {
+ StreamingReporterBase::sectionEnded( sectionStats );
+ if( --m_sectionDepth > 0 ) {
+ XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResults" );
+ e.writeAttribute( "successes"_sr, sectionStats.assertions.passed );
+ e.writeAttribute( "failures"_sr, sectionStats.assertions.failed );
+ e.writeAttribute( "expectedFailures"_sr, sectionStats.assertions.failedButOk );
+
+ if ( m_config->showDurations() == ShowDurations::Always )
+ e.writeAttribute( "durationInSeconds"_sr, sectionStats.durationInSeconds );
+
+ m_xml.endElement();
+ }
+ }
+
+ void XmlReporter::testCaseEnded( TestCaseStats const& testCaseStats ) {
+ StreamingReporterBase::testCaseEnded( testCaseStats );
+ XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResult" );
+ e.writeAttribute( "success"_sr, testCaseStats.totals.assertions.allOk() );
+
+ if ( m_config->showDurations() == ShowDurations::Always )
+ e.writeAttribute( "durationInSeconds"_sr, m_testCaseTimer.getElapsedSeconds() );
+
+ if( !testCaseStats.stdOut.empty() )
+ m_xml.scopedElement( "StdOut" ).writeText( trim( testCaseStats.stdOut ), XmlFormatting::Newline );
+ if( !testCaseStats.stdErr.empty() )
+ m_xml.scopedElement( "StdErr" ).writeText( trim( testCaseStats.stdErr ), XmlFormatting::Newline );
+
+ m_xml.endElement();
+ }
+
+ void XmlReporter::testRunEnded( TestRunStats const& testRunStats ) {
+ StreamingReporterBase::testRunEnded( testRunStats );
+ m_xml.scopedElement( "OverallResults" )
+ .writeAttribute( "successes"_sr, testRunStats.totals.assertions.passed )
+ .writeAttribute( "failures"_sr, testRunStats.totals.assertions.failed )
+ .writeAttribute( "expectedFailures"_sr, testRunStats.totals.assertions.failedButOk );
+ m_xml.scopedElement( "OverallResultsCases")
+ .writeAttribute( "successes"_sr, testRunStats.totals.testCases.passed )
+ .writeAttribute( "failures"_sr, testRunStats.totals.testCases.failed )
+ .writeAttribute( "expectedFailures"_sr, testRunStats.totals.testCases.failedButOk );
+ m_xml.endElement();
+ }
+
+ void XmlReporter::benchmarkPreparing( StringRef name ) {
+ m_xml.startElement("BenchmarkResults")
+ .writeAttribute("name"_sr, name);
+ }
+
+ void XmlReporter::benchmarkStarting(BenchmarkInfo const &info) {
+ m_xml.writeAttribute("samples"_sr, info.samples)
+ .writeAttribute("resamples"_sr, info.resamples)
+ .writeAttribute("iterations"_sr, info.iterations)
+ .writeAttribute("clockResolution"_sr, info.clockResolution)
+ .writeAttribute("estimatedDuration"_sr, info.estimatedDuration)
+ .writeComment("All values in nano seconds"_sr);
+ }
+
+ void XmlReporter::benchmarkEnded(BenchmarkStats<> const& benchmarkStats) {
+ m_xml.startElement("mean")
+ .writeAttribute("value"_sr, benchmarkStats.mean.point.count())
+ .writeAttribute("lowerBound"_sr, benchmarkStats.mean.lower_bound.count())
+ .writeAttribute("upperBound"_sr, benchmarkStats.mean.upper_bound.count())
+ .writeAttribute("ci"_sr, benchmarkStats.mean.confidence_interval);
+ m_xml.endElement();
+ m_xml.startElement("standardDeviation")
+ .writeAttribute("value"_sr, benchmarkStats.standardDeviation.point.count())
+ .writeAttribute("lowerBound"_sr, benchmarkStats.standardDeviation.lower_bound.count())
+ .writeAttribute("upperBound"_sr, benchmarkStats.standardDeviation.upper_bound.count())
+ .writeAttribute("ci"_sr, benchmarkStats.standardDeviation.confidence_interval);
+ m_xml.endElement();
+ m_xml.startElement("outliers")
+ .writeAttribute("variance"_sr, benchmarkStats.outlierVariance)
+ .writeAttribute("lowMild"_sr, benchmarkStats.outliers.low_mild)
+ .writeAttribute("lowSevere"_sr, benchmarkStats.outliers.low_severe)
+ .writeAttribute("highMild"_sr, benchmarkStats.outliers.high_mild)
+ .writeAttribute("highSevere"_sr, benchmarkStats.outliers.high_severe);
+ m_xml.endElement();
+ m_xml.endElement();
+ }
+
+ void XmlReporter::benchmarkFailed(StringRef error) {
+ m_xml.scopedElement("failed").
+ writeAttribute("message"_sr, error);
+ m_xml.endElement();
+ }
+
+ void XmlReporter::listReporters(std::vector<ReporterDescription> const& descriptions) {
+ auto outerTag = m_xml.scopedElement("AvailableReporters");
+ for (auto const& reporter : descriptions) {
+ auto inner = m_xml.scopedElement("Reporter");
+ m_xml.startElement("Name", XmlFormatting::Indent)
+ .writeText(reporter.name, XmlFormatting::None)
+ .endElement(XmlFormatting::Newline);
+ m_xml.startElement("Description", XmlFormatting::Indent)
+ .writeText(reporter.description, XmlFormatting::None)
+ .endElement(XmlFormatting::Newline);
+ }
+ }
+
+ void XmlReporter::listListeners(std::vector<ListenerDescription> const& descriptions) {
+ auto outerTag = m_xml.scopedElement( "RegisteredListeners" );
+ for ( auto const& listener : descriptions ) {
+ auto inner = m_xml.scopedElement( "Listener" );
+ m_xml.startElement( "Name", XmlFormatting::Indent )
+ .writeText( listener.name, XmlFormatting::None )
+ .endElement( XmlFormatting::Newline );
+ m_xml.startElement( "Description", XmlFormatting::Indent )
+ .writeText( listener.description, XmlFormatting::None )
+ .endElement( XmlFormatting::Newline );
+ }
+ }
+
+ void XmlReporter::listTests(std::vector<TestCaseHandle> const& tests) {
+ auto outerTag = m_xml.scopedElement("MatchingTests");
+ for (auto const& test : tests) {
+ auto innerTag = m_xml.scopedElement("TestCase");
+ auto const& testInfo = test.getTestCaseInfo();
+ m_xml.startElement("Name", XmlFormatting::Indent)
+ .writeText(testInfo.name, XmlFormatting::None)
+ .endElement(XmlFormatting::Newline);
+ m_xml.startElement("ClassName", XmlFormatting::Indent)
+ .writeText(testInfo.className, XmlFormatting::None)
+ .endElement(XmlFormatting::Newline);
+ m_xml.startElement("Tags", XmlFormatting::Indent)
+ .writeText(testInfo.tagsAsString(), XmlFormatting::None)
+ .endElement(XmlFormatting::Newline);
+
+ auto sourceTag = m_xml.scopedElement("SourceInfo");
+ m_xml.startElement("File", XmlFormatting::Indent)
+ .writeText(testInfo.lineInfo.file, XmlFormatting::None)
+ .endElement(XmlFormatting::Newline);
+ m_xml.startElement("Line", XmlFormatting::Indent)
+ .writeText(std::to_string(testInfo.lineInfo.line), XmlFormatting::None)
+ .endElement(XmlFormatting::Newline);
+ }
+ }
+
+ void XmlReporter::listTags(std::vector<TagInfo> const& tags) {
+ auto outerTag = m_xml.scopedElement("TagsFromMatchingTests");
+ for (auto const& tag : tags) {
+ auto innerTag = m_xml.scopedElement("Tag");
+ m_xml.startElement("Count", XmlFormatting::Indent)
+ .writeText(std::to_string(tag.count), XmlFormatting::None)
+ .endElement(XmlFormatting::Newline);
+ auto aliasTag = m_xml.scopedElement("Aliases");
+ for (auto const& alias : tag.spellings) {
+ m_xml.startElement("Alias", XmlFormatting::Indent)
+ .writeText(alias, XmlFormatting::None)
+ .endElement(XmlFormatting::Newline);
+ }
+ }
+ }
+
+} // end namespace Catch
+
+#if defined(_MSC_VER)
+#pragma warning(pop)
+#endif
diff --git a/3rdparty/bx/3rdparty/catch/catch_amalgamated.hpp b/3rdparty/bx/3rdparty/catch/catch_amalgamated.hpp
new file mode 100644
index 00000000000..757e10c5ac5
--- /dev/null
+++ b/3rdparty/bx/3rdparty/catch/catch_amalgamated.hpp
@@ -0,0 +1,12233 @@
+// Copyright Catch2 Authors
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at
+// https://www.boost.org/LICENSE_1_0.txt)
+
+// SPDX-License-Identifier: BSL-1.0
+
+// Catch v3.1.0
+// Generated: 2022-07-17 20:14:04.055157
+// ----------------------------------------------------------
+// This file is an amalgamation of multiple different files.
+// You probably shouldn't edit it directly.
+// ----------------------------------------------------------
+#ifndef CATCH_AMALGAMATED_HPP_INCLUDED
+#define CATCH_AMALGAMATED_HPP_INCLUDED
+
+
+/** \file
+ * This is a convenience header for Catch2. It includes **all** of Catch2 headers.
+ *
+ * Generally the Catch2 users should use specific includes they need,
+ * but this header can be used instead for ease-of-experimentation, or
+ * just plain convenience, at the cost of (significantly) increased
+ * compilation times.
+ *
+ * When a new header is added to either the top level folder, or to the
+ * corresponding internal subfolder, it should be added here. Headers
+ * added to the various subparts (e.g. matchers, generators, etc...),
+ * should go their respective catch-all headers.
+ */
+
+#ifndef CATCH_ALL_HPP_INCLUDED
+#define CATCH_ALL_HPP_INCLUDED
+
+
+
+/** \file
+ * This is a convenience header for Catch2's benchmarking. It includes
+ * **all** of Catch2 headers related to benchmarking.
+ *
+ * Generally the Catch2 users should use specific includes they need,
+ * but this header can be used instead for ease-of-experimentation, or
+ * just plain convenience, at the cost of (significantly) increased
+ * compilation times.
+ *
+ * When a new header is added to either the `benchmark` folder, or to
+ * the corresponding internal (detail) subfolder, it should be added here.
+ */
+
+#ifndef CATCH_BENCHMARK_ALL_HPP_INCLUDED
+#define CATCH_BENCHMARK_ALL_HPP_INCLUDED
+
+
+
+// Adapted from donated nonius code.
+
+#ifndef CATCH_BENCHMARK_HPP_INCLUDED
+#define CATCH_BENCHMARK_HPP_INCLUDED
+
+
+
+#ifndef CATCH_INTERFACES_CONFIG_HPP_INCLUDED
+#define CATCH_INTERFACES_CONFIG_HPP_INCLUDED
+
+
+
+#ifndef CATCH_NONCOPYABLE_HPP_INCLUDED
+#define CATCH_NONCOPYABLE_HPP_INCLUDED
+
+namespace Catch {
+ namespace Detail {
+
+ //! Deriving classes become noncopyable and nonmovable
+ class NonCopyable {
+ NonCopyable( NonCopyable const& ) = delete;
+ NonCopyable( NonCopyable&& ) = delete;
+ NonCopyable& operator=( NonCopyable const& ) = delete;
+ NonCopyable& operator=( NonCopyable&& ) = delete;
+
+ protected:
+ NonCopyable() noexcept = default;
+ };
+
+ } // namespace Detail
+} // namespace Catch
+
+#endif // CATCH_NONCOPYABLE_HPP_INCLUDED
+
+
+#ifndef CATCH_STRINGREF_HPP_INCLUDED
+#define CATCH_STRINGREF_HPP_INCLUDED
+
+#include <cstddef>
+#include <string>
+#include <iosfwd>
+#include <cassert>
+
+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 {
+ public:
+ using size_type = std::size_t;
+ using const_iterator = const char*;
+
+ private:
+ static constexpr char const* const s_empty = "";
+
+ char const* m_start = s_empty;
+ size_type m_size = 0;
+
+ public: // construction
+ constexpr StringRef() noexcept = default;
+
+ StringRef( char const* rawChars ) noexcept;
+
+ constexpr StringRef( char const* rawChars, size_type size ) noexcept
+ : m_start( rawChars ),
+ m_size( size )
+ {}
+
+ StringRef( std::string const& stdString ) noexcept
+ : m_start( stdString.c_str() ),
+ m_size( stdString.size() )
+ {}
+
+ explicit operator std::string() const {
+ return std::string(m_start, m_size);
+ }
+
+ public: // operators
+ auto operator == ( StringRef other ) const noexcept -> bool;
+ auto operator != (StringRef other) const noexcept -> bool {
+ return !(*this == other);
+ }
+
+ constexpr auto operator[] ( size_type index ) const noexcept -> char {
+ assert(index < m_size);
+ return m_start[index];
+ }
+
+ bool operator<(StringRef rhs) const noexcept;
+
+ public: // named queries
+ constexpr auto empty() const noexcept -> bool {
+ return m_size == 0;
+ }
+ constexpr auto size() const noexcept -> size_type {
+ return m_size;
+ }
+
+ // Returns a substring of [start, start + length).
+ // If start + length > size(), then the substring is [start, start + size()).
+ // If start > size(), then the substring is empty.
+ constexpr StringRef substr(size_type start, size_type length) const noexcept {
+ if (start < m_size) {
+ const auto shortened_size = m_size - start;
+ return StringRef(m_start + start, (shortened_size < length) ? shortened_size : length);
+ } else {
+ return StringRef();
+ }
+ }
+
+ // Returns the current start pointer. May not be null-terminated.
+ constexpr char const* data() const noexcept {
+ return m_start;
+ }
+
+ 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);
+
+ /**
+ * Provides a three-way comparison with rhs
+ *
+ * Returns negative number if lhs < rhs, 0 if lhs == rhs, and a positive
+ * number if lhs > rhs
+ */
+ int compare( StringRef rhs ) const;
+ };
+
+
+ constexpr auto operator ""_sr( char const* rawChars, std::size_t size ) noexcept -> StringRef {
+ return StringRef( rawChars, size );
+ }
+} // namespace Catch
+
+constexpr auto operator ""_catch_sr( char const* rawChars, std::size_t size ) noexcept -> Catch::StringRef {
+ return Catch::StringRef( rawChars, size );
+}
+
+#endif // CATCH_STRINGREF_HPP_INCLUDED
+
+#include <chrono>
+#include <iosfwd>
+#include <string>
+#include <vector>
+
+namespace Catch {
+
+ enum class Verbosity {
+ Quiet = 0,
+ Normal,
+ High
+ };
+
+ 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,
+ }; };
+
+ 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;
+
+ class IConfig : public Detail::NonCopyable {
+ 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<std::string> 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<std::string> const& getSectionsToRun() const = 0;
+ virtual Verbosity verbosity() const = 0;
+
+ 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;
+ };
+}
+
+#endif // CATCH_INTERFACES_CONFIG_HPP_INCLUDED
+
+
+#ifndef CATCH_COMPILER_CAPABILITIES_HPP_INCLUDED
+#define CATCH_COMPILER_CAPABILITIES_HPP_INCLUDED
+
+// 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
+// ****************
+
+// In general each macro has a _NO_<feature name> 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.
+
+
+
+#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 <TargetConditionals.h>
+# if (defined(TARGET_OS_OSX) && TARGET_OS_OSX == 1) || \
+ (defined(TARGET_OS_MAC) && TARGET_OS_MAC == 1)
+# define CATCH_PLATFORM_MAC
+# elif (defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE == 1)
+# define CATCH_PLATFORM_IPHONE
+# endif
+
+#elif defined(linux) || defined(__linux) || defined(__linux__)
+# define CATCH_PLATFORM_LINUX
+
+#elif defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER) || defined(__MINGW32__)
+# define CATCH_PLATFORM_WINDOWS
+#endif
+
+#endif // CATCH_PLATFORM_HPP_INCLUDED
+
+#ifdef __cplusplus
+
+# 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
+
+#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\"" )
+
+# define CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \
+ _Pragma( "GCC diagnostic ignored \"-Wunused-variable\"" )
+
+# define CATCH_INTERNAL_IGNORE_BUT_WARN(...) (void)__builtin_constant_p(__VA_ARGS__)
+
+#endif
+
+#if defined(__CUDACC__) && !defined(__clang__)
+# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION _Pragma( "nv_diagnostic push" )
+# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION _Pragma( "nv_diagnostic pop" )
+# define CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS _Pragma( "nv_diag_suppress 177" )
+#endif
+
+// clang-cl defines _MSC_VER as well as __clang__, which could cause the
+// start/stop internal suppression macros to be double defined.
+#if defined(__clang__) && !defined(_MSC_VER)
+
+# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION _Pragma( "clang diagnostic push" )
+# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION _Pragma( "clang diagnostic pop" )
+
+#endif // __clang__ && !_MSC_VER
+
+#if defined(__clang__)
+
+// 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
+
+
+# define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
+ _Pragma( "clang diagnostic ignored \"-Wexit-time-destructors\"" ) \
+ _Pragma( "clang diagnostic ignored \"-Wglobal-constructors\"")
+
+# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \
+ _Pragma( "clang diagnostic ignored \"-Wparentheses\"" )
+
+# define CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \
+ _Pragma( "clang diagnostic ignored \"-Wunused-variable\"" )
+
+# define CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS \
+ _Pragma( "clang diagnostic ignored \"-Wgnu-zero-variadic-macro-arguments\"" )
+
+# define CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \
+ _Pragma( "clang diagnostic ignored \"-Wunused-template\"" )
+
+#endif // __clang__
+
+
+////////////////////////////////////////////////////////////////////////////////
+// Assume that non-Windows platforms support posix signals by default
+#if !defined(CATCH_PLATFORM_WINDOWS)
+ #define CATCH_INTERNAL_CONFIG_POSIX_SIGNALS
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+// 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
+
+////////////////////////////////////////////////////////////////////////////////
+// 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
+
+////////////////////////////////////////////////////////////////////////////////
+// PS4
+#if defined(__ORBIS__)
+# define CATCH_INTERNAL_CONFIG_NO_NEW_CAPTURE
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+// Cygwin
+#ifdef __CYGWIN__
+
+// 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))
+
+# define CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING
+
+# endif
+#endif // __CYGWIN__
+
+////////////////////////////////////////////////////////////////////////////////
+// Visual C++
+#if defined(_MSC_VER)
+
+# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION __pragma( warning(push) )
+# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION __pragma( warning(pop) )
+
+// 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__
+
+#endif // _MSC_VER
+
+#if defined(_REENTRANT) || defined(_MSC_VER)
+// Enable async processing, as -pthread is specified or no additional linking is required
+# define CATCH_INTERNAL_CONFIG_USE_ASYNC
+#endif // _MSC_VER
+
+////////////////////////////////////////////////////////////////////////////////
+// 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
+
+
+////////////////////////////////////////////////////////////////////////////////
+// Embarcadero C++Build
+#if defined(__BORLANDC__)
+ #define CATCH_INTERNAL_CONFIG_POLYFILL_ISNAN
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+
+// 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
+
+#if !defined(_GLIBCXX_USE_C99_MATH_TR1)
+#define CATCH_INTERNAL_CONFIG_GLOBAL_NEXTAFTER
+#endif
+
+// Various stdlib support checks that require __has_include
+#if defined(__has_include)
+ // Check if string_view is available and usable
+ #if __has_include(<string_view>) && defined(CATCH_CPP17_OR_GREATER)
+ # define CATCH_INTERNAL_CONFIG_CPP17_STRING_VIEW
+ #endif
+
+ // Check if optional is available and usable
+ # if __has_include(<optional>) && defined(CATCH_CPP17_OR_GREATER)
+ # define CATCH_INTERNAL_CONFIG_CPP17_OPTIONAL
+ # endif // __has_include(<optional>) && defined(CATCH_CPP17_OR_GREATER)
+
+ // Check if byte is available and usable
+ # if __has_include(<cstddef>) && defined(CATCH_CPP17_OR_GREATER)
+ # include <cstddef>
+ # if defined(__cpp_lib_byte) && (__cpp_lib_byte > 0)
+ # define CATCH_INTERNAL_CONFIG_CPP17_BYTE
+ # endif
+ # endif // __has_include(<cstddef>) && defined(CATCH_CPP17_OR_GREATER)
+
+ // Check if variant is available and usable
+ # if __has_include(<variant>) && defined(CATCH_CPP17_OR_GREATER)
+ # if defined(__clang__) && (__clang_major__ < 8)
+ // work around clang bug with libstdc++ https://bugs.llvm.org/show_bug.cgi?id=31852
+ // fix should be in clang 8, workaround in libstdc++ 8.2
+ # include <ciso646>
+ # if defined(__GLIBCXX__) && defined(_GLIBCXX_RELEASE) && (_GLIBCXX_RELEASE < 9)
+ # define CATCH_CONFIG_NO_CPP17_VARIANT
+ # else
+ # define CATCH_INTERNAL_CONFIG_CPP17_VARIANT
+ # endif // defined(__GLIBCXX__) && defined(_GLIBCXX_RELEASE) && (_GLIBCXX_RELEASE < 9)
+ # else
+ # define CATCH_INTERNAL_CONFIG_CPP17_VARIANT
+ # endif // defined(__clang__) && (__clang_major__ < 8)
+ # endif // __has_include(<variant>) && defined(CATCH_CPP17_OR_GREATER)
+#endif // defined(__has_include)
+
+
+#if defined(CATCH_INTERNAL_CONFIG_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
+
+#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
+
+#if defined(CATCH_INTERNAL_CONFIG_CPP17_OPTIONAL) && !defined(CATCH_CONFIG_NO_CPP17_OPTIONAL) && !defined(CATCH_CONFIG_CPP17_OPTIONAL)
+# define CATCH_CONFIG_CPP17_OPTIONAL
+#endif
+
+#if defined(CATCH_INTERNAL_CONFIG_CPP17_STRING_VIEW) && !defined(CATCH_CONFIG_NO_CPP17_STRING_VIEW) && !defined(CATCH_CONFIG_CPP17_STRING_VIEW)
+# 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
+
+#if defined(CATCH_INTERNAL_CONFIG_CPP17_BYTE) && !defined(CATCH_CONFIG_NO_CPP17_BYTE) && !defined(CATCH_CONFIG_CPP17_BYTE)
+# define CATCH_CONFIG_CPP17_BYTE
+#endif
+
+
+#if defined(CATCH_CONFIG_EXPERIMENTAL_REDIRECT)
+# define CATCH_INTERNAL_CONFIG_NEW_CAPTURE
+#endif
+
+#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
+
+#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
+
+#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
+
+
+// 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
+
+// The goal of this macro is to avoid evaluation of the arguments, but
+// still have the compiler warn on problems inside...
+#if !defined(CATCH_INTERNAL_IGNORE_BUT_WARN)
+# define CATCH_INTERNAL_IGNORE_BUT_WARN(...)
+#endif
+
+#if defined(__APPLE__) && defined(__apple_build_version__) && (__clang_major__ < 10)
+# undef CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS
+#elif defined(__clang__) && (__clang_major__ < 5)
+# undef CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS
+#endif
+
+#if !defined(CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS)
+# define CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS
+#endif
+
+#if defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
+#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
+
+#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 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
+
+
+#endif // CATCH_COMPILER_CAPABILITIES_HPP_INCLUDED
+
+
+#ifndef CATCH_CONTEXT_HPP_INCLUDED
+#define CATCH_CONTEXT_HPP_INCLUDED
+
+namespace Catch {
+
+ class IResultCapture;
+ class IConfig;
+
+ class IContext {
+ public:
+ virtual ~IContext(); // = default
+
+ virtual IResultCapture* getResultCapture() = 0;
+ virtual IConfig const* getConfig() const = 0;
+ };
+
+ class IMutableContext : public IContext {
+ public:
+ ~IMutableContext() override; // = default
+ virtual void setResultCapture( IResultCapture* resultCapture ) = 0;
+ virtual void setConfig( IConfig const* config ) = 0;
+
+ private:
+ static IMutableContext *currentContext;
+ friend IMutableContext& getCurrentMutableContext();
+ friend void cleanUpContext();
+ static void createContext();
+ };
+
+ inline IMutableContext& getCurrentMutableContext()
+ {
+ if( !IMutableContext::currentContext )
+ IMutableContext::createContext();
+ // NOLINTNEXTLINE(clang-analyzer-core.uninitialized.UndefReturn)
+ return *IMutableContext::currentContext;
+ }
+
+ inline IContext& getCurrentContext()
+ {
+ return getCurrentMutableContext();
+ }
+
+ void cleanUpContext();
+
+ class SimplePcg32;
+ SimplePcg32& sharedRng();
+}
+
+#endif // CATCH_CONTEXT_HPP_INCLUDED
+
+
+#ifndef CATCH_INTERFACES_REPORTER_HPP_INCLUDED
+#define CATCH_INTERFACES_REPORTER_HPP_INCLUDED
+
+
+
+#ifndef CATCH_SECTION_INFO_HPP_INCLUDED
+#define CATCH_SECTION_INFO_HPP_INCLUDED
+
+
+
+#ifndef CATCH_MOVE_AND_FORWARD_HPP_INCLUDED
+#define CATCH_MOVE_AND_FORWARD_HPP_INCLUDED
+
+#include <type_traits>
+
+//! Replacement for std::move with better compile time performance
+#define CATCH_MOVE(...) static_cast<std::remove_reference_t<decltype(__VA_ARGS__)>&&>(__VA_ARGS__)
+
+//! Replacement for std::forward with better compile time performance
+#define CATCH_FORWARD(...) static_cast<decltype(__VA_ARGS__)&&>(__VA_ARGS__)
+
+#endif // CATCH_MOVE_AND_FORWARD_HPP_INCLUDED
+
+
+#ifndef CATCH_SOURCE_LINE_INFO_HPP_INCLUDED
+#define CATCH_SOURCE_LINE_INFO_HPP_INCLUDED
+
+#include <cstddef>
+#include <iosfwd>
+
+namespace Catch {
+
+ struct SourceLineInfo {
+
+ SourceLineInfo() = delete;
+ constexpr SourceLineInfo( char const* _file, std::size_t _line ) noexcept:
+ file( _file ),
+ line( _line )
+ {}
+
+ bool operator == ( SourceLineInfo const& other ) const noexcept;
+ bool operator < ( SourceLineInfo const& other ) const noexcept;
+
+ char const* file;
+ std::size_t line;
+
+ friend std::ostream& operator << (std::ostream& os, SourceLineInfo const& info);
+ };
+}
+
+#define CATCH_INTERNAL_LINEINFO \
+ ::Catch::SourceLineInfo( __FILE__, static_cast<std::size_t>( __LINE__ ) )
+
+#endif // CATCH_SOURCE_LINE_INFO_HPP_INCLUDED
+
+
+#ifndef CATCH_TOTALS_HPP_INCLUDED
+#define CATCH_TOTALS_HPP_INCLUDED
+
+#include <cstdint>
+
+namespace Catch {
+
+ struct Counts {
+ Counts operator - ( Counts const& other ) const;
+ Counts& operator += ( Counts const& other );
+
+ 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;
+ };
+
+ struct Totals {
+
+ Totals operator - ( Totals const& other ) const;
+ Totals& operator += ( Totals const& other );
+
+ Totals delta( Totals const& prevTotals ) const;
+
+ Counts assertions;
+ Counts testCases;
+ };
+}
+
+#endif // CATCH_TOTALS_HPP_INCLUDED
+
+#include <string>
+
+namespace Catch {
+
+ 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;
+ };
+
+ struct SectionEndInfo {
+ SectionInfo sectionInfo;
+ Counts prevAssertions;
+ double durationInSeconds;
+ };
+
+} // end namespace Catch
+
+#endif // CATCH_SECTION_INFO_HPP_INCLUDED
+
+
+#ifndef CATCH_ASSERTION_RESULT_HPP_INCLUDED
+#define CATCH_ASSERTION_RESULT_HPP_INCLUDED
+
+
+
+#ifndef CATCH_ASSERTION_INFO_HPP_INCLUDED
+#define CATCH_ASSERTION_INFO_HPP_INCLUDED
+
+
+
+#ifndef CATCH_RESULT_TYPE_HPP_INCLUDED
+#define CATCH_RESULT_TYPE_HPP_INCLUDED
+
+namespace Catch {
+
+ // 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 );
+
+ 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
+
+namespace Catch {
+
+ struct AssertionInfo {
+ // AssertionInfo() = delete;
+
+ StringRef macroName;
+ SourceLineInfo lineInfo;
+ StringRef capturedExpression;
+ ResultDisposition::Flags resultDisposition;
+ };
+
+} // end namespace Catch
+
+#endif // CATCH_ASSERTION_INFO_HPP_INCLUDED
+
+
+#ifndef CATCH_LAZY_EXPR_HPP_INCLUDED
+#define CATCH_LAZY_EXPR_HPP_INCLUDED
+
+#include <iosfwd>
+
+namespace Catch {
+
+ 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;
+ }
+
+ friend auto operator << ( std::ostream& os, LazyExpression const& lazyExpr ) -> std::ostream&;
+ };
+
+} // namespace Catch
+
+#endif // CATCH_LAZY_EXPR_HPP_INCLUDED
+
+#include <string>
+
+namespace Catch {
+
+ struct AssertionResultData
+ {
+ AssertionResultData() = delete;
+
+ AssertionResultData( ResultWas::OfType _resultType, LazyExpression const& _lazyExpression );
+
+ std::string message;
+ mutable std::string reconstructedExpression;
+ LazyExpression lazyExpression;
+ ResultWas::OfType resultType;
+
+ std::string reconstructExpression() const;
+ };
+
+ 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;
+
+ //protected:
+ AssertionInfo m_info;
+ AssertionResultData m_resultData;
+ };
+
+} // end namespace Catch
+
+#endif // CATCH_ASSERTION_RESULT_HPP_INCLUDED
+
+
+#ifndef CATCH_MESSAGE_INFO_HPP_INCLUDED
+#define CATCH_MESSAGE_INFO_HPP_INCLUDED
+
+
+
+#ifndef CATCH_INTERFACES_CAPTURE_HPP_INCLUDED
+#define CATCH_INTERFACES_CAPTURE_HPP_INCLUDED
+
+#include <string>
+#include <chrono>
+
+
+namespace Catch {
+
+ class AssertionResult;
+ struct AssertionInfo;
+ struct SectionInfo;
+ struct SectionEndInfo;
+ struct MessageInfo;
+ struct MessageBuilder;
+ struct Counts;
+ struct AssertionReaction;
+ struct SourceLineInfo;
+
+ class ITransientExpression;
+ class IGeneratorTracker;
+
+ struct BenchmarkInfo;
+ template <typename Duration = std::chrono::duration<double, std::nano>>
+ struct BenchmarkStats;
+
+ class IResultCapture {
+ public:
+ virtual ~IResultCapture();
+
+ 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;
+
+ 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;
+
+ virtual void pushScopedMessage( MessageInfo const& message ) = 0;
+ virtual void popScopedMessage( MessageInfo const& message ) = 0;
+
+ virtual void emplaceUnscopedMessage( MessageBuilder const& builder ) = 0;
+
+ virtual void handleFatalErrorCondition( StringRef message ) = 0;
+
+ virtual void handleExpr
+ ( 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;
+
+
+
+ virtual bool lastAssertionPassed() = 0;
+ virtual void assertionPassed() = 0;
+
+ // Deprecated, do not use:
+ virtual std::string getCurrentTestName() const = 0;
+ virtual const AssertionResult* getLastResult() const = 0;
+ virtual void exceptionEarlyReported() = 0;
+ };
+
+ IResultCapture& getResultCapture();
+}
+
+#endif // CATCH_INTERFACES_CAPTURE_HPP_INCLUDED
+
+#include <string>
+
+namespace Catch {
+
+ struct MessageInfo {
+ MessageInfo( StringRef _macroName,
+ SourceLineInfo const& _lineInfo,
+ ResultWas::OfType _type );
+
+ StringRef macroName;
+ std::string message;
+ SourceLineInfo lineInfo;
+ ResultWas::OfType type;
+ unsigned int sequence;
+
+ 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;
+ };
+
+} // end namespace Catch
+
+#endif // CATCH_MESSAGE_INFO_HPP_INCLUDED
+
+
+#ifndef CATCH_UNIQUE_PTR_HPP_INCLUDED
+#define CATCH_UNIQUE_PTR_HPP_INCLUDED
+
+#include <cassert>
+#include <type_traits>
+
+
+namespace Catch {
+namespace Detail {
+ /**
+ * A reimplementation of `std::unique_ptr` for improved compilation performance
+ *
+ * Does not support arrays nor custom deleters.
+ */
+ template <typename T>
+ 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)
+ {}
+
+ template <typename U, typename = std::enable_if_t<std::is_base_of<T, U>::value>>
+ unique_ptr(unique_ptr<U>&& from):
+ m_ptr(from.release())
+ {}
+
+ template <typename U, typename = std::enable_if_t<std::is_base_of<T, U>::value>>
+ unique_ptr& operator=(unique_ptr<U>&& from) {
+ reset(from.release());
+
+ return *this;
+ }
+
+ 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());
+
+ return *this;
+ }
+
+ ~unique_ptr() {
+ delete m_ptr;
+ }
+
+ 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;
+ }
+
+ T* get() { return m_ptr; }
+ T const* get() const { return m_ptr; }
+
+ void reset(T* ptr = nullptr) {
+ delete m_ptr;
+ m_ptr = ptr;
+ }
+
+ T* release() {
+ auto temp = m_ptr;
+ m_ptr = nullptr;
+ return temp;
+ }
+
+ 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;
+ }
+ };
+
+ //! Specialization to cause compile-time error for arrays
+ template <typename T>
+ class unique_ptr<T[]>;
+
+ template <typename T, typename... Args>
+ unique_ptr<T> make_unique(Args&&... args) {
+ return unique_ptr<T>(new T(CATCH_FORWARD(args)...));
+ }
+
+
+} // end namespace Detail
+} // end namespace Catch
+
+#endif // CATCH_UNIQUE_PTR_HPP_INCLUDED
+
+
+// Adapted from donated nonius code.
+
+#ifndef CATCH_ESTIMATE_HPP_INCLUDED
+#define CATCH_ESTIMATE_HPP_INCLUDED
+
+namespace Catch {
+ namespace Benchmark {
+ template <typename Duration>
+ struct Estimate {
+ Duration point;
+ Duration lower_bound;
+ Duration upper_bound;
+ double confidence_interval;
+
+ template <typename Duration2>
+ operator Estimate<Duration2>() const {
+ return { point, lower_bound, upper_bound, confidence_interval };
+ }
+ };
+ } // namespace Benchmark
+} // namespace Catch
+
+#endif // CATCH_ESTIMATE_HPP_INCLUDED
+
+
+// Adapted from donated nonius code.
+
+#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
+
+#endif // CATCH_OUTLIERS_CLASSIFICATION_HPP_INCLUDED
+
+
+#include <map>
+#include <string>
+#include <vector>
+#include <iosfwd>
+
+namespace Catch {
+
+ struct ReporterDescription;
+ struct ListenerDescription;
+ 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<IStream> _stream,
+ ColourMode colourMode,
+ std::map<std::string, std::string> customOptions );
+
+ ReporterConfig( ReporterConfig&& ) = default;
+ ReporterConfig& operator=( ReporterConfig&& ) = default;
+ ~ReporterConfig(); // = default
+
+ Detail::unique_ptr<IStream> takeStream() &&;
+ IConfig const* fullConfig() const;
+ ColourMode colourMode() const;
+ std::map<std::string, std::string> const& customOptions() const;
+
+ private:
+ Detail::unique_ptr<IStream> m_stream;
+ IConfig const* m_fullConfig;
+ ColourMode m_colourMode;
+ std::map<std::string, std::string> m_customOptions;
+ };
+
+ struct TestRunInfo {
+ constexpr TestRunInfo(StringRef _name) : name(_name) {}
+ StringRef name;
+ };
+
+ struct AssertionStats {
+ AssertionStats( AssertionResult const& _assertionResult,
+ std::vector<MessageInfo> const& _infoMessages,
+ Totals const& _totals );
+
+ AssertionStats( AssertionStats const& ) = default;
+ AssertionStats( AssertionStats && ) = default;
+ AssertionStats& operator = ( AssertionStats const& ) = delete;
+ AssertionStats& operator = ( AssertionStats && ) = delete;
+
+ AssertionResult assertionResult;
+ std::vector<MessageInfo> infoMessages;
+ Totals totals;
+ };
+
+ struct SectionStats {
+ SectionStats( SectionInfo const& _sectionInfo,
+ Counts const& _assertions,
+ double _durationInSeconds,
+ bool _missingAssertions );
+
+ SectionInfo sectionInfo;
+ Counts assertions;
+ double durationInSeconds;
+ bool missingAssertions;
+ };
+
+ struct TestCaseStats {
+ TestCaseStats( TestCaseInfo const& _testInfo,
+ Totals const& _totals,
+ std::string const& _stdOut,
+ std::string const& _stdErr,
+ bool _aborting );
+
+ TestCaseInfo const * testInfo;
+ Totals totals;
+ std::string stdOut;
+ std::string stdErr;
+ bool aborting;
+ };
+
+ struct TestRunStats {
+ TestRunStats( TestRunInfo const& _runInfo,
+ Totals const& _totals,
+ bool _aborting );
+
+ TestRunInfo runInfo;
+ Totals totals;
+ bool aborting;
+ };
+
+
+ struct BenchmarkInfo {
+ std::string name;
+ double estimatedDuration;
+ int iterations;
+ unsigned int samples;
+ unsigned int resamples;
+ double clockResolution;
+ double clockCost;
+ };
+
+ template <class Duration>
+ struct BenchmarkStats {
+ BenchmarkInfo info;
+
+ std::vector<Duration> samples;
+ Benchmark::Estimate<Duration> mean;
+ Benchmark::Estimate<Duration> standardDeviation;
+ Benchmark::OutlierClassification outliers;
+ double outlierVariance;
+
+ template <typename Duration2>
+ operator BenchmarkStats<Duration2>() const {
+ std::vector<Duration2> samples2;
+ samples2.reserve(samples.size());
+ for (auto const& sample : samples) {
+ samples2.push_back(Duration2(sample));
+ }
+ return {
+ info,
+ CATCH_MOVE(samples2),
+ mean,
+ standardDeviation,
+ outliers,
+ outlierVariance,
+ };
+ }
+ };
+
+ //! 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;
+
+ //! 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;
+
+ //! 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;
+
+ //! 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;
+
+ //! Called with test cases that are skipped due to the test run aborting
+ virtual void skipTest( TestCaseInfo const& testInfo ) = 0;
+
+ //! Called if a fatal error (signal/structured exception) occured
+ virtual void fatalErrorEncountered( StringRef error ) = 0;
+
+ //! Writes out information about provided reporters using reporter-specific format
+ virtual void listReporters(std::vector<ReporterDescription> const& descriptions) = 0;
+ //! Writes out the provided listeners descriptions using reporter-specific format
+ virtual void listListeners(std::vector<ListenerDescription> const& descriptions) = 0;
+ //! Writes out information about provided tests using reporter-specific format
+ virtual void listTests(std::vector<TestCaseHandle> const& tests) = 0;
+ //! Writes out information about the provided tags using reporter-specific format
+ virtual void listTags(std::vector<TagInfo> const& tags) = 0;
+ };
+ using IEventListenerPtr = Detail::unique_ptr<IEventListener>;
+
+} // end namespace Catch
+
+#endif // CATCH_INTERFACES_REPORTER_HPP_INCLUDED
+
+
+#ifndef CATCH_UNIQUE_NAME_HPP_INCLUDED
+#define CATCH_UNIQUE_NAME_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.
+ */
+
+#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
+
+
+// Adapted from donated nonius code.
+
+#ifndef CATCH_CHRONOMETER_HPP_INCLUDED
+#define CATCH_CHRONOMETER_HPP_INCLUDED
+
+
+
+// Adapted from donated nonius code.
+
+#ifndef CATCH_CLOCK_HPP_INCLUDED
+#define CATCH_CLOCK_HPP_INCLUDED
+
+#include <chrono>
+#include <ratio>
+
+namespace Catch {
+ namespace Benchmark {
+ template <typename Clock>
+ using ClockDuration = typename Clock::duration;
+ template <typename Clock>
+ using FloatDuration = std::chrono::duration<double, typename Clock::period>;
+
+ template <typename Clock>
+ using TimePoint = typename Clock::time_point;
+
+ using default_clock = std::chrono::steady_clock;
+
+ template <typename Clock>
+ struct now {
+ TimePoint<Clock> operator()() const {
+ return Clock::now();
+ }
+ };
+
+ using fp_seconds = std::chrono::duration<double, std::ratio<1>>;
+ } // namespace Benchmark
+} // namespace Catch
+
+#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> // atomic_thread_fence
+#endif
+
+
+#include <type_traits>
+
+namespace Catch {
+ namespace Benchmark {
+#if defined(__GNUC__) || defined(__clang__)
+ template <typename T>
+ inline void keep_memory(T* p) {
+ asm volatile("" : : "g"(p) : "memory");
+ }
+ inline void keep_memory() {
+ asm volatile("" : : : "memory");
+ }
+
+ namespace Detail {
+ inline void optimizer_barrier() { keep_memory(); }
+ } // namespace Detail
+#elif defined(_MSC_VER)
+
+#pragma optimize("", off)
+ template <typename T>
+ inline void keep_memory(T* p) {
+ // thanks @milleniumbug
+ *reinterpret_cast<char volatile*>(p) = *reinterpret_cast<char const volatile*>(p);
+ }
+ // TODO equivalent keep_memory()
+#pragma optimize("", on)
+
+ namespace Detail {
+ inline void optimizer_barrier() {
+ std::atomic_thread_fence(std::memory_order_seq_cst);
+ }
+ } // namespace Detail
+
+#endif
+
+ template <typename T>
+ inline void deoptimize_value(T&& x) {
+ keep_memory(&x);
+ }
+
+ template <typename Fn, typename... Args>
+ inline auto invoke_deoptimized(Fn&& fn, Args&&... args) -> std::enable_if_t<!std::is_same<void, decltype(fn(args...))>::value> {
+ deoptimize_value(CATCH_FORWARD(fn) (CATCH_FORWARD(args)...));
+ }
+
+ template <typename Fn, typename... Args>
+ inline auto invoke_deoptimized(Fn&& fn, Args&&... args) -> std::enable_if_t<std::is_same<void, decltype(fn(args...))>::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 TestFailureException{};
+
+} // namespace Catch
+
+#endif // CATCH_TEST_FAILURE_EXCEPTION_HPP_INCLUDED
+
+
+#ifndef CATCH_META_HPP_INCLUDED
+#define CATCH_META_HPP_INCLUDED
+
+#include <type_traits>
+
+namespace Catch {
+ template<typename T>
+ struct always_false : std::false_type {};
+
+ template <typename> struct true_given : std::true_type {};
+ struct is_callable_tester {
+ template <typename Fun, typename... Args>
+ true_given<decltype(std::declval<Fun>()(std::declval<Args>()...))> static test(int);
+ template <typename...>
+ std::false_type static test(...);
+ };
+
+ template <typename T>
+ struct is_callable;
+
+ template <typename Fun, typename... Args>
+ struct is_callable<Fun(Args...)> : decltype(is_callable_tester::test<Fun, Args...>(0)) {};
+
+
+#if defined(__cpp_lib_is_invocable) && __cpp_lib_is_invocable >= 201703
+ // std::result_of is deprecated in C++17 and removed in C++20. Hence, it is
+ // replaced with std::invoke_result here.
+ template <typename Func, typename... U>
+ using FunctionReturnType = std::remove_reference_t<std::remove_cv_t<std::invoke_result_t<Func, U...>>>;
+#else
+ template <typename Func, typename... U>
+ using FunctionReturnType = std::remove_reference_t<std::remove_cv_t<std::result_of_t<Func(U...)>>>;
+#endif
+
+} // namespace Catch
+
+namespace mpl_{
+ struct na;
+}
+
+#endif // CATCH_META_HPP_INCLUDED
+
+
+#ifndef CATCH_INTERFACES_REGISTRY_HUB_HPP_INCLUDED
+#define CATCH_INTERFACES_REGISTRY_HUB_HPP_INCLUDED
+
+
+#include <string>
+
+namespace Catch {
+
+ 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;
+
+ using IReporterFactoryPtr = Detail::unique_ptr<IReporterFactory>;
+
+ class IRegistryHub {
+ public:
+ virtual ~IRegistryHub(); // = default
+
+ virtual IReporterRegistry const& getReporterRegistry() const = 0;
+ virtual ITestCaseRegistry const& getTestCaseRegistry() const = 0;
+ virtual ITagAliasRegistry const& getTagAliasRegistry() const = 0;
+ virtual IExceptionTranslatorRegistry const& getExceptionTranslatorRegistry() const = 0;
+
+
+ virtual StartupExceptionRegistry const& getStartupExceptionRegistry() const = 0;
+ };
+
+ class IMutableRegistryHub {
+ public:
+ virtual ~IMutableRegistryHub(); // = default
+ virtual void registerReporter( std::string const& name, IReporterFactoryPtr factory ) = 0;
+ virtual void registerListener( Detail::unique_ptr<EventListenerFactory> factory ) = 0;
+ virtual void registerTest(Detail::unique_ptr<TestCaseInfo>&& testInfo, Detail::unique_ptr<ITestInvoker>&& invoker) = 0;
+ virtual void registerTranslator( Detail::unique_ptr<IExceptionTranslator>&& translator ) = 0;
+ virtual void registerTagAlias( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ) = 0;
+ virtual void registerStartupException() noexcept = 0;
+ virtual IMutableEnumValuesRegistry& getMutableEnumValuesRegistry() = 0;
+ };
+
+ IRegistryHub const& getRegistryHub();
+ IMutableRegistryHub& getMutableRegistryHub();
+ void cleanUp();
+ std::string translateActiveException();
+
+}
+
+#endif // CATCH_INTERFACES_REGISTRY_HUB_HPP_INCLUDED
+
+#include <type_traits>
+
+namespace Catch {
+ namespace Benchmark {
+ namespace Detail {
+ template <typename T>
+ struct CompleteType { using type = T; };
+ template <>
+ struct CompleteType<void> { struct type {}; };
+
+ template <typename T>
+ using CompleteType_t = typename CompleteType<T>::type;
+
+ template <typename Result>
+ struct CompleteInvoker {
+ template <typename Fun, typename... Args>
+ static Result invoke(Fun&& fun, Args&&... args) {
+ return CATCH_FORWARD(fun)(CATCH_FORWARD(args)...);
+ }
+ };
+ template <>
+ struct CompleteInvoker<void> {
+ template <typename Fun, typename... Args>
+ static CompleteType_t<void> invoke(Fun&& fun, Args&&... args) {
+ CATCH_FORWARD(fun)(CATCH_FORWARD(args)...);
+ return {};
+ }
+ };
+
+ // invoke and not return void :(
+ template <typename Fun, typename... Args>
+ CompleteType_t<FunctionReturnType<Fun, Args...>> complete_invoke(Fun&& fun, Args&&... args) {
+ return CompleteInvoker<FunctionReturnType<Fun, Args...>>::invoke(CATCH_FORWARD(fun), CATCH_FORWARD(args)...);
+ }
+
+ } // namespace Detail
+
+ template <typename Fun>
+ Detail::CompleteType_t<FunctionReturnType<Fun>> user_code(Fun&& fun) {
+ return Detail::complete_invoke(CATCH_FORWARD(fun));
+ }
+ } // namespace Benchmark
+} // namespace Catch
+
+#endif // CATCH_COMPLETE_INVOKE_HPP_INCLUDED
+
+namespace Catch {
+ namespace Benchmark {
+ namespace Detail {
+ struct ChronometerConcept {
+ virtual void start() = 0;
+ virtual void finish() = 0;
+ virtual ~ChronometerConcept(); // = default;
+
+ ChronometerConcept() = default;
+ ChronometerConcept(ChronometerConcept const&) = default;
+ ChronometerConcept& operator=(ChronometerConcept const&) = default;
+ };
+ template <typename Clock>
+ struct ChronometerModel final : public ChronometerConcept {
+ void start() override { started = Clock::now(); }
+ void finish() override { finished = Clock::now(); }
+
+ ClockDuration<Clock> elapsed() const { return finished - started; }
+
+ TimePoint<Clock> started;
+ TimePoint<Clock> finished;
+ };
+ } // namespace Detail
+
+ struct Chronometer {
+ public:
+ template <typename Fun>
+ void measure(Fun&& fun) { measure(CATCH_FORWARD(fun), is_callable<Fun(int)>()); }
+
+ int runs() const { return repeats; }
+
+ Chronometer(Detail::ChronometerConcept& meter, int repeats_)
+ : impl(&meter)
+ , repeats(repeats_) {}
+
+ private:
+ template <typename Fun>
+ void measure(Fun&& fun, std::false_type) {
+ measure([&fun](int) { return fun(); }, std::true_type());
+ }
+
+ template <typename Fun>
+ void measure(Fun&& fun, std::true_type) {
+ Detail::optimizer_barrier();
+ impl->start();
+ for (int i = 0; i < repeats; ++i) invoke_deoptimized(fun, i);
+ impl->finish();
+ Detail::optimizer_barrier();
+ }
+
+ Detail::ChronometerConcept* impl;
+ int repeats;
+ };
+ } // namespace Benchmark
+} // namespace Catch
+
+#endif // CATCH_CHRONOMETER_HPP_INCLUDED
+
+
+// Adapted from donated nonius code.
+
+#ifndef CATCH_ENVIRONMENT_HPP_INCLUDED
+#define CATCH_ENVIRONMENT_HPP_INCLUDED
+
+
+namespace Catch {
+ namespace Benchmark {
+ template <typename Duration>
+ struct EnvironmentEstimate {
+ Duration mean;
+ OutlierClassification outliers;
+
+ template <typename Duration2>
+ operator EnvironmentEstimate<Duration2>() const {
+ return { mean, outliers };
+ }
+ };
+ template <typename Clock>
+ struct Environment {
+ using clock_type = Clock;
+ EnvironmentEstimate<FloatDuration<Clock>> clock_resolution;
+ EnvironmentEstimate<FloatDuration<Clock>> clock_cost;
+ };
+ } // namespace Benchmark
+} // namespace Catch
+
+#endif // CATCH_ENVIRONMENT_HPP_INCLUDED
+
+
+// Adapted from donated nonius code.
+
+#ifndef CATCH_EXECUTION_PLAN_HPP_INCLUDED
+#define CATCH_EXECUTION_PLAN_HPP_INCLUDED
+
+
+
+// Adapted from donated nonius code.
+
+#ifndef CATCH_BENCHMARK_FUNCTION_HPP_INCLUDED
+#define CATCH_BENCHMARK_FUNCTION_HPP_INCLUDED
+
+
+#include <type_traits>
+
+namespace Catch {
+ namespace Benchmark {
+ namespace Detail {
+ template <typename T, typename U>
+ struct is_related
+ : std::is_same<std::decay_t<T>, std::decay_t<U>> {};
+
+ /// We need to reinvent std::function because every piece of code that might add overhead
+ /// in a measurement context needs to have consistent performance characteristics so that we
+ /// can account for it in the measurement.
+ /// Implementations of std::function with optimizations that aren't always applicable, like
+ /// small buffer optimizations, are not uncommon.
+ /// This is effectively an implementation of std::function without any such optimizations;
+ /// it may be slow, but it is consistently slow.
+ struct BenchmarkFunction {
+ private:
+ struct callable {
+ virtual void call(Chronometer meter) const = 0;
+ virtual Catch::Detail::unique_ptr<callable> clone() const = 0;
+ virtual ~callable(); // = default;
+
+ callable() = default;
+ callable(callable const&) = default;
+ callable& operator=(callable const&) = default;
+ };
+ template <typename Fun>
+ struct model : public callable {
+ model(Fun&& fun_) : fun(CATCH_MOVE(fun_)) {}
+ model(Fun const& fun_) : fun(fun_) {}
+
+ Catch::Detail::unique_ptr<callable> clone() const override {
+ return Catch::Detail::make_unique<model<Fun>>( *this );
+ }
+
+ void call(Chronometer meter) const override {
+ call(meter, is_callable<Fun(Chronometer)>());
+ }
+ void call(Chronometer meter, std::true_type) const {
+ fun(meter);
+ }
+ void call(Chronometer meter, std::false_type) const {
+ meter.measure(fun);
+ }
+
+ Fun fun;
+ };
+
+ struct do_nothing { void operator()() const {} };
+
+ template <typename T>
+ BenchmarkFunction(model<T>* c) : f(c) {}
+
+ public:
+ BenchmarkFunction()
+ : f(new model<do_nothing>{ {} }) {}
+
+ template <typename Fun,
+ std::enable_if_t<!is_related<Fun, BenchmarkFunction>::value, int> = 0>
+ BenchmarkFunction(Fun&& fun)
+ : f(new model<std::decay_t<Fun>>(CATCH_FORWARD(fun))) {}
+
+ BenchmarkFunction( BenchmarkFunction&& that ) noexcept:
+ f( CATCH_MOVE( that.f ) ) {}
+
+ BenchmarkFunction(BenchmarkFunction const& that)
+ : f(that.f->clone()) {}
+
+ BenchmarkFunction&
+ operator=( BenchmarkFunction&& that ) noexcept {
+ f = CATCH_MOVE( that.f );
+ return *this;
+ }
+
+ BenchmarkFunction& operator=(BenchmarkFunction const& that) {
+ f = that.f->clone();
+ return *this;
+ }
+
+ void operator()(Chronometer meter) const { f->call(meter); }
+
+ private:
+ Catch::Detail::unique_ptr<callable> f;
+ };
+ } // namespace Detail
+ } // namespace Benchmark
+} // namespace Catch
+
+#endif // CATCH_BENCHMARK_FUNCTION_HPP_INCLUDED
+
+
+// Adapted from donated nonius code.
+
+#ifndef CATCH_REPEAT_HPP_INCLUDED
+#define CATCH_REPEAT_HPP_INCLUDED
+
+#include <type_traits>
+
+namespace Catch {
+ namespace Benchmark {
+ namespace Detail {
+ template <typename Fun>
+ struct repeater {
+ void operator()(int k) const {
+ for (int i = 0; i < k; ++i) {
+ fun();
+ }
+ }
+ Fun fun;
+ };
+ template <typename Fun>
+ repeater<std::decay_t<Fun>> repeat(Fun&& fun) {
+ return { CATCH_FORWARD(fun) };
+ }
+ } // namespace Detail
+ } // namespace Benchmark
+} // namespace Catch
+
+#endif // CATCH_REPEAT_HPP_INCLUDED
+
+
+// Adapted from donated nonius code.
+
+#ifndef CATCH_RUN_FOR_AT_LEAST_HPP_INCLUDED
+#define CATCH_RUN_FOR_AT_LEAST_HPP_INCLUDED
+
+
+
+// Adapted from donated nonius code.
+
+#ifndef CATCH_MEASURE_HPP_INCLUDED
+#define CATCH_MEASURE_HPP_INCLUDED
+
+
+
+// Adapted from donated nonius code.
+
+#ifndef CATCH_TIMING_HPP_INCLUDED
+#define CATCH_TIMING_HPP_INCLUDED
+
+
+#include <type_traits>
+
+namespace Catch {
+ namespace Benchmark {
+ template <typename Duration, typename Result>
+ struct Timing {
+ Duration elapsed;
+ Result result;
+ int iterations;
+ };
+ template <typename Clock, typename Func, typename... Args>
+ using TimingOf = Timing<ClockDuration<Clock>, Detail::CompleteType_t<FunctionReturnType<Func, Args...>>>;
+ } // namespace Benchmark
+} // namespace Catch
+
+#endif // CATCH_TIMING_HPP_INCLUDED
+
+namespace Catch {
+ namespace Benchmark {
+ namespace Detail {
+ template <typename Clock, typename Fun, typename... Args>
+ TimingOf<Clock, Fun, Args...> measure(Fun&& fun, Args&&... args) {
+ auto start = Clock::now();
+ auto&& r = Detail::complete_invoke(fun, 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 <type_traits>
+
+namespace Catch {
+ namespace Benchmark {
+ namespace Detail {
+ template <typename Clock, typename Fun>
+ TimingOf<Clock, Fun, int> measure_one(Fun&& fun, int iters, std::false_type) {
+ return Detail::measure<Clock>(fun, iters);
+ }
+ template <typename Clock, typename Fun>
+ TimingOf<Clock, Fun, Chronometer> measure_one(Fun&& fun, int iters, std::true_type) {
+ Detail::ChronometerModel<Clock> meter;
+ auto&& result = Detail::complete_invoke(fun, Chronometer(meter, iters));
+
+ return { meter.elapsed(), CATCH_MOVE(result), iters };
+ }
+
+ template <typename Clock, typename Fun>
+ using run_for_at_least_argument_t = std::conditional_t<is_callable<Fun(Chronometer)>::value, Chronometer, int>;
+
+
+ [[noreturn]]
+ void throw_optimized_away_error();
+
+ template <typename Clock, typename Fun>
+ TimingOf<Clock, Fun, run_for_at_least_argument_t<Clock, Fun>>
+ run_for_at_least(ClockDuration<Clock> how_long,
+ const int initial_iterations,
+ Fun&& fun) {
+ auto iters = initial_iterations;
+ while (iters < (1 << 30)) {
+ auto&& Timing = measure_one<Clock>(fun, iters, is_callable<Fun(Chronometer)>());
+
+ 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 <algorithm>
+#include <iterator>
+
+namespace Catch {
+ namespace Benchmark {
+ template <typename Duration>
+ struct ExecutionPlan {
+ int iterations_per_sample;
+ Duration estimated_duration;
+ Detail::BenchmarkFunction benchmark;
+ Duration warmup_time;
+ int warmup_iterations;
+
+ template <typename Duration2>
+ operator ExecutionPlan<Duration2>() const {
+ return { iterations_per_sample, estimated_duration, benchmark, warmup_time, warmup_iterations };
+ }
+
+ template <typename Clock>
+ std::vector<FloatDuration<Clock>> run(const IConfig &cfg, Environment<FloatDuration<Clock>> env) const {
+ // warmup a bit
+ Detail::run_for_at_least<Clock>(std::chrono::duration_cast<ClockDuration<Clock>>(warmup_time), warmup_iterations, Detail::repeat(now<Clock>{}));
+
+ std::vector<FloatDuration<Clock>> times;
+ times.reserve(cfg.benchmarkSamples());
+ std::generate_n(std::back_inserter(times), cfg.benchmarkSamples(), [this, env] {
+ Detail::ChronometerModel<Clock> model;
+ this->benchmark(Chronometer(model, iterations_per_sample));
+ auto sample_time = model.elapsed() - env.clock_cost.mean;
+ if (sample_time < FloatDuration<Clock>::zero()) sample_time = FloatDuration<Clock>::zero();
+ return sample_time / iterations_per_sample;
+ });
+ return times;
+ }
+ };
+ } // namespace Benchmark
+} // namespace Catch
+
+#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 <algorithm>
+#include <vector>
+#include <numeric>
+#include <tuple>
+#include <cmath>
+
+namespace Catch {
+ namespace Benchmark {
+ namespace Detail {
+ using sample = std::vector<double>;
+
+ // Used when we know we want == comparison of two doubles
+ // to centralize warning suppression
+ bool directCompare( double lhs, double rhs );
+
+ double weighted_average_quantile(int k, int q, std::vector<double>::iterator first, std::vector<double>::iterator last);
+
+ template <typename Iterator>
+ OutlierClassification classify_outliers(Iterator first, Iterator last) {
+ std::vector<double> copy(first, last);
+
+ auto q1 = weighted_average_quantile(1, 4, copy.begin(), copy.end());
+ auto q3 = weighted_average_quantile(3, 4, copy.begin(), copy.end());
+ auto iqr = q3 - q1;
+ auto los = q1 - (iqr * 3.);
+ auto lom = q1 - (iqr * 1.5);
+ auto him = q3 + (iqr * 1.5);
+ auto his = q3 + (iqr * 3.);
+
+ OutlierClassification o;
+ for (; first != last; ++first) {
+ auto&& t = *first;
+ if (t < los) ++o.low_severe;
+ else if (t < lom) ++o.low_mild;
+ else if (t > his) ++o.high_severe;
+ else if (t > him) ++o.high_mild;
+ ++o.samples_seen;
+ }
+ return o;
+ }
+
+ template <typename Iterator>
+ double mean(Iterator first, Iterator last) {
+ auto count = last - first;
+ double sum = std::accumulate(first, last, 0.);
+ return sum / static_cast<double>(count);
+ }
+
+ template <typename Estimator, typename Iterator>
+ sample jackknife(Estimator&& estimator, Iterator first, Iterator last) {
+ auto n = static_cast<size_t>(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 <typename Iterator, typename Estimator>
+ Estimate<double> bootstrap(double confidence_level, Iterator first, Iterator last, sample const& resample, Estimator&& estimator) {
+ auto n_samples = last - first;
+
+ double point = estimator(first, last);
+ // Degenerate case with a single sample
+ if (n_samples == 1) return { point, point, point, confidence_level };
+
+ sample jack = jackknife(estimator, first, last);
+ double jack_mean = mean(jack.begin(), jack.end());
+ double sum_squares, sum_cubes;
+ std::tie(sum_squares, sum_cubes) = std::accumulate(jack.begin(), jack.end(), std::make_pair(0., 0.), [jack_mean](std::pair<double, double> sqcb, double x) -> std::pair<double, double> {
+ auto d = jack_mean - x;
+ auto d2 = d * d;
+ auto d3 = d2 * d;
+ return { sqcb.first + d2, sqcb.second + d3 };
+ });
+
+ double accel = sum_cubes / (6 * std::pow(sum_squares, 1.5));
+ long n = static_cast<long>(resample.size());
+ double prob_n = std::count_if(resample.begin(), resample.end(), [point](double x) { return x < point; }) / static_cast<double>(n);
+ // degenerate case with uniform samples
+ if ( directCompare( 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 ) -> long {
+ return std::lround( normal_cdf( x ) * static_cast<double>(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<size_t>((std::max)(cumn(a1), 0l));
+ auto hi = static_cast<size_t>((std::min)(cumn(a2), n - 1));
+
+ return { point, resample[lo], resample[hi], confidence_level };
+ }
+
+ double outlier_variance(Estimate<double> mean, Estimate<double> stddev, int n);
+
+ struct bootstrap_analysis {
+ Estimate<double> mean;
+ Estimate<double> standard_deviation;
+ double outlier_variance;
+ };
+
+ bootstrap_analysis analyse_samples(double confidence_level, unsigned int n_resamples, std::vector<double>::iterator first, std::vector<double>::iterator last);
+ } // namespace Detail
+ } // namespace Benchmark
+} // namespace Catch
+
+#endif // CATCH_STATS_HPP_INCLUDED
+
+#include <algorithm>
+#include <iterator>
+#include <vector>
+#include <cmath>
+
+namespace Catch {
+ namespace Benchmark {
+ namespace Detail {
+ template <typename Clock>
+ std::vector<double> resolution(int k) {
+ std::vector<TimePoint<Clock>> times;
+ times.reserve(static_cast<size_t>(k + 1));
+ std::generate_n(std::back_inserter(times), k + 1, now<Clock>{});
+
+ std::vector<double> deltas;
+ deltas.reserve(static_cast<size_t>(k));
+ std::transform(std::next(times.begin()), times.end(), times.begin(),
+ std::back_inserter(deltas),
+ [](TimePoint<Clock> a, TimePoint<Clock> b) { return static_cast<double>((a - b).count()); });
+
+ return deltas;
+ }
+
+ const auto warmup_iterations = 10000;
+ const auto warmup_time = std::chrono::milliseconds(100);
+ const auto minimum_ticks = 1000;
+ const auto warmup_seed = 10000;
+ const auto clock_resolution_estimation_time = std::chrono::milliseconds(500);
+ const auto clock_cost_estimation_time_limit = std::chrono::seconds(1);
+ const auto clock_cost_estimation_tick_limit = 100000;
+ const auto clock_cost_estimation_time = std::chrono::milliseconds(10);
+ const auto clock_cost_estimation_iterations = 10000;
+
+ template <typename Clock>
+ int warmup() {
+ return run_for_at_least<Clock>(std::chrono::duration_cast<ClockDuration<Clock>>(warmup_time), warmup_seed, &resolution<Clock>)
+ .iterations;
+ }
+ template <typename Clock>
+ EnvironmentEstimate<FloatDuration<Clock>> estimate_clock_resolution(int iterations) {
+ auto r = run_for_at_least<Clock>(std::chrono::duration_cast<ClockDuration<Clock>>(clock_resolution_estimation_time), iterations, &resolution<Clock>)
+ .result;
+ return {
+ FloatDuration<Clock>(mean(r.begin(), r.end())),
+ classify_outliers(r.begin(), r.end()),
+ };
+ }
+ template <typename Clock>
+ EnvironmentEstimate<FloatDuration<Clock>> estimate_clock_cost(FloatDuration<Clock> resolution) {
+ auto time_limit = (std::min)(
+ resolution * clock_cost_estimation_tick_limit,
+ FloatDuration<Clock>(clock_cost_estimation_time_limit));
+ auto time_clock = [](int k) {
+ return Detail::measure<Clock>([k] {
+ for (int i = 0; i < k; ++i) {
+ volatile auto ignored = Clock::now();
+ (void)ignored;
+ }
+ }).elapsed;
+ };
+ time_clock(1);
+ int iters = clock_cost_estimation_iterations;
+ auto&& r = run_for_at_least<Clock>(std::chrono::duration_cast<ClockDuration<Clock>>(clock_cost_estimation_time), iters, time_clock);
+ std::vector<double> times;
+ int nsamples = static_cast<int>(std::ceil(time_limit / r.elapsed));
+ times.reserve(static_cast<size_t>(nsamples));
+ std::generate_n(std::back_inserter(times), nsamples, [time_clock, &r] {
+ return static_cast<double>((time_clock(r.iterations) / r.iterations).count());
+ });
+ return {
+ FloatDuration<Clock>(mean(times.begin(), times.end())),
+ classify_outliers(times.begin(), times.end()),
+ };
+ }
+
+ template <typename Clock>
+ Environment<FloatDuration<Clock>> measure_environment() {
+#if defined(__clang__)
+# pragma clang diagnostic push
+# pragma clang diagnostic ignored "-Wexit-time-destructors"
+#endif
+ static Catch::Detail::unique_ptr<Environment<FloatDuration<Clock>>> env;
+#if defined(__clang__)
+# pragma clang diagnostic pop
+#endif
+ if (env) {
+ return *env;
+ }
+
+ auto iters = Detail::warmup<Clock>();
+ auto resolution = Detail::estimate_clock_resolution<Clock>(iters);
+ auto cost = Detail::estimate_clock_cost<Clock>(resolution.mean);
+
+ env = Catch::Detail::make_unique<Environment<FloatDuration<Clock>>>( Environment<FloatDuration<Clock>>{resolution, cost} );
+ return *env;
+ }
+ } // namespace Detail
+ } // namespace Benchmark
+} // namespace Catch
+
+#endif // CATCH_ESTIMATE_CLOCK_HPP_INCLUDED
+
+
+// Adapted from donated nonius code.
+
+#ifndef CATCH_ANALYSE_HPP_INCLUDED
+#define CATCH_ANALYSE_HPP_INCLUDED
+
+
+
+// Adapted from donated nonius code.
+
+#ifndef CATCH_SAMPLE_ANALYSIS_HPP_INCLUDED
+#define CATCH_SAMPLE_ANALYSIS_HPP_INCLUDED
+
+
+#include <algorithm>
+#include <vector>
+#include <iterator>
+
+namespace Catch {
+ namespace Benchmark {
+ template <typename Duration>
+ struct SampleAnalysis {
+ std::vector<Duration> samples;
+ Estimate<Duration> mean;
+ Estimate<Duration> standard_deviation;
+ OutlierClassification outliers;
+ double outlier_variance;
+
+ template <typename Duration2>
+ operator SampleAnalysis<Duration2>() const {
+ std::vector<Duration2> samples2;
+ samples2.reserve(samples.size());
+ std::transform(samples.begin(), samples.end(), std::back_inserter(samples2), [](Duration d) { return Duration2(d); });
+ return {
+ CATCH_MOVE(samples2),
+ mean,
+ standard_deviation,
+ outliers,
+ outlier_variance,
+ };
+ }
+ };
+ } // namespace Benchmark
+} // namespace Catch
+
+#endif // CATCH_SAMPLE_ANALYSIS_HPP_INCLUDED
+
+#include <algorithm>
+#include <iterator>
+#include <vector>
+
+namespace Catch {
+ namespace Benchmark {
+ namespace Detail {
+ template <typename Duration, typename Iterator>
+ SampleAnalysis<Duration> analyse(const IConfig &cfg, Environment<Duration>, Iterator first, Iterator last) {
+ if (!cfg.benchmarkNoAnalysis()) {
+ std::vector<double> samples;
+ samples.reserve(static_cast<size_t>(last - first));
+ std::transform(first, last, std::back_inserter(samples), [](Duration d) { return d.count(); });
+
+ auto analysis = Catch::Benchmark::Detail::analyse_samples(cfg.benchmarkConfidenceInterval(), cfg.benchmarkResamples(), samples.begin(), samples.end());
+ auto outliers = Catch::Benchmark::Detail::classify_outliers(samples.begin(), samples.end());
+
+ auto wrap_estimate = [](Estimate<double> e) {
+ return Estimate<Duration> {
+ Duration(e.point),
+ Duration(e.lower_bound),
+ Duration(e.upper_bound),
+ e.confidence_interval,
+ };
+ };
+ std::vector<Duration> samples2;
+ samples2.reserve(samples.size());
+ std::transform(samples.begin(), samples.end(), std::back_inserter(samples2), [](double d) { return Duration(d); });
+ return {
+ CATCH_MOVE(samples2),
+ wrap_estimate(analysis.mean),
+ wrap_estimate(analysis.standard_deviation),
+ outliers,
+ analysis.outlier_variance,
+ };
+ } else {
+ std::vector<Duration> samples;
+ samples.reserve(static_cast<size_t>(last - first));
+
+ Duration mean = Duration(0);
+ int i = 0;
+ for (auto it = first; it < last; ++it, ++i) {
+ samples.push_back(Duration(*it));
+ mean += Duration(*it);
+ }
+ mean /= i;
+
+ return {
+ CATCH_MOVE(samples),
+ Estimate<Duration>{mean, mean, mean, 0.0},
+ Estimate<Duration>{Duration(0), Duration(0), Duration(0), 0.0},
+ OutlierClassification{},
+ 0.0
+ };
+ }
+ }
+ } // namespace Detail
+ } // namespace Benchmark
+} // namespace Catch
+
+#endif // CATCH_ANALYSE_HPP_INCLUDED
+
+#include <algorithm>
+#include <functional>
+#include <string>
+#include <vector>
+#include <cmath>
+
+namespace Catch {
+ namespace Benchmark {
+ struct Benchmark {
+ Benchmark(std::string&& benchmarkName)
+ : name(CATCH_MOVE(benchmarkName)) {}
+
+ template <class FUN>
+ Benchmark(std::string&& benchmarkName , FUN &&func)
+ : fun(CATCH_MOVE(func)), name(CATCH_MOVE(benchmarkName)) {}
+
+ template <typename Clock>
+ ExecutionPlan<FloatDuration<Clock>> prepare(const IConfig &cfg, Environment<FloatDuration<Clock>> env) const {
+ auto min_time = env.clock_resolution.mean * Detail::minimum_ticks;
+ auto run_time = std::max(min_time, std::chrono::duration_cast<decltype(min_time)>(cfg.benchmarkWarmupTime()));
+ auto&& test = Detail::run_for_at_least<Clock>(std::chrono::duration_cast<ClockDuration<Clock>>(run_time), 1, fun);
+ int new_iters = static_cast<int>(std::ceil(min_time * test.iterations / test.elapsed));
+ return { new_iters, test.elapsed / test.iterations * new_iters * cfg.benchmarkSamples(), fun, std::chrono::duration_cast<FloatDuration<Clock>>(cfg.benchmarkWarmupTime()), Detail::warmup_iterations };
+ }
+
+ template <typename Clock = default_clock>
+ void run() {
+ auto const* cfg = getCurrentContext().getConfig();
+
+ auto env = Detail::measure_environment<Clock>();
+
+ getResultCapture().benchmarkPreparing(name);
+ CATCH_TRY{
+ auto plan = user_code([&] {
+ return prepare<Clock>(*cfg, env);
+ });
+
+ BenchmarkInfo info {
+ name,
+ plan.estimated_duration.count(),
+ plan.iterations_per_sample,
+ cfg->benchmarkSamples(),
+ cfg->benchmarkResamples(),
+ env.clock_resolution.mean.count(),
+ env.clock_cost.mean.count()
+ };
+
+ getResultCapture().benchmarkStarting(info);
+
+ auto samples = user_code([&] {
+ return plan.template run<Clock>(*cfg, env);
+ });
+
+ auto analysis = Detail::analyse(*cfg, env, samples.begin(), samples.end());
+ BenchmarkStats<FloatDuration<Clock>> stats{ info, analysis.samples, analysis.mean, analysis.standard_deviation, analysis.outliers, analysis.outlier_variance };
+ getResultCapture().benchmarkEnded(stats);
+ } CATCH_CATCH_ANON (TestFailureException) {
+ getResultCapture().benchmarkFailed("Benchmark failed due to failed assertion"_sr);
+ } CATCH_CATCH_ALL{
+ getResultCapture().benchmarkFailed(translateActiveException());
+ // We let the exception go further up so that the
+ // test case is marked as failed.
+ std::rethrow_exception(std::current_exception());
+ }
+ }
+
+ // sets lambda to be used in fun *and* executes benchmark!
+ template <typename Fun, std::enable_if_t<!Detail::is_related<Fun, Benchmark>::value, int> = 0>
+ Benchmark & operator=(Fun func) {
+ auto const* cfg = getCurrentContext().getConfig();
+ if (!cfg->skipBenchmarks()) {
+ fun = Detail::BenchmarkFunction(func);
+ run();
+ }
+ return *this;
+ }
+
+ explicit operator bool() {
+ return true;
+ }
+
+ private:
+ Detail::BenchmarkFunction fun;
+ std::string name;
+ };
+ }
+} // namespace Catch
+
+#define INTERNAL_CATCH_GET_1_ARG(arg1, arg2, ...) arg1
+#define INTERNAL_CATCH_GET_2_ARG(arg1, arg2, ...) arg2
+
+#define INTERNAL_CATCH_BENCHMARK(BenchmarkName, name, benchmarkIndex)\
+ if( Catch::Benchmark::Benchmark BenchmarkName{name} ) \
+ BenchmarkName = [&](int benchmarkIndex)
+
+#define INTERNAL_CATCH_BENCHMARK_ADVANCED(BenchmarkName, name)\
+ if( Catch::Benchmark::Benchmark BenchmarkName{name} ) \
+ BenchmarkName = [&]
+
+#if defined(CATCH_CONFIG_PREFIX_ALL)
+
+#define CATCH_BENCHMARK(...) \
+ INTERNAL_CATCH_BENCHMARK(INTERNAL_CATCH_UNIQUE_NAME(CATCH2_INTERNAL_BENCHMARK_), INTERNAL_CATCH_GET_1_ARG(__VA_ARGS__,,), INTERNAL_CATCH_GET_2_ARG(__VA_ARGS__,,))
+#define CATCH_BENCHMARK_ADVANCED(name) \
+ INTERNAL_CATCH_BENCHMARK_ADVANCED(INTERNAL_CATCH_UNIQUE_NAME(CATCH2_INTERNAL_BENCHMARK_), name)
+
+#else
+
+#define BENCHMARK(...) \
+ INTERNAL_CATCH_BENCHMARK(INTERNAL_CATCH_UNIQUE_NAME(CATCH2_INTERNAL_BENCHMARK_), INTERNAL_CATCH_GET_1_ARG(__VA_ARGS__,,), INTERNAL_CATCH_GET_2_ARG(__VA_ARGS__,,))
+#define BENCHMARK_ADVANCED(name) \
+ INTERNAL_CATCH_BENCHMARK_ADVANCED(INTERNAL_CATCH_UNIQUE_NAME(CATCH2_INTERNAL_BENCHMARK_), name)
+
+#endif
+
+#endif // CATCH_BENCHMARK_HPP_INCLUDED
+
+
+// Adapted from donated nonius code.
+
+#ifndef CATCH_CONSTRUCTOR_HPP_INCLUDED
+#define CATCH_CONSTRUCTOR_HPP_INCLUDED
+
+
+#include <type_traits>
+
+namespace Catch {
+ namespace Benchmark {
+ namespace Detail {
+ template <typename T, bool Destruct>
+ struct ObjectStorage
+ {
+ ObjectStorage() = default;
+
+ ObjectStorage(const ObjectStorage& other)
+ {
+ new(&data) T(other.stored_object());
+ }
+
+ ObjectStorage(ObjectStorage&& other)
+ {
+ new(data) T(CATCH_MOVE(other.stored_object()));
+ }
+
+ ~ObjectStorage() { destruct_on_exit<T>(); }
+
+ template <typename... Args>
+ void construct(Args&&... args)
+ {
+ new (data) T(CATCH_FORWARD(args)...);
+ }
+
+ template <bool AllowManualDestruction = !Destruct>
+ std::enable_if_t<AllowManualDestruction> destruct()
+ {
+ stored_object().~T();
+ }
+
+ private:
+ // If this is a constructor benchmark, destruct the underlying object
+ template <typename U>
+ void destruct_on_exit(std::enable_if_t<Destruct, U>* = nullptr) { destruct<true>(); }
+ // Otherwise, don't
+ template <typename U>
+ void destruct_on_exit(std::enable_if_t<!Destruct, U>* = nullptr) { }
+
+ T& stored_object() {
+ return *static_cast<T*>(static_cast<void*>(data));
+ }
+
+ T const& stored_object() const {
+ return *static_cast<T const*>(static_cast<void const*>(data));
+ }
+
+
+ alignas( T ) unsigned char data[sizeof( T )]{};
+ };
+ } // namespace Detail
+
+ template <typename T>
+ using storage_for = Detail::ObjectStorage<T, true>;
+
+ template <typename T>
+ using destructable_object = Detail::ObjectStorage<T, false>;
+ } // namespace Benchmark
+} // namespace Catch
+
+#endif // CATCH_CONSTRUCTOR_HPP_INCLUDED
+
+#endif // CATCH_BENCHMARK_ALL_HPP_INCLUDED
+
+
+#ifndef CATCH_APPROX_HPP_INCLUDED
+#define CATCH_APPROX_HPP_INCLUDED
+
+
+
+#ifndef CATCH_TOSTRING_HPP_INCLUDED
+#define CATCH_TOSTRING_HPP_INCLUDED
+
+
+#include <vector>
+#include <cstddef>
+#include <type_traits>
+#include <string>
+#include <string.h>
+
+
+
+
+/** \file
+ * Wrapper for the WCHAR configuration option
+ *
+ * We want to support platforms that do not provide `wchar_t`, so we
+ * sometimes have to disable providing wchar_t overloads through Catch2,
+ * e.g. the StringMaker specialization for `std::wstring`.
+ */
+
+#ifndef CATCH_CONFIG_WCHAR_HPP_INCLUDED
+#define CATCH_CONFIG_WCHAR_HPP_INCLUDED
+
+// We assume that WCHAR should be enabled by default, and only disabled
+// for a shortlist (so far only DJGPP) of compilers.
+
+#if defined(__DJGPP__)
+# define CATCH_INTERNAL_CONFIG_NO_WCHAR
+#endif // __DJGPP__
+
+#if !defined( CATCH_INTERNAL_CONFIG_NO_WCHAR ) && \
+ !defined( CATCH_CONFIG_NO_WCHAR ) && \
+ !defined( CATCH_CONFIG_WCHAR )
+# define CATCH_CONFIG_WCHAR
+#endif
+
+#endif // CATCH_CONFIG_WCHAR_HPP_INCLUDED
+
+
+#ifndef CATCH_REUSABLE_STRING_STREAM_HPP_INCLUDED
+#define CATCH_REUSABLE_STRING_STREAM_HPP_INCLUDED
+
+
+#include <iosfwd>
+#include <cstddef>
+#include <ostream>
+#include <string>
+
+namespace Catch {
+
+ class ReusableStringStream : Detail::NonCopyable {
+ std::size_t m_index;
+ std::ostream* m_oss;
+ public:
+ ReusableStringStream();
+ ~ReusableStringStream();
+
+ //! Returns the serialized state
+ std::string str() const;
+ //! Sets internal state to `str`
+ void str(std::string const& str);
+
+#if defined(__GNUC__) && !defined(__clang__)
+#pragma GCC diagnostic push
+// Old versions of GCC do not understand -Wnonnull-compare
+#pragma GCC diagnostic ignored "-Wpragmas"
+// Streaming a function pointer triggers Waddress and Wnonnull-compare
+// on GCC, because it implicitly converts it to bool and then decides
+// that the check it uses (a? true : false) is tautological and cannot
+// be null...
+#pragma GCC diagnostic ignored "-Waddress"
+#pragma GCC diagnostic ignored "-Wnonnull-compare"
+#endif
+
+ template<typename T>
+ auto operator << ( T const& value ) -> ReusableStringStream& {
+ *m_oss << value;
+ return *this;
+ }
+
+#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 <typename...>
+ struct make_void { using type = void; };
+
+ template <typename... Ts>
+ using void_t = typename make_void<Ts...>::type;
+
+ } // namespace Detail
+} // namespace Catch
+
+
+#endif // CATCH_VOID_TYPE_HPP_INCLUDED
+
+
+#ifndef CATCH_INTERFACES_ENUM_VALUES_REGISTRY_HPP_INCLUDED
+#define CATCH_INTERFACES_ENUM_VALUES_REGISTRY_HPP_INCLUDED
+
+
+#include <vector>
+
+namespace Catch {
+
+ namespace Detail {
+ struct EnumInfo {
+ StringRef m_name;
+ std::vector<std::pair<int, StringRef>> m_values;
+
+ ~EnumInfo();
+
+ StringRef lookup( int value ) const;
+ };
+ } // namespace Detail
+
+ class IMutableEnumValuesRegistry {
+ public:
+ virtual ~IMutableEnumValuesRegistry(); // = default;
+
+ virtual Detail::EnumInfo const& registerEnum( StringRef enumName, StringRef allEnums, std::vector<int> const& values ) = 0;
+
+ template<typename E>
+ Detail::EnumInfo const& registerEnum( StringRef enumName, StringRef allEnums, std::initializer_list<E> values ) {
+ static_assert(sizeof(int) >= sizeof(E), "Cannot serialize enum to int");
+ std::vector<int> intValues;
+ intValues.reserve( values.size() );
+ for( auto enumValue : values )
+ intValues.push_back( static_cast<int>( enumValue ) );
+ return registerEnum( enumName, allEnums, intValues );
+ }
+ };
+
+} // Catch
+
+#endif // CATCH_INTERFACES_ENUM_VALUES_REGISTRY_HPP_INCLUDED
+
+#ifdef CATCH_CONFIG_CPP17_STRING_VIEW
+#include <string_view>
+#endif
+
+#ifdef _MSC_VER
+#pragma warning(push)
+#pragma warning(disable:4180) // We attempt to stream a function (address) by const&, which MSVC complains about but is harmless
+#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);
+
+namespace Catch {
+ // Bring in global namespace operator<< for ADL lookup in
+ // `IsStreamInsertable` below.
+ using ::operator<<;
+
+ namespace Detail {
+
+
+ constexpr StringRef unprintableString = "{?}"_sr;
+
+ //! Encases `string in quotes, and optionally escapes invisibles
+ 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 );
+
+ std::string rawMemoryToString( const void *object, std::size_t size );
+
+ template<typename T>
+ std::string rawMemoryToString( const T& object ) {
+ return rawMemoryToString( &object, sizeof(object) );
+ }
+
+ template<typename T>
+ class IsStreamInsertable {
+ template<typename Stream, typename U>
+ static auto test(int)
+ -> decltype(std::declval<Stream&>() << std::declval<U>(), std::true_type());
+
+ template<typename, typename>
+ static auto test(...)->std::false_type;
+
+ public:
+ static const bool value = decltype(test<std::ostream, const T&>(0))::value;
+ };
+
+ template<typename E>
+ std::string convertUnknownEnumToString( E e );
+
+ template<typename T>
+ std::enable_if_t<
+ !std::is_enum<T>::value && !std::is_base_of<std::exception, T>::value,
+ std::string> convertUnstreamable( T const& ) {
+ return std::string(Detail::unprintableString);
+ }
+ template<typename T>
+ std::enable_if_t<
+ !std::is_enum<T>::value && std::is_base_of<std::exception, T>::value,
+ std::string> convertUnstreamable(T const& ex) {
+ return ex.what();
+ }
+
+
+ template<typename T>
+ std::enable_if_t<
+ std::is_enum<T>::value,
+ std::string> convertUnstreamable( T const& value ) {
+ return convertUnknownEnumToString( value );
+ }
+
+#if defined(_MANAGED)
+ //! Convert a CLR string to a utf8 std::string
+ template<typename T>
+ std::string clrReferenceToString( T^ ref ) {
+ if (ref == nullptr)
+ return std::string("null");
+ auto bytes = System::Text::Encoding::UTF8->GetBytes(ref->ToString());
+ cli::pin_ptr<System::Byte> p = &bytes[0];
+ return std::string(reinterpret_cast<char const *>(p), bytes->Length);
+ }
+#endif
+
+ } // namespace Detail
+
+
+ // If we decide for C++14, change these to enable_if_ts
+ template <typename T, typename = void>
+ struct StringMaker {
+ template <typename Fake = T>
+ static
+ std::enable_if_t<::Catch::Detail::IsStreamInsertable<Fake>::value, std::string>
+ convert(const Fake& value) {
+ ReusableStringStream rss;
+ // NB: call using the function-like syntax to avoid ambiguity with
+ // user-defined templated operator<< under clang.
+ rss.operator<<(value);
+ return rss.str();
+ }
+
+ template <typename Fake = T>
+ static
+ std::enable_if_t<!::Catch::Detail::IsStreamInsertable<Fake>::value, std::string>
+ convert( const Fake& value ) {
+#if !defined(CATCH_CONFIG_FALLBACK_STRINGIFIER)
+ return Detail::convertUnstreamable(value);
+#else
+ return CATCH_CONFIG_FALLBACK_STRINGIFIER(value);
+#endif
+ }
+ };
+
+ namespace Detail {
+
+ // This function dispatches all stringification requests inside of Catch.
+ // Should be preferably called fully qualified, like ::Catch::Detail::stringify
+ template <typename T>
+ std::string stringify(const T& e) {
+ return ::Catch::StringMaker<std::remove_cv_t<std::remove_reference_t<T>>>::convert(e);
+ }
+
+ template<typename E>
+ std::string convertUnknownEnumToString( E e ) {
+ return ::Catch::Detail::stringify(static_cast<std::underlying_type_t<E>>(e));
+ }
+
+#if defined(_MANAGED)
+ template <typename T>
+ std::string stringify( T^ e ) {
+ return ::Catch::StringMaker<T^>::convert(e);
+ }
+#endif
+
+ } // namespace Detail
+
+ // Some predefined specializations
+
+ template<>
+ struct StringMaker<std::string> {
+ static std::string convert(const std::string& str);
+ };
+
+#ifdef CATCH_CONFIG_CPP17_STRING_VIEW
+ template<>
+ struct StringMaker<std::string_view> {
+ static std::string convert(std::string_view str);
+ };
+#endif
+
+ template<>
+ struct StringMaker<char const *> {
+ static std::string convert(char const * str);
+ };
+ template<>
+ struct StringMaker<char *> {
+ static std::string convert(char * str);
+ };
+
+#if defined(CATCH_CONFIG_WCHAR)
+ template<>
+ struct StringMaker<std::wstring> {
+ static std::string convert(const std::wstring& wstr);
+ };
+
+# ifdef CATCH_CONFIG_CPP17_STRING_VIEW
+ template<>
+ struct StringMaker<std::wstring_view> {
+ static std::string convert(std::wstring_view str);
+ };
+# endif
+
+ template<>
+ struct StringMaker<wchar_t const *> {
+ static std::string convert(wchar_t const * str);
+ };
+ template<>
+ struct StringMaker<wchar_t *> {
+ static std::string convert(wchar_t * str);
+ };
+#endif // CATCH_CONFIG_WCHAR
+
+ template<size_t SZ>
+ struct StringMaker<char[SZ]> {
+ static std::string convert(char const* str) {
+ // Note that `strnlen` is not actually part of standard C++,
+ // but both POSIX and Windows cstdlib provide it.
+ return Detail::convertIntoString(
+ StringRef( str, strnlen( str, SZ ) ) );
+ }
+ };
+ template<size_t SZ>
+ struct StringMaker<signed char[SZ]> {
+ static std::string convert(signed char const* str) {
+ // See the plain `char const*` overload
+ auto reinterpreted = reinterpret_cast<char const*>(str);
+ return Detail::convertIntoString(
+ StringRef(reinterpreted, strnlen(reinterpreted, SZ)));
+ }
+ };
+ template<size_t SZ>
+ struct StringMaker<unsigned char[SZ]> {
+ static std::string convert(unsigned char const* str) {
+ // See the plain `char const*` overload
+ auto reinterpreted = reinterpret_cast<char const*>(str);
+ return Detail::convertIntoString(
+ StringRef(reinterpreted, strnlen(reinterpreted, SZ)));
+ }
+ };
+
+#if defined(CATCH_CONFIG_CPP17_BYTE)
+ template<>
+ struct StringMaker<std::byte> {
+ static std::string convert(std::byte value);
+ };
+#endif // defined(CATCH_CONFIG_CPP17_BYTE)
+ template<>
+ struct StringMaker<int> {
+ static std::string convert(int value);
+ };
+ template<>
+ struct StringMaker<long> {
+ static std::string convert(long value);
+ };
+ template<>
+ struct StringMaker<long long> {
+ static std::string convert(long long value);
+ };
+ template<>
+ struct StringMaker<unsigned int> {
+ static std::string convert(unsigned int value);
+ };
+ template<>
+ struct StringMaker<unsigned long> {
+ static std::string convert(unsigned long value);
+ };
+ template<>
+ struct StringMaker<unsigned long long> {
+ static std::string convert(unsigned long long value);
+ };
+
+ template<>
+ struct StringMaker<bool> {
+ static std::string convert(bool b) {
+ using namespace std::string_literals;
+ return b ? "true"s : "false"s;
+ }
+ };
+
+ template<>
+ struct StringMaker<char> {
+ static std::string convert(char c);
+ };
+ template<>
+ struct StringMaker<signed char> {
+ static std::string convert(signed char c);
+ };
+ template<>
+ struct StringMaker<unsigned char> {
+ static std::string convert(unsigned char c);
+ };
+
+ template<>
+ struct StringMaker<std::nullptr_t> {
+ static std::string convert(std::nullptr_t) {
+ using namespace std::string_literals;
+ return "nullptr"s;
+ }
+ };
+
+ template<>
+ struct StringMaker<float> {
+ static std::string convert(float value);
+ static int precision;
+ };
+
+ template<>
+ struct StringMaker<double> {
+ static std::string convert(double value);
+ static int precision;
+ };
+
+ template <typename T>
+ struct StringMaker<T*> {
+ template <typename U>
+ static std::string convert(U* p) {
+ if (p) {
+ return ::Catch::Detail::rawMemoryToString(p);
+ } else {
+ return "nullptr";
+ }
+ }
+ };
+
+ template <typename R, typename C>
+ struct StringMaker<R C::*> {
+ static std::string convert(R C::* p) {
+ if (p) {
+ return ::Catch::Detail::rawMemoryToString(p);
+ } else {
+ return "nullptr";
+ }
+ }
+ };
+
+#if defined(_MANAGED)
+ template <typename T>
+ struct StringMaker<T^> {
+ static std::string convert( T^ ref ) {
+ return ::Catch::Detail::clrReferenceToString(ref);
+ }
+ };
+#endif
+
+ namespace Detail {
+ template<typename InputIterator, typename Sentinel = InputIterator>
+ std::string rangeToString(InputIterator first, Sentinel last) {
+ ReusableStringStream rss;
+ rss << "{ ";
+ if (first != last) {
+ rss << ::Catch::Detail::stringify(*first);
+ for (++first; first != last; ++first)
+ rss << ", " << ::Catch::Detail::stringify(*first);
+ }
+ rss << " }";
+ return rss.str();
+ }
+ }
+
+} // namespace Catch
+
+//////////////////////////////////////////////////////
+// Separate std-lib types stringification, so it can be selectively enabled
+// This means that we do not bring in their headers
+
+#if defined(CATCH_CONFIG_ENABLE_ALL_STRINGMAKERS)
+# define CATCH_CONFIG_ENABLE_PAIR_STRINGMAKER
+# define CATCH_CONFIG_ENABLE_TUPLE_STRINGMAKER
+# define CATCH_CONFIG_ENABLE_VARIANT_STRINGMAKER
+# define CATCH_CONFIG_ENABLE_OPTIONAL_STRINGMAKER
+#endif
+
+// Separate std::pair specialization
+#if defined(CATCH_CONFIG_ENABLE_PAIR_STRINGMAKER)
+#include <utility>
+namespace Catch {
+ template<typename T1, typename T2>
+ struct StringMaker<std::pair<T1, T2> > {
+ static std::string convert(const std::pair<T1, T2>& pair) {
+ ReusableStringStream rss;
+ rss << "{ "
+ << ::Catch::Detail::stringify(pair.first)
+ << ", "
+ << ::Catch::Detail::stringify(pair.second)
+ << " }";
+ return rss.str();
+ }
+ };
+}
+#endif // CATCH_CONFIG_ENABLE_PAIR_STRINGMAKER
+
+#if defined(CATCH_CONFIG_ENABLE_OPTIONAL_STRINGMAKER) && defined(CATCH_CONFIG_CPP17_OPTIONAL)
+#include <optional>
+namespace Catch {
+ template<typename T>
+ struct StringMaker<std::optional<T> > {
+ static std::string convert(const std::optional<T>& optional) {
+ if (optional.has_value()) {
+ return ::Catch::Detail::stringify(*optional);
+ } else {
+ return "{ }";
+ }
+ }
+ };
+}
+#endif // CATCH_CONFIG_ENABLE_OPTIONAL_STRINGMAKER
+
+// Separate std::tuple specialization
+#if defined(CATCH_CONFIG_ENABLE_TUPLE_STRINGMAKER)
+#include <tuple>
+namespace Catch {
+ namespace Detail {
+ template<
+ typename Tuple,
+ std::size_t N = 0,
+ bool = (N < std::tuple_size<Tuple>::value)
+ >
+ struct TupleElementPrinter {
+ static void print(const Tuple& tuple, std::ostream& os) {
+ os << (N ? ", " : " ")
+ << ::Catch::Detail::stringify(std::get<N>(tuple));
+ TupleElementPrinter<Tuple, N + 1>::print(tuple, os);
+ }
+ };
+
+ template<
+ typename Tuple,
+ std::size_t N
+ >
+ struct TupleElementPrinter<Tuple, N, false> {
+ static void print(const Tuple&, std::ostream&) {}
+ };
+
+ }
+
+
+ template<typename ...Types>
+ struct StringMaker<std::tuple<Types...>> {
+ static std::string convert(const std::tuple<Types...>& tuple) {
+ ReusableStringStream rss;
+ rss << '{';
+ Detail::TupleElementPrinter<std::tuple<Types...>>::print(tuple, rss.get());
+ rss << " }";
+ return rss.str();
+ }
+ };
+}
+#endif // CATCH_CONFIG_ENABLE_TUPLE_STRINGMAKER
+
+#if defined(CATCH_CONFIG_ENABLE_VARIANT_STRINGMAKER) && defined(CATCH_CONFIG_CPP17_VARIANT)
+#include <variant>
+namespace Catch {
+ template<>
+ struct StringMaker<std::monostate> {
+ static std::string convert(const std::monostate&) {
+ return "{ }";
+ }
+ };
+
+ template<typename... Elements>
+ struct StringMaker<std::variant<Elements...>> {
+ static std::string convert(const std::variant<Elements...>& variant) {
+ if (variant.valueless_by_exception()) {
+ return "{valueless variant}";
+ } else {
+ return std::visit(
+ [](const auto& value) {
+ return ::Catch::Detail::stringify(value);
+ },
+ variant
+ );
+ }
+ }
+ };
+}
+#endif // CATCH_CONFIG_ENABLE_VARIANT_STRINGMAKER
+
+namespace Catch {
+ // Import begin/ end from std here
+ using std::begin;
+ using std::end;
+
+ namespace Detail {
+ template <typename T, typename = void>
+ struct is_range_impl : std::false_type {};
+
+ template <typename T>
+ struct is_range_impl<T, void_t<decltype(begin(std::declval<T>()))>> : std::true_type {};
+ } // namespace Detail
+
+ template <typename T>
+ struct is_range : Detail::is_range_impl<T> {};
+
+#if defined(_MANAGED) // Managed types are never ranges
+ template <typename T>
+ struct is_range<T^> {
+ static const bool value = false;
+ };
+#endif
+
+ template<typename Range>
+ std::string rangeToString( Range const& range ) {
+ return ::Catch::Detail::rangeToString( begin( range ), end( range ) );
+ }
+
+ // Handle vector<bool> specially
+ template<typename Allocator>
+ std::string rangeToString( std::vector<bool, Allocator> const& v ) {
+ ReusableStringStream rss;
+ rss << "{ ";
+ bool first = true;
+ for( bool b : v ) {
+ if( first )
+ first = false;
+ else
+ rss << ", ";
+ rss << ::Catch::Detail::stringify( b );
+ }
+ rss << " }";
+ return rss.str();
+ }
+
+ template<typename R>
+ struct StringMaker<R, std::enable_if_t<is_range<R>::value && !::Catch::Detail::IsStreamInsertable<R>::value>> {
+ static std::string convert( R const& range ) {
+ return rangeToString( range );
+ }
+ };
+
+ template <typename T, size_t SZ>
+ struct StringMaker<T[SZ]> {
+ static std::string convert(T const(&arr)[SZ]) {
+ return rangeToString(arr);
+ }
+ };
+
+
+} // namespace Catch
+
+// Separate std::chrono::duration specialization
+#include <ctime>
+#include <ratio>
+#include <chrono>
+
+
+namespace Catch {
+
+template <class Ratio>
+struct ratio_string {
+ static std::string symbol() {
+ Catch::ReusableStringStream rss;
+ rss << '[' << Ratio::num << '/'
+ << Ratio::den << ']';
+ return rss.str();
+ }
+};
+
+template <>
+struct ratio_string<std::atto> {
+ static char symbol() { return 'a'; }
+};
+template <>
+struct ratio_string<std::femto> {
+ static char symbol() { return 'f'; }
+};
+template <>
+struct ratio_string<std::pico> {
+ static char symbol() { return 'p'; }
+};
+template <>
+struct ratio_string<std::nano> {
+ static char symbol() { return 'n'; }
+};
+template <>
+struct ratio_string<std::micro> {
+ static char symbol() { return 'u'; }
+};
+template <>
+struct ratio_string<std::milli> {
+ static char symbol() { return 'm'; }
+};
+
+ ////////////
+ // std::chrono::duration specializations
+ template<typename Value, typename Ratio>
+ struct StringMaker<std::chrono::duration<Value, Ratio>> {
+ static std::string convert(std::chrono::duration<Value, Ratio> const& duration) {
+ ReusableStringStream rss;
+ rss << duration.count() << ' ' << ratio_string<Ratio>::symbol() << 's';
+ return rss.str();
+ }
+ };
+ template<typename Value>
+ struct StringMaker<std::chrono::duration<Value, std::ratio<1>>> {
+ static std::string convert(std::chrono::duration<Value, std::ratio<1>> const& duration) {
+ ReusableStringStream rss;
+ rss << duration.count() << " s";
+ return rss.str();
+ }
+ };
+ template<typename Value>
+ struct StringMaker<std::chrono::duration<Value, std::ratio<60>>> {
+ static std::string convert(std::chrono::duration<Value, std::ratio<60>> const& duration) {
+ ReusableStringStream rss;
+ rss << duration.count() << " m";
+ return rss.str();
+ }
+ };
+ template<typename Value>
+ struct StringMaker<std::chrono::duration<Value, std::ratio<3600>>> {
+ static std::string convert(std::chrono::duration<Value, std::ratio<3600>> const& duration) {
+ ReusableStringStream rss;
+ rss << duration.count() << " h";
+ return rss.str();
+ }
+ };
+
+ ////////////
+ // std::chrono::time_point specialization
+ // Generic time_point cannot be specialized, only std::chrono::time_point<system_clock>
+ template<typename Clock, typename Duration>
+ struct StringMaker<std::chrono::time_point<Clock, Duration>> {
+ static std::string convert(std::chrono::time_point<Clock, Duration> const& time_point) {
+ return ::Catch::Detail::stringify(time_point.time_since_epoch()) + " since epoch";
+ }
+ };
+ // std::chrono::time_point<system_clock> specialization
+ template<typename Duration>
+ struct StringMaker<std::chrono::time_point<std::chrono::system_clock, Duration>> {
+ static std::string convert(std::chrono::time_point<std::chrono::system_clock, Duration> const& time_point) {
+ auto converted = std::chrono::system_clock::to_time_t(time_point);
+
+#ifdef _MSC_VER
+ std::tm timeInfo = {};
+ gmtime_s(&timeInfo, &converted);
+#else
+ std::tm* timeInfo = std::gmtime(&converted);
+#endif
+
+ auto const timeStampSize = sizeof("2017-01-16T17:06:45Z");
+ char timeStamp[timeStampSize];
+ const char * const fmt = "%Y-%m-%dT%H:%M:%SZ";
+
+#ifdef _MSC_VER
+ std::strftime(timeStamp, timeStampSize, fmt, &timeInfo);
+#else
+ std::strftime(timeStamp, timeStampSize, fmt, timeInfo);
+#endif
+ return std::string(timeStamp, timeStampSize - 1);
+ }
+ };
+}
+
+
+#define INTERNAL_CATCH_REGISTER_ENUM( enumName, ... ) \
+namespace Catch { \
+ template<> struct StringMaker<enumName> { \
+ static std::string convert( enumName value ) { \
+ static const auto& enumInfo = ::Catch::getMutableRegistryHub().getMutableEnumValuesRegistry().registerEnum( #enumName, #__VA_ARGS__, { __VA_ARGS__ } ); \
+ return static_cast<std::string>(enumInfo.lookup( static_cast<int>( value ) )); \
+ } \
+ }; \
+}
+
+#define CATCH_REGISTER_ENUM( enumName, ... ) INTERNAL_CATCH_REGISTER_ENUM( enumName, __VA_ARGS__ )
+
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+
+#endif // CATCH_TOSTRING_HPP_INCLUDED
+
+#include <type_traits>
+
+namespace Catch {
+
+ class Approx {
+ private:
+ bool equalityComparisonImpl(double other) const;
+ // Sets and validates the new margin (margin >= 0)
+ void setMargin(double margin);
+ // Sets and validates the new epsilon (0 < epsilon < 1)
+ void setEpsilon(double epsilon);
+
+ public:
+ explicit Approx ( double value );
+
+ static Approx custom();
+
+ Approx operator-() const;
+
+ template <typename T, typename = std::enable_if_t<std::is_constructible<double, T>::value>>
+ Approx operator()( T const& value ) const {
+ Approx approx( static_cast<double>(value) );
+ approx.m_epsilon = m_epsilon;
+ approx.m_margin = m_margin;
+ approx.m_scale = m_scale;
+ return approx;
+ }
+
+ template <typename T, typename = std::enable_if_t<std::is_constructible<double, T>::value>>
+ explicit Approx( T const& value ): Approx(static_cast<double>(value))
+ {}
+
+
+ template <typename T, typename = std::enable_if_t<std::is_constructible<double, T>::value>>
+ friend bool operator == ( const T& lhs, Approx const& rhs ) {
+ auto lhs_v = static_cast<double>(lhs);
+ return rhs.equalityComparisonImpl(lhs_v);
+ }
+
+ template <typename T, typename = std::enable_if_t<std::is_constructible<double, T>::value>>
+ friend bool operator == ( Approx const& lhs, const T& rhs ) {
+ return operator==( rhs, lhs );
+ }
+
+ template <typename T, typename = std::enable_if_t<std::is_constructible<double, T>::value>>
+ friend bool operator != ( T const& lhs, Approx const& rhs ) {
+ return !operator==( lhs, rhs );
+ }
+
+ template <typename T, typename = std::enable_if_t<std::is_constructible<double, T>::value>>
+ friend bool operator != ( Approx const& lhs, T const& rhs ) {
+ return !operator==( rhs, lhs );
+ }
+
+ template <typename T, typename = std::enable_if_t<std::is_constructible<double, T>::value>>
+ friend bool operator <= ( T const& lhs, Approx const& rhs ) {
+ return static_cast<double>(lhs) < rhs.m_value || lhs == rhs;
+ }
+
+ template <typename T, typename = std::enable_if_t<std::is_constructible<double, T>::value>>
+ friend bool operator <= ( Approx const& lhs, T const& rhs ) {
+ return lhs.m_value < static_cast<double>(rhs) || lhs == rhs;
+ }
+
+ template <typename T, typename = std::enable_if_t<std::is_constructible<double, T>::value>>
+ friend bool operator >= ( T const& lhs, Approx const& rhs ) {
+ return static_cast<double>(lhs) > rhs.m_value || lhs == rhs;
+ }
+
+ template <typename T, typename = std::enable_if_t<std::is_constructible<double, T>::value>>
+ friend bool operator >= ( Approx const& lhs, T const& rhs ) {
+ return lhs.m_value > static_cast<double>(rhs) || lhs == rhs;
+ }
+
+ template <typename T, typename = std::enable_if_t<std::is_constructible<double, T>::value>>
+ Approx& epsilon( T const& newEpsilon ) {
+ const auto epsilonAsDouble = static_cast<double>(newEpsilon);
+ setEpsilon(epsilonAsDouble);
+ return *this;
+ }
+
+ template <typename T, typename = std::enable_if_t<std::is_constructible<double, T>::value>>
+ Approx& margin( T const& newMargin ) {
+ const auto marginAsDouble = static_cast<double>(newMargin);
+ setMargin(marginAsDouble);
+ return *this;
+ }
+
+ template <typename T, typename = std::enable_if_t<std::is_constructible<double, T>::value>>
+ Approx& scale( T const& newScale ) {
+ m_scale = static_cast<double>(newScale);
+ return *this;
+ }
+
+ std::string toString() const;
+
+ private:
+ double m_epsilon;
+ double m_margin;
+ double m_scale;
+ double m_value;
+ };
+
+namespace literals {
+ Approx operator ""_a(long double val);
+ Approx operator ""_a(unsigned long long val);
+} // end namespace literals
+
+template<>
+struct StringMaker<Catch::Approx> {
+ static std::string convert(Catch::Approx const& value);
+};
+
+} // end namespace Catch
+
+#endif // CATCH_APPROX_HPP_INCLUDED
+
+
+#ifndef CATCH_CONFIG_HPP_INCLUDED
+#define CATCH_CONFIG_HPP_INCLUDED
+
+
+
+#ifndef CATCH_TEST_SPEC_HPP_INCLUDED
+#define CATCH_TEST_SPEC_HPP_INCLUDED
+
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wpadded"
+#endif
+
+
+
+#ifndef CATCH_WILDCARD_PATTERN_HPP_INCLUDED
+#define CATCH_WILDCARD_PATTERN_HPP_INCLUDED
+
+
+
+#ifndef CATCH_CASE_SENSITIVE_HPP_INCLUDED
+#define CATCH_CASE_SENSITIVE_HPP_INCLUDED
+
+namespace Catch {
+
+ enum class CaseSensitive { Yes, No };
+
+} // namespace Catch
+
+#endif // CATCH_CASE_SENSITIVE_HPP_INCLUDED
+
+#include <string>
+
+namespace Catch
+{
+ class WildcardPattern {
+ enum WildcardPosition {
+ NoWildcard = 0,
+ WildcardAtStart = 1,
+ WildcardAtEnd = 2,
+ WildcardAtBothEnds = WildcardAtStart | WildcardAtEnd
+ };
+
+ public:
+
+ WildcardPattern( std::string const& pattern, CaseSensitive caseSensitivity );
+ bool matches( std::string const& str ) const;
+
+ private:
+ std::string normaliseString( std::string const& str ) const;
+ CaseSensitive m_caseSensitivity;
+ WildcardPosition m_wildcard = NoWildcard;
+ std::string m_pattern;
+ };
+}
+
+#endif // CATCH_WILDCARD_PATTERN_HPP_INCLUDED
+
+#include <string>
+#include <vector>
+
+namespace Catch {
+
+ class IConfig;
+ struct TestCaseInfo;
+ class TestCaseHandle;
+
+ class TestSpec {
+
+ class Pattern {
+ public:
+ explicit Pattern( std::string const& name );
+ virtual ~Pattern();
+ virtual bool matches( TestCaseInfo const& testCase ) const = 0;
+ std::string const& name() const;
+ private:
+ std::string const m_name;
+ };
+
+ class NamePattern : public Pattern {
+ public:
+ explicit NamePattern( std::string const& name, std::string const& filterString );
+ bool matches( TestCaseInfo const& testCase ) const override;
+ private:
+ WildcardPattern m_wildcardPattern;
+ };
+
+ class TagPattern : public Pattern {
+ public:
+ explicit TagPattern( std::string const& tag, std::string const& filterString );
+ bool matches( TestCaseInfo const& testCase ) const override;
+ private:
+ std::string m_tag;
+ };
+
+ struct Filter {
+ std::vector<Detail::unique_ptr<Pattern>> m_required;
+ std::vector<Detail::unique_ptr<Pattern>> m_forbidden;
+
+ bool matches( TestCaseInfo const& testCase ) const;
+ std::string name() const;
+ };
+
+ public:
+ struct FilterMatch {
+ std::string name;
+ std::vector<TestCaseHandle const*> tests;
+ };
+ using Matches = std::vector<FilterMatch>;
+ using vectorStrings = std::vector<std::string>;
+
+ bool hasFilters() const;
+ bool matches( TestCaseInfo const& testCase ) const;
+ Matches matchesByFilter( std::vector<TestCaseHandle> const& testCases, IConfig const& config ) const;
+ const vectorStrings & getInvalidSpecs() const;
+
+ private:
+ std::vector<Filter> m_filters;
+ std::vector<std::string> m_invalidSpecs;
+ friend class TestSpecParser;
+ };
+}
+
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+
+#endif // CATCH_TEST_SPEC_HPP_INCLUDED
+
+
+#ifndef CATCH_OPTIONAL_HPP_INCLUDED
+#define CATCH_OPTIONAL_HPP_INCLUDED
+
+#include <cassert>
+
+namespace Catch {
+
+ // An optional type
+ template<typename T>
+ class Optional {
+ public:
+ Optional() : nullableValue( nullptr ) {}
+ Optional( T const& _value )
+ : nullableValue( new( storage ) T( _value ) )
+ {}
+ Optional( Optional const& _other )
+ : nullableValue( _other ? new( storage ) T( *_other ) : nullptr )
+ {}
+
+ ~Optional() {
+ reset();
+ }
+
+ Optional& operator= ( Optional const& _other ) {
+ if( &_other != this ) {
+ reset();
+ if( _other )
+ nullableValue = new( storage ) T( *_other );
+ }
+ return *this;
+ }
+ Optional& operator = ( T const& _value ) {
+ reset();
+ nullableValue = new( storage ) T( _value );
+ return *this;
+ }
+
+ void reset() {
+ if( nullableValue )
+ nullableValue->~T();
+ nullableValue = nullptr;
+ }
+
+ T& operator*() {
+ assert(nullableValue);
+ return *nullableValue;
+ }
+ T const& operator*() const {
+ assert(nullableValue);
+ return *nullableValue;
+ }
+ T* operator->() {
+ assert(nullableValue);
+ return nullableValue;
+ }
+ const T* operator->() const {
+ assert(nullableValue);
+ return nullableValue;
+ }
+
+ T valueOr( T const& defaultValue ) const {
+ return nullableValue ? *nullableValue : defaultValue;
+ }
+
+ bool some() const { return nullableValue != nullptr; }
+ bool none() const { return nullableValue == nullptr; }
+
+ bool operator !() const { return nullableValue == nullptr; }
+ explicit operator bool() const {
+ return some();
+ }
+
+ friend bool operator==(Optional const& a, Optional const& b) {
+ if (a.none() && b.none()) {
+ return true;
+ } else if (a.some() && b.some()) {
+ return *a == *b;
+ } else {
+ return false;
+ }
+ }
+ friend bool operator!=(Optional const& a, Optional const& b) {
+ return !( a == b );
+ }
+
+ private:
+ T *nullableValue;
+ alignas(alignof(T)) char storage[sizeof(T)];
+ };
+
+} // end namespace Catch
+
+#endif // CATCH_OPTIONAL_HPP_INCLUDED
+
+
+#ifndef CATCH_RANDOM_SEED_GENERATION_HPP_INCLUDED
+#define CATCH_RANDOM_SEED_GENERATION_HPP_INCLUDED
+
+#include <cstdint>
+
+namespace Catch {
+
+ enum class GenerateFrom {
+ Time,
+ RandomDevice,
+ //! Currently equivalent to RandomDevice, but can change at any point
+ Default
+ };
+
+ std::uint32_t generateRandomSeed(GenerateFrom from);
+
+} // end namespace Catch
+
+#endif // CATCH_RANDOM_SEED_GENERATION_HPP_INCLUDED
+
+
+#ifndef CATCH_REPORTER_SPEC_PARSER_HPP_INCLUDED
+#define CATCH_REPORTER_SPEC_PARSER_HPP_INCLUDED
+
+
+
+#ifndef CATCH_CONSOLE_COLOUR_HPP_INCLUDED
+#define CATCH_CONSOLE_COLOUR_HPP_INCLUDED
+
+
+#include <iosfwd>
+#include <cstdint>
+
+namespace Catch {
+
+ enum class ColourMode : std::uint8_t;
+ class IStream;
+
+ struct Colour {
+ enum Code {
+ None = 0,
+
+ White,
+ Red,
+ Green,
+ Blue,
+ Cyan,
+ Yellow,
+ Grey,
+
+ Bright = 0x10,
+
+ BrightRed = Bright | Red,
+ BrightGreen = Bright | Green,
+ LightGrey = Bright | Grey,
+ BrightWhite = Bright | White,
+ BrightYellow = Bright | Yellow,
+
+ // By intention
+ FileName = LightGrey,
+ Warning = BrightYellow,
+ ResultError = BrightRed,
+ ResultSuccess = BrightGreen,
+ ResultExpectedFailure = Warning,
+
+ Error = BrightRed,
+ Success = Green,
+
+ OriginalExpression = Cyan,
+ ReconstructedExpression = BrightYellow,
+
+ SecondaryText = LightGrey,
+ Headers = White
+ };
+ };
+
+ class ColourImpl {
+ protected:
+ //! The associated stream of this ColourImpl instance
+ IStream* m_stream;
+ public:
+ ColourImpl( IStream* stream ): m_stream( stream ) {}
+
+ //! RAII wrapper around writing specific colour of text using specific
+ //! colour impl into a stream.
+ class ColourGuard {
+ ColourImpl const* m_colourImpl;
+ Colour::Code m_code;
+ bool m_engaged = false;
+
+ public:
+ //! Does **not** engage the guard/start the colour
+ ColourGuard( Colour::Code code,
+ ColourImpl const* colour );
+
+ ColourGuard( ColourGuard const& rhs ) = delete;
+ ColourGuard& operator=( ColourGuard const& rhs ) = delete;
+
+ ColourGuard( ColourGuard&& rhs ) noexcept;
+ ColourGuard& operator=( ColourGuard&& rhs ) noexcept;
+
+ //! Removes colour _if_ the guard was engaged
+ ~ColourGuard();
+
+ /**
+ * Explicitly engages colour for given stream.
+ *
+ * The API based on operator<< should be preferred.
+ */
+ ColourGuard& engage( std::ostream& stream ) &;
+ /**
+ * Explicitly engages colour for given stream.
+ *
+ * The API based on operator<< should be preferred.
+ */
+ ColourGuard&& engage( std::ostream& stream ) &&;
+
+ private:
+ //! Engages the guard and starts using colour
+ friend std::ostream& operator<<( std::ostream& lhs,
+ ColourGuard& guard ) {
+ guard.engageImpl( lhs );
+ return lhs;
+ }
+ //! Engages the guard and starts using colour
+ friend std::ostream& operator<<( std::ostream& lhs,
+ ColourGuard&& guard) {
+ guard.engageImpl( lhs );
+ return lhs;
+ }
+
+ void engageImpl( std::ostream& stream );
+
+ };
+
+ virtual ~ColourImpl(); // = default
+ /**
+ * Creates a guard object for given colour and this colour impl
+ *
+ * **Important:**
+ * the guard starts disengaged, and has to be engaged explicitly.
+ */
+ ColourGuard guardColour( Colour::Code colourCode );
+
+ private:
+ virtual void use( Colour::Code colourCode ) const = 0;
+ };
+
+ //! Provides ColourImpl based on global config and target compilation platform
+ Detail::unique_ptr<ColourImpl> makeColourImpl( ColourMode colourSelection,
+ IStream* stream );
+
+ //! Checks if specific colour impl has been compiled into the binary
+ bool isColourImplAvailable( ColourMode colourSelection );
+
+} // end namespace Catch
+
+#endif // CATCH_CONSOLE_COLOUR_HPP_INCLUDED
+
+#include <map>
+#include <string>
+#include <vector>
+
+namespace Catch {
+
+ enum class ColourMode : std::uint8_t;
+
+ namespace Detail {
+ //! Splits the reporter spec into reporter name and kv-pair options
+ std::vector<std::string> splitReporterSpec( StringRef reporterSpec );
+
+ Optional<ColourMode> stringToColourMode( StringRef colourMode );
+ }
+
+ /**
+ * Structured reporter spec that a reporter can be created from
+ *
+ * Parsing has been validated, but semantics have not. This means e.g.
+ * that the colour mode is known to Catch2, but it might not be
+ * compiled into the binary, and the output filename might not be
+ * openable.
+ */
+ class ReporterSpec {
+ std::string m_name;
+ Optional<std::string> m_outputFileName;
+ Optional<ColourMode> m_colourMode;
+ std::map<std::string, std::string> m_customOptions;
+
+ friend bool operator==( ReporterSpec const& lhs,
+ ReporterSpec const& rhs );
+ friend bool operator!=( ReporterSpec const& lhs,
+ ReporterSpec const& rhs ) {
+ return !( lhs == rhs );
+ }
+
+ public:
+ ReporterSpec(
+ std::string name,
+ Optional<std::string> outputFileName,
+ Optional<ColourMode> colourMode,
+ std::map<std::string, std::string> customOptions );
+
+ std::string const& name() const { return m_name; }
+
+ Optional<std::string> const& outputFile() const {
+ return m_outputFileName;
+ }
+
+ Optional<ColourMode> const& colourMode() const { return m_colourMode; }
+
+ std::map<std::string, std::string> const& customOptions() const {
+ return m_customOptions;
+ }
+ };
+
+ /**
+ * Parses provided reporter spec string into
+ *
+ * Returns empty optional on errors, e.g.
+ * * field that is not first and not a key+value pair
+ * * duplicated keys in kv pair
+ * * unknown catch reporter option
+ * * empty key/value in an custom kv pair
+ * * ...
+ */
+ Optional<ReporterSpec> parseReporterSpec( StringRef reporterSpec );
+
+}
+
+#endif // CATCH_REPORTER_SPEC_PARSER_HPP_INCLUDED
+
+#include <chrono>
+#include <map>
+#include <string>
+#include <vector>
+
+namespace Catch {
+
+ class IStream;
+
+ /**
+ * `ReporterSpec` but with the defaults filled in.
+ *
+ * Like `ReporterSpec`, the semantics are unchecked.
+ */
+ struct ProcessedReporterSpec {
+ std::string name;
+ std::string outputFilename;
+ ColourMode colourMode;
+ std::map<std::string, std::string> customOptions;
+ friend bool operator==( ProcessedReporterSpec const& lhs,
+ ProcessedReporterSpec const& rhs );
+ friend bool operator!=( ProcessedReporterSpec const& lhs,
+ ProcessedReporterSpec const& rhs ) {
+ return !( lhs == rhs );
+ }
+ };
+
+ struct ConfigData {
+
+ bool listTests = false;
+ bool listTags = false;
+ bool listReporters = false;
+ bool listListeners = false;
+
+ bool showSuccessfulTests = false;
+ bool shouldDebugBreak = false;
+ bool noThrow = false;
+ bool showHelp = false;
+ bool showInvisibles = false;
+ bool filenamesAsTags = false;
+ bool libIdentify = false;
+ bool allowZeroTests = false;
+
+ int abortAfter = -1;
+ uint32_t rngSeed = generateRandomSeed(GenerateFrom::Default);
+
+ unsigned int shardCount = 1;
+ unsigned int shardIndex = 0;
+
+ bool skipBenchmarks = false;
+ bool benchmarkNoAnalysis = false;
+ unsigned int benchmarkSamples = 100;
+ double benchmarkConfidenceInterval = 0.95;
+ unsigned int benchmarkResamples = 100000;
+ std::chrono::milliseconds::rep benchmarkWarmupTime = 100;
+
+ Verbosity verbosity = Verbosity::Normal;
+ WarnAbout::What warnings = WarnAbout::Nothing;
+ ShowDurations showDurations = ShowDurations::DefaultForReporter;
+ double minDuration = -1;
+ TestRunOrder runOrder = TestRunOrder::Declared;
+ ColourMode defaultColourMode = ColourMode::PlatformDefault;
+ WaitForKeypress::When waitForKeypress = WaitForKeypress::Never;
+
+ std::string defaultOutputFilename;
+ std::string name;
+ std::string processName;
+ std::vector<ReporterSpec> reporterSpecifications;
+
+ std::vector<std::string> testsOrTags;
+ std::vector<std::string> sectionsToRun;
+ };
+
+
+ class Config : public IConfig {
+ public:
+
+ Config() = default;
+ Config( ConfigData const& data );
+ ~Config() override; // = default in the cpp file
+
+ bool listTests() const;
+ bool listTags() const;
+ bool listReporters() const;
+ bool listListeners() const;
+
+ std::vector<ReporterSpec> const& getReporterSpecs() const;
+ std::vector<ProcessedReporterSpec> const&
+ getProcessedReporterSpecs() const;
+
+ std::vector<std::string> const& getTestsOrTags() const override;
+ std::vector<std::string> const& getSectionsToRun() const override;
+
+ TestSpec const& testSpec() const override;
+ bool hasTestFilters() const override;
+
+ bool showHelp() const;
+
+ // IConfig interface
+ bool allowThrows() const override;
+ StringRef name() const override;
+ bool includeSuccessfulResults() const override;
+ bool warnAboutMissingAssertions() const override;
+ bool warnAboutUnmatchedTestSpecs() const override;
+ bool zeroTestsCountAsSuccess() const override;
+ ShowDurations showDurations() const override;
+ double minDuration() const override;
+ TestRunOrder runOrder() const override;
+ uint32_t rngSeed() const override;
+ unsigned int shardCount() const override;
+ unsigned int shardIndex() const override;
+ ColourMode defaultColourMode() const override;
+ bool shouldDebugBreak() const override;
+ 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;
+ unsigned int benchmarkResamples() const override;
+ std::chrono::milliseconds benchmarkWarmupTime() const override;
+
+ private:
+ ConfigData m_data;
+ std::vector<ProcessedReporterSpec> m_processedReporterSpecs;
+ TestSpec m_testSpec;
+ bool m_hasTestFilters = false;
+ };
+} // end namespace Catch
+
+#endif // CATCH_CONFIG_HPP_INCLUDED
+
+
+#ifndef CATCH_MESSAGE_HPP_INCLUDED
+#define CATCH_MESSAGE_HPP_INCLUDED
+
+
+
+#ifndef CATCH_STREAM_END_STOP_HPP_INCLUDED
+#define CATCH_STREAM_END_STOP_HPP_INCLUDED
+
+
+namespace Catch {
+
+ // Use this in variadic streaming macros to allow
+ // << +StreamEndStop
+ // as well as
+ // << stuff +StreamEndStop
+ struct StreamEndStop {
+ StringRef operator+() const { return StringRef(); }
+
+ template <typename T>
+ friend T const& operator+( T const& value, StreamEndStop ) {
+ return value;
+ }
+ };
+
+} // namespace Catch
+
+#endif // CATCH_STREAM_END_STOP_HPP_INCLUDED
+
+#include <string>
+#include <vector>
+
+namespace Catch {
+
+ struct SourceLineInfo;
+
+ struct MessageStream {
+
+ template<typename T>
+ MessageStream& operator << ( T const& value ) {
+ m_stream << value;
+ return *this;
+ }
+
+ ReusableStringStream m_stream;
+ };
+
+ struct MessageBuilder : MessageStream {
+ MessageBuilder( StringRef macroName,
+ SourceLineInfo const& lineInfo,
+ ResultWas::OfType type ):
+ m_info(macroName, lineInfo, type) {}
+
+
+ template<typename T>
+ MessageBuilder& operator << ( T const& value ) {
+ m_stream << value;
+ return *this;
+ }
+
+ MessageInfo m_info;
+ };
+
+ class ScopedMessage {
+ public:
+ explicit ScopedMessage( MessageBuilder const& builder );
+ ScopedMessage( ScopedMessage& duplicate ) = delete;
+ ScopedMessage( ScopedMessage&& old ) noexcept;
+ ~ScopedMessage();
+
+ MessageInfo m_info;
+ bool m_moved = false;
+ };
+
+ class Capturer {
+ std::vector<MessageInfo> m_messages;
+ IResultCapture& m_resultCapture = getResultCapture();
+ size_t m_captured = 0;
+ public:
+ Capturer( StringRef macroName, SourceLineInfo const& lineInfo, ResultWas::OfType resultType, StringRef names );
+
+ Capturer(Capturer const&) = delete;
+ Capturer& operator=(Capturer const&) = delete;
+
+ ~Capturer();
+
+ void captureValue( size_t index, std::string const& value );
+
+ template<typename T>
+ void captureValues( size_t index, T const& value ) {
+ captureValue( index, Catch::Detail::stringify( value ) );
+ }
+
+ template<typename T, typename... Ts>
+ void captureValues( size_t index, T const& value, Ts const&... values ) {
+ captureValue( index, Catch::Detail::stringify(value) );
+ captureValues( index+1, values... );
+ }
+ };
+
+} // end namespace Catch
+
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CATCH_MSG( macroName, messageType, resultDisposition, ... ) \
+ do { \
+ Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, Catch::StringRef(), resultDisposition ); \
+ catchAssertionHandler.handleMessage( messageType, ( Catch::MessageStream() << __VA_ARGS__ + ::Catch::StreamEndStop() ).m_stream.str() ); \
+ INTERNAL_CATCH_REACT( catchAssertionHandler ) \
+ } while( false )
+
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CATCH_CAPTURE( varName, macroName, ... ) \
+ Catch::Capturer varName( macroName, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info, #__VA_ARGS__ ); \
+ varName.captureValues( 0, __VA_ARGS__ )
+
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CATCH_INFO( macroName, log ) \
+ Catch::ScopedMessage INTERNAL_CATCH_UNIQUE_NAME( scopedMessage )( Catch::MessageBuilder( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info ) << log )
+
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CATCH_UNSCOPED_INFO( macroName, log ) \
+ Catch::getResultCapture().emplaceUnscopedMessage( Catch::MessageBuilder( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info ) << log )
+
+
+#if defined(CATCH_CONFIG_PREFIX_ALL) && !defined(CATCH_CONFIG_DISABLE)
+
+ #define CATCH_INFO( msg ) INTERNAL_CATCH_INFO( "CATCH_INFO", msg )
+ #define CATCH_UNSCOPED_INFO( msg ) INTERNAL_CATCH_UNSCOPED_INFO( "CATCH_UNSCOPED_INFO", msg )
+ #define CATCH_WARN( msg ) INTERNAL_CATCH_MSG( "CATCH_WARN", Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, msg )
+ #define CATCH_CAPTURE( ... ) INTERNAL_CATCH_CAPTURE( INTERNAL_CATCH_UNIQUE_NAME(capturer), "CATCH_CAPTURE", __VA_ARGS__ )
+
+#elif defined(CATCH_CONFIG_PREFIX_ALL) && defined(CATCH_CONFIG_DISABLE)
+
+ #define CATCH_INFO( msg ) (void)(0)
+ #define CATCH_UNSCOPED_INFO( msg ) (void)(0)
+ #define CATCH_WARN( msg ) (void)(0)
+ #define CATCH_CAPTURE( ... ) (void)(0)
+
+#elif !defined(CATCH_CONFIG_PREFIX_ALL) && !defined(CATCH_CONFIG_DISABLE)
+
+ #define INFO( msg ) INTERNAL_CATCH_INFO( "INFO", msg )
+ #define UNSCOPED_INFO( msg ) INTERNAL_CATCH_UNSCOPED_INFO( "UNSCOPED_INFO", msg )
+ #define WARN( msg ) INTERNAL_CATCH_MSG( "WARN", Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, msg )
+ #define CAPTURE( ... ) INTERNAL_CATCH_CAPTURE( INTERNAL_CATCH_UNIQUE_NAME(capturer), "CAPTURE", __VA_ARGS__ )
+
+#elif !defined(CATCH_CONFIG_PREFIX_ALL) && defined(CATCH_CONFIG_DISABLE)
+
+ #define INFO( msg ) (void)(0)
+ #define UNSCOPED_INFO( msg ) (void)(0)
+ #define WARN( msg ) (void)(0)
+ #define CAPTURE( ... ) (void)(0)
+
+#endif // end of user facing macro declarations
+
+
+
+
+#endif // CATCH_MESSAGE_HPP_INCLUDED
+
+
+#ifndef CATCH_SESSION_HPP_INCLUDED
+#define CATCH_SESSION_HPP_INCLUDED
+
+
+
+#ifndef CATCH_COMMANDLINE_HPP_INCLUDED
+#define CATCH_COMMANDLINE_HPP_INCLUDED
+
+
+
+#ifndef CATCH_CLARA_HPP_INCLUDED
+#define CATCH_CLARA_HPP_INCLUDED
+
+#if defined( __clang__ )
+# pragma clang diagnostic push
+# pragma clang diagnostic ignored "-Wweak-vtables"
+# pragma clang diagnostic ignored "-Wshadow"
+# pragma clang diagnostic ignored "-Wdeprecated"
+#endif
+
+#if defined( __GNUC__ )
+# pragma GCC diagnostic push
+# pragma GCC diagnostic ignored "-Wsign-conversion"
+#endif
+
+#ifndef CLARA_CONFIG_OPTIONAL_TYPE
+# ifdef __has_include
+# if __has_include( <optional>) && __cplusplus >= 201703L
+# include <optional>
+# define CLARA_CONFIG_OPTIONAL_TYPE std::optional
+# endif
+# endif
+#endif
+
+
+#include <cassert>
+#include <memory>
+#include <ostream>
+#include <sstream>
+#include <string>
+#include <type_traits>
+#include <vector>
+
+namespace Catch {
+ namespace Clara {
+
+ class Args;
+ class Parser;
+
+ // enum of result types from a parse
+ enum class ParseResultType {
+ Matched,
+ NoMatch,
+ ShortCircuitAll,
+ ShortCircuitSame
+ };
+
+ struct accept_many_t {};
+ constexpr accept_many_t accept_many {};
+
+ namespace Detail {
+ struct fake_arg {
+ template <typename T>
+ operator T();
+ };
+
+ template <typename F, typename = void>
+ struct is_unary_function : std::false_type {};
+
+ template <typename F>
+ struct is_unary_function<
+ F,
+ Catch::Detail::void_t<decltype(
+ std::declval<F>()( fake_arg() ) )
+ >
+ > : std::true_type {};
+
+ // Traits for extracting arg and return type of lambdas (for single
+ // argument lambdas)
+ template <typename L>
+ struct UnaryLambdaTraits
+ : UnaryLambdaTraits<decltype( &L::operator() )> {};
+
+ template <typename ClassT, typename ReturnT, typename... Args>
+ struct UnaryLambdaTraits<ReturnT ( ClassT::* )( Args... ) const> {
+ static const bool isValid = false;
+ };
+
+ template <typename ClassT, typename ReturnT, typename ArgT>
+ struct UnaryLambdaTraits<ReturnT ( ClassT::* )( ArgT ) const> {
+ static const bool isValid = true;
+ using ArgType = std::remove_const_t<std::remove_reference_t<ArgT>>;
+ using ReturnType = ReturnT;
+ };
+
+ class TokenStream;
+
+ // 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 {
+ TokenType type;
+ std::string token;
+ };
+
+ // Abstracts iterators into args as a stream of tokens, with option
+ // arguments uniformly handled
+ class TokenStream {
+ using Iterator = std::vector<std::string>::const_iterator;
+ Iterator it;
+ Iterator itEnd;
+ std::vector<Token> m_tokenBuffer;
+
+ void loadBuffer();
+
+ public:
+ explicit TokenStream( Args const& args );
+ TokenStream( Iterator it, Iterator itEnd );
+
+ explicit operator bool() const {
+ return !m_tokenBuffer.empty() || it != itEnd;
+ }
+
+ size_t count() const {
+ return m_tokenBuffer.size() + ( itEnd - it );
+ }
+
+ Token operator*() const {
+ assert( !m_tokenBuffer.empty() );
+ return m_tokenBuffer.front();
+ }
+
+ Token const* operator->() const {
+ assert( !m_tokenBuffer.empty() );
+ return &m_tokenBuffer.front();
+ }
+
+ TokenStream& operator++();
+ };
+
+ //! Denotes type of a parsing result
+ enum class ResultType {
+ Ok, ///< No errors
+ LogicError, ///< Error in user-specified arguments for
+ ///< construction
+ RuntimeError ///< Error in parsing inputs
+ };
+
+ class ResultBase {
+ protected:
+ ResultBase( ResultType type ): m_type( type ) {}
+ virtual ~ResultBase(); // = default;
+
+
+ ResultBase(ResultBase const&) = default;
+ ResultBase& operator=(ResultBase const&) = default;
+ ResultBase(ResultBase&&) = default;
+ ResultBase& operator=(ResultBase&&) = default;
+
+ virtual void enforceOk() const = 0;
+
+ ResultType m_type;
+ };
+
+ template <typename T> class ResultValueBase : public ResultBase {
+ public:
+ auto value() const -> T const& {
+ enforceOk();
+ return m_value;
+ }
+
+ protected:
+ ResultValueBase( ResultType type ): ResultBase( type ) {}
+
+ ResultValueBase( ResultValueBase const& other ):
+ ResultBase( other ) {
+ if ( m_type == ResultType::Ok )
+ new ( &m_value ) T( other.m_value );
+ }
+
+ ResultValueBase( ResultType, T const& value ): ResultBase( ResultType::Ok ) {
+ new ( &m_value ) T( value );
+ }
+
+ auto operator=( ResultValueBase const& other )
+ -> ResultValueBase& {
+ if ( m_type == ResultType::Ok )
+ m_value.~T();
+ ResultBase::operator=( other );
+ if ( m_type == ResultType::Ok )
+ new ( &m_value ) T( other.m_value );
+ return *this;
+ }
+
+ ~ResultValueBase() override {
+ if ( m_type == ResultType::Ok )
+ m_value.~T();
+ }
+
+ union {
+ T m_value;
+ };
+ };
+
+ template <> class ResultValueBase<void> : public ResultBase {
+ protected:
+ using ResultBase::ResultBase;
+ };
+
+ template <typename T = void>
+ class BasicResult : public ResultValueBase<T> {
+ public:
+ template <typename U>
+ explicit BasicResult( BasicResult<U> const& other ):
+ ResultValueBase<T>( other.type() ),
+ m_errorMessage( other.errorMessage() ) {
+ assert( type() != ResultType::Ok );
+ }
+
+ template <typename U>
+ static auto ok( U const& value ) -> BasicResult {
+ return { ResultType::Ok, value };
+ }
+ static auto ok() -> BasicResult { return { ResultType::Ok }; }
+ static auto logicError( std::string&& message )
+ -> BasicResult {
+ return { ResultType::LogicError, CATCH_MOVE(message) };
+ }
+ static auto runtimeError( std::string&& message )
+ -> BasicResult {
+ return { ResultType::RuntimeError, CATCH_MOVE(message) };
+ }
+
+ explicit operator bool() const {
+ return m_type == ResultType::Ok;
+ }
+ auto type() const -> ResultType { return m_type; }
+ auto errorMessage() const -> std::string const& {
+ return m_errorMessage;
+ }
+
+ protected:
+ void enforceOk() const override {
+
+ // Errors shouldn't reach this point, but if they do
+ // the actual error message will be in m_errorMessage
+ assert( m_type != ResultType::LogicError );
+ assert( m_type != ResultType::RuntimeError );
+ if ( m_type != ResultType::Ok )
+ std::abort();
+ }
+
+ std::string
+ m_errorMessage; // Only populated if resultType is an error
+
+ BasicResult( ResultType type,
+ std::string&& message ):
+ ResultValueBase<T>( type ), m_errorMessage( CATCH_MOVE(message) ) {
+ assert( m_type != ResultType::Ok );
+ }
+
+ using ResultValueBase<T>::ResultValueBase;
+ using ResultBase::m_type;
+ };
+
+ class ParseState {
+ public:
+ ParseState( ParseResultType type,
+ TokenStream const& remainingTokens );
+
+ ParseResultType type() const { return m_type; }
+ TokenStream const& remainingTokens() const {
+ return m_remainingTokens;
+ }
+
+ private:
+ ParseResultType m_type;
+ TokenStream m_remainingTokens;
+ };
+
+ using Result = BasicResult<void>;
+ using ParserResult = BasicResult<ParseResultType>;
+ using InternalParseResult = BasicResult<ParseState>;
+
+ struct HelpColumns {
+ std::string left;
+ std::string right;
+ };
+
+ template <typename T>
+ ParserResult convertInto( std::string const& source, T& target ) {
+ std::stringstream ss( source );
+ ss >> target;
+ if ( ss.fail() ) {
+ return ParserResult::runtimeError(
+ "Unable to convert '" + source +
+ "' to destination type" );
+ } else {
+ return ParserResult::ok( ParseResultType::Matched );
+ }
+ }
+ ParserResult convertInto( std::string const& source,
+ std::string& target );
+ ParserResult convertInto( std::string const& source, bool& target );
+
+#ifdef CLARA_CONFIG_OPTIONAL_TYPE
+ template <typename T>
+ auto convertInto( std::string const& source,
+ CLARA_CONFIG_OPTIONAL_TYPE<T>& target )
+ -> ParserResult {
+ T temp;
+ auto result = convertInto( source, temp );
+ if ( result )
+ target = CATCH_MOVE( temp );
+ return result;
+ }
+#endif // CLARA_CONFIG_OPTIONAL_TYPE
+
+ struct BoundRef : Catch::Detail::NonCopyable {
+ virtual ~BoundRef() = default;
+ virtual bool isContainer() const;
+ virtual bool isFlag() const;
+ };
+ struct BoundValueRefBase : BoundRef {
+ virtual auto setValue( std::string const& arg )
+ -> ParserResult = 0;
+ };
+ struct BoundFlagRefBase : BoundRef {
+ virtual auto setFlag( bool flag ) -> ParserResult = 0;
+ bool isFlag() const override;
+ };
+
+ template <typename T> struct BoundValueRef : BoundValueRefBase {
+ T& m_ref;
+
+ explicit BoundValueRef( T& ref ): m_ref( ref ) {}
+
+ ParserResult setValue( std::string const& arg ) override {
+ return convertInto( arg, m_ref );
+ }
+ };
+
+ template <typename T>
+ struct BoundValueRef<std::vector<T>> : BoundValueRefBase {
+ std::vector<T>& m_ref;
+
+ explicit BoundValueRef( std::vector<T>& ref ): m_ref( ref ) {}
+
+ auto isContainer() const -> bool override { return true; }
+
+ auto setValue( std::string const& arg )
+ -> ParserResult override {
+ T temp;
+ auto result = convertInto( arg, temp );
+ if ( result )
+ m_ref.push_back( temp );
+ return result;
+ }
+ };
+
+ struct BoundFlagRef : BoundFlagRefBase {
+ bool& m_ref;
+
+ explicit BoundFlagRef( bool& ref ): m_ref( ref ) {}
+
+ ParserResult setFlag( bool flag ) override;
+ };
+
+ template <typename ReturnType> struct LambdaInvoker {
+ static_assert(
+ std::is_same<ReturnType, ParserResult>::value,
+ "Lambda must return void or clara::ParserResult" );
+
+ template <typename L, typename ArgType>
+ static auto invoke( L const& lambda, ArgType const& arg )
+ -> ParserResult {
+ return lambda( arg );
+ }
+ };
+
+ template <> struct LambdaInvoker<void> {
+ template <typename L, typename ArgType>
+ static auto invoke( L const& lambda, ArgType const& arg )
+ -> ParserResult {
+ lambda( arg );
+ return ParserResult::ok( ParseResultType::Matched );
+ }
+ };
+
+ template <typename ArgType, typename L>
+ auto invokeLambda( L const& lambda, std::string const& arg )
+ -> ParserResult {
+ ArgType temp{};
+ auto result = convertInto( arg, temp );
+ return !result ? result
+ : LambdaInvoker<typename UnaryLambdaTraits<
+ L>::ReturnType>::invoke( lambda, temp );
+ }
+
+ template <typename L> struct BoundLambda : BoundValueRefBase {
+ L m_lambda;
+
+ static_assert(
+ UnaryLambdaTraits<L>::isValid,
+ "Supplied lambda must take exactly one argument" );
+ explicit BoundLambda( L const& lambda ): m_lambda( lambda ) {}
+
+ auto setValue( std::string const& arg )
+ -> ParserResult override {
+ return invokeLambda<typename UnaryLambdaTraits<L>::ArgType>(
+ m_lambda, arg );
+ }
+ };
+
+ template <typename L> struct BoundManyLambda : BoundLambda<L> {
+ explicit BoundManyLambda( L const& lambda ): BoundLambda<L>( lambda ) {}
+ bool isContainer() const override { return true; }
+ };
+
+ template <typename L> struct BoundFlagLambda : BoundFlagRefBase {
+ L m_lambda;
+
+ static_assert(
+ UnaryLambdaTraits<L>::isValid,
+ "Supplied lambda must take exactly one argument" );
+ static_assert(
+ std::is_same<typename UnaryLambdaTraits<L>::ArgType,
+ bool>::value,
+ "flags must be boolean" );
+
+ explicit BoundFlagLambda( L const& lambda ):
+ m_lambda( lambda ) {}
+
+ auto setFlag( bool flag ) -> ParserResult override {
+ return LambdaInvoker<typename UnaryLambdaTraits<
+ L>::ReturnType>::invoke( m_lambda, flag );
+ }
+ };
+
+ enum class Optionality { Optional, Required };
+
+ class ParserBase {
+ public:
+ virtual ~ParserBase() = default;
+ virtual auto validate() const -> Result { return Result::ok(); }
+ virtual auto parse( std::string const& exeName,
+ TokenStream const& tokens ) const
+ -> InternalParseResult = 0;
+ virtual size_t cardinality() const;
+
+ InternalParseResult parse( Args const& args ) const;
+ };
+
+ template <typename DerivedT>
+ class ComposableParserImpl : public ParserBase {
+ public:
+ template <typename T>
+ auto operator|( T const& other ) const -> Parser;
+ };
+
+ // Common code and state for Args and Opts
+ template <typename DerivedT>
+ class ParserRefImpl : public ComposableParserImpl<DerivedT> {
+ protected:
+ Optionality m_optionality = Optionality::Optional;
+ std::shared_ptr<BoundRef> m_ref;
+ std::string m_hint;
+ std::string m_description;
+
+ explicit ParserRefImpl( std::shared_ptr<BoundRef> const& ref ):
+ m_ref( ref ) {}
+
+ public:
+ template <typename LambdaT>
+ ParserRefImpl( accept_many_t,
+ LambdaT const& ref,
+ std::string const& hint ):
+ m_ref( std::make_shared<BoundManyLambda<LambdaT>>( ref ) ),
+ m_hint( hint ) {}
+
+ template <typename T,
+ typename = typename std::enable_if_t<
+ !Detail::is_unary_function<T>::value>>
+ ParserRefImpl( T& ref, std::string const& hint ):
+ m_ref( std::make_shared<BoundValueRef<T>>( ref ) ),
+ m_hint( hint ) {}
+
+ template <typename LambdaT,
+ typename = typename std::enable_if_t<
+ Detail::is_unary_function<LambdaT>::value>>
+ ParserRefImpl( LambdaT const& ref, std::string const& hint ):
+ m_ref( std::make_shared<BoundLambda<LambdaT>>( ref ) ),
+ m_hint( hint ) {}
+
+ auto operator()( std::string const& description ) -> DerivedT& {
+ m_description = description;
+ return static_cast<DerivedT&>( *this );
+ }
+
+ auto optional() -> DerivedT& {
+ m_optionality = Optionality::Optional;
+ return static_cast<DerivedT&>( *this );
+ }
+
+ auto required() -> DerivedT& {
+ m_optionality = Optionality::Required;
+ return static_cast<DerivedT&>( *this );
+ }
+
+ auto isOptional() const -> bool {
+ return m_optionality == Optionality::Optional;
+ }
+
+ auto cardinality() const -> size_t override {
+ if ( m_ref->isContainer() )
+ return 0;
+ else
+ return 1;
+ }
+
+ std::string const& hint() const { return m_hint; }
+ };
+
+ } // namespace detail
+
+
+ // A parser for arguments
+ class Arg : public Detail::ParserRefImpl<Arg> {
+ public:
+ using ParserRefImpl::ParserRefImpl;
+ using ParserBase::parse;
+
+ Detail::InternalParseResult
+ parse(std::string const&,
+ Detail::TokenStream const& tokens) const override;
+ };
+
+ // A parser for options
+ class Opt : public Detail::ParserRefImpl<Opt> {
+ protected:
+ std::vector<std::string> m_optNames;
+
+ public:
+ template <typename LambdaT>
+ explicit Opt(LambdaT const& ref) :
+ ParserRefImpl(
+ std::make_shared<Detail::BoundFlagLambda<LambdaT>>(ref)) {}
+
+ explicit Opt(bool& ref);
+
+ template <typename LambdaT,
+ typename = typename std::enable_if_t<
+ Detail::is_unary_function<LambdaT>::value>>
+ Opt( LambdaT const& ref, std::string const& hint ):
+ ParserRefImpl( ref, hint ) {}
+
+ template <typename LambdaT>
+ Opt( accept_many_t, LambdaT const& ref, std::string const& hint ):
+ ParserRefImpl( accept_many, ref, hint ) {}
+
+ template <typename T,
+ typename = typename std::enable_if_t<
+ !Detail::is_unary_function<T>::value>>
+ Opt( T& ref, std::string const& hint ):
+ ParserRefImpl( ref, hint ) {}
+
+ auto operator[](std::string const& optName) -> Opt& {
+ m_optNames.push_back(optName);
+ return *this;
+ }
+
+ std::vector<Detail::HelpColumns> getHelpColumns() const;
+
+ bool isMatch(std::string const& optToken) const;
+
+ using ParserBase::parse;
+
+ Detail::InternalParseResult
+ parse(std::string const&,
+ Detail::TokenStream const& tokens) const override;
+
+ Detail::Result validate() const override;
+ };
+
+ // Specifies the name of the executable
+ class ExeName : public Detail::ComposableParserImpl<ExeName> {
+ std::shared_ptr<std::string> m_name;
+ std::shared_ptr<Detail::BoundValueRefBase> m_ref;
+
+ public:
+ ExeName();
+ explicit ExeName(std::string& ref);
+
+ template <typename LambdaT>
+ explicit ExeName(LambdaT const& lambda) : ExeName() {
+ m_ref = std::make_shared<Detail::BoundLambda<LambdaT>>(lambda);
+ }
+
+ // The exe name is not parsed out of the normal tokens, but is
+ // handled specially
+ Detail::InternalParseResult
+ parse(std::string const&,
+ Detail::TokenStream const& tokens) const override;
+
+ std::string const& name() const { return *m_name; }
+ Detail::ParserResult set(std::string const& newName);
+ };
+
+
+ // A Combined parser
+ class Parser : Detail::ParserBase {
+ mutable ExeName m_exeName;
+ std::vector<Opt> m_options;
+ std::vector<Arg> m_args;
+
+ public:
+
+ auto operator|=(ExeName const& exeName) -> Parser& {
+ m_exeName = exeName;
+ return *this;
+ }
+
+ auto operator|=(Arg const& arg) -> Parser& {
+ m_args.push_back(arg);
+ return *this;
+ }
+
+ auto operator|=(Opt const& opt) -> Parser& {
+ m_options.push_back(opt);
+ return *this;
+ }
+
+ Parser& operator|=(Parser const& other);
+
+ template <typename T>
+ auto operator|(T const& other) const -> Parser {
+ return Parser(*this) |= other;
+ }
+
+ std::vector<Detail::HelpColumns> getHelpColumns() const;
+
+ void writeToStream(std::ostream& os) const;
+
+ friend auto operator<<(std::ostream& os, Parser const& parser)
+ -> std::ostream& {
+ parser.writeToStream(os);
+ return os;
+ }
+
+ Detail::Result validate() const override;
+
+ using ParserBase::parse;
+ Detail::InternalParseResult
+ parse(std::string const& exeName,
+ Detail::TokenStream const& tokens) const override;
+ };
+
+ // Transport for raw args (copied from main args, or supplied via
+ // init list for testing)
+ class Args {
+ friend Detail::TokenStream;
+ std::string m_exeName;
+ std::vector<std::string> m_args;
+
+ public:
+ Args(int argc, char const* const* argv);
+ Args(std::initializer_list<std::string> args);
+
+ std::string const& exeName() const { return m_exeName; }
+ };
+
+
+ // Convenience wrapper for option parser that specifies the help option
+ struct Help : Opt {
+ Help(bool& showHelpFlag);
+ };
+
+ // Result type for parser operation
+ using Detail::ParserResult;
+
+ namespace Detail {
+ template <typename DerivedT>
+ template <typename T>
+ Parser
+ ComposableParserImpl<DerivedT>::operator|(T const& other) const {
+ return Parser() | static_cast<DerivedT const&>(*this) | other;
+ }
+ }
+
+ } // namespace Clara
+} // namespace Catch
+
+#if defined( __clang__ )
+# pragma clang diagnostic pop
+#endif
+
+#if defined( __GNUC__ )
+# pragma GCC diagnostic pop
+#endif
+
+#endif // CATCH_CLARA_HPP_INCLUDED
+
+namespace Catch {
+
+ struct ConfigData;
+
+ Clara::Parser makeCommandLineParser( ConfigData& config );
+
+} // end namespace Catch
+
+#endif // CATCH_COMMANDLINE_HPP_INCLUDED
+
+namespace Catch {
+
+ class Session : Detail::NonCopyable {
+ public:
+
+ Session();
+ ~Session();
+
+ void showHelp() const;
+ void libIdentify();
+
+ int applyCommandLine( int argc, char const * const * argv );
+ #if defined(CATCH_CONFIG_WCHAR) && defined(_WIN32) && defined(UNICODE)
+ int applyCommandLine( int argc, wchar_t const * const * argv );
+ #endif
+
+ void useConfigData( ConfigData const& configData );
+
+ template<typename CharT>
+ int run(int argc, CharT const * const argv[]) {
+ if (m_startupExceptions)
+ return 1;
+ int returnCode = applyCommandLine(argc, argv);
+ if (returnCode == 0)
+ returnCode = run();
+ return returnCode;
+ }
+
+ int run();
+
+ Clara::Parser const& cli() const;
+ void cli( Clara::Parser const& newParser );
+ ConfigData& configData();
+ Config& config();
+ private:
+ int runInternal();
+
+ Clara::Parser m_cli;
+ ConfigData m_configData;
+ Detail::unique_ptr<Config> m_config;
+ bool m_startupExceptions = false;
+ };
+
+} // end namespace Catch
+
+#endif // CATCH_SESSION_HPP_INCLUDED
+
+
+#ifndef CATCH_TAG_ALIAS_HPP_INCLUDED
+#define CATCH_TAG_ALIAS_HPP_INCLUDED
+
+
+#include <string>
+
+namespace Catch {
+
+ struct TagAlias {
+ TagAlias(std::string const& _tag, SourceLineInfo _lineInfo):
+ tag(_tag),
+ lineInfo(_lineInfo)
+ {}
+
+ std::string tag;
+ SourceLineInfo lineInfo;
+ };
+
+} // end namespace Catch
+
+#endif // CATCH_TAG_ALIAS_HPP_INCLUDED
+
+
+#ifndef CATCH_TAG_ALIAS_AUTOREGISTRAR_HPP_INCLUDED
+#define CATCH_TAG_ALIAS_AUTOREGISTRAR_HPP_INCLUDED
+
+
+namespace Catch {
+
+ struct RegistrarForTagAliases {
+ RegistrarForTagAliases( char const* alias, char const* tag, SourceLineInfo const& lineInfo );
+ };
+
+} // end namespace Catch
+
+#define CATCH_REGISTER_TAG_ALIAS( alias, spec ) \
+ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
+ CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
+ namespace{ Catch::RegistrarForTagAliases INTERNAL_CATCH_UNIQUE_NAME( AutoRegisterTagAlias )( alias, spec, CATCH_INTERNAL_LINEINFO ); } \
+ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
+
+#endif // CATCH_TAG_ALIAS_AUTOREGISTRAR_HPP_INCLUDED
+
+
+#ifndef CATCH_TEMPLATE_TEST_MACROS_HPP_INCLUDED
+#define CATCH_TEMPLATE_TEST_MACROS_HPP_INCLUDED
+
+// We need this suppression to leak, because it took until GCC 10
+// for the front end to handle local suppression via _Pragma properly
+// inside templates (so `TEMPLATE_TEST_CASE` and co).
+// **THIS IS DIFFERENT FOR STANDARD TESTS, WHERE GCC 9 IS SUFFICIENT**
+#if defined(__GNUC__) && !defined(__clang__) && !defined(__ICC) && __GNUC__ < 10
+#pragma GCC diagnostic ignored "-Wparentheses"
+#endif
+
+
+
+
+#ifndef CATCH_TEST_MACROS_HPP_INCLUDED
+#define CATCH_TEST_MACROS_HPP_INCLUDED
+
+
+
+#ifndef CATCH_TEST_MACRO_IMPL_HPP_INCLUDED
+#define CATCH_TEST_MACRO_IMPL_HPP_INCLUDED
+
+
+
+#ifndef CATCH_ASSERTION_HANDLER_HPP_INCLUDED
+#define CATCH_ASSERTION_HANDLER_HPP_INCLUDED
+
+
+
+#ifndef CATCH_DECOMPOSER_HPP_INCLUDED
+#define CATCH_DECOMPOSER_HPP_INCLUDED
+
+
+#include <iosfwd>
+
+#ifdef _MSC_VER
+#pragma warning(push)
+#pragma warning(disable:4389) // '==' : signed/unsigned mismatch
+#pragma warning(disable:4018) // more "signed/unsigned mismatch"
+#pragma warning(disable:4312) // Converting int to T* using reinterpret_cast (issue on x64 platform)
+#pragma warning(disable:4180) // qualifier applied to function type has no meaning
+#pragma warning(disable:4800) // Forcing result to true or false
+#endif
+
+#ifdef __clang__
+# pragma clang diagnostic push
+# pragma clang diagnostic ignored "-Wsign-compare"
+#elif defined __GNUC__
+# pragma GCC diagnostic push
+# pragma GCC diagnostic ignored "-Wsign-compare"
+#endif
+
+namespace Catch {
+
+ class ITransientExpression {
+ bool m_isBinaryExpression;
+ bool m_result;
+
+ public:
+ auto isBinaryExpression() const -> bool { return m_isBinaryExpression; }
+ auto getResult() const -> bool { return m_result; }
+ virtual void streamReconstructedExpression( std::ostream &os ) const = 0;
+
+ ITransientExpression( bool isBinaryExpression, bool result )
+ : m_isBinaryExpression( isBinaryExpression ),
+ m_result( result )
+ {}
+
+ ITransientExpression() = default;
+ ITransientExpression(ITransientExpression const&) = default;
+ ITransientExpression& operator=(ITransientExpression const&) = default;
+
+ // We don't actually need a virtual destructor, but many static analysers
+ // complain if it's not here :-(
+ virtual ~ITransientExpression(); // = default;
+
+ 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 );
+
+ template<typename LhsT, typename RhsT>
+ class BinaryExpr : public ITransientExpression {
+ LhsT m_lhs;
+ StringRef m_op;
+ RhsT m_rhs;
+
+ void streamReconstructedExpression( std::ostream &os ) const override {
+ formatReconstructedExpression
+ ( os, Catch::Detail::stringify( m_lhs ), m_op, Catch::Detail::stringify( m_rhs ) );
+ }
+
+ public:
+ BinaryExpr( bool comparisonResult, LhsT lhs, StringRef op, RhsT rhs )
+ : ITransientExpression{ true, comparisonResult },
+ m_lhs( lhs ),
+ m_op( op ),
+ m_rhs( rhs )
+ {}
+
+ template<typename T>
+ auto operator && ( T ) const -> BinaryExpr<LhsT, RhsT const&> const {
+ static_assert(always_false<T>::value,
+ "chained comparisons are not supported inside assertions, "
+ "wrap the expression inside parentheses, or decompose it");
+ }
+
+ template<typename T>
+ auto operator || ( T ) const -> BinaryExpr<LhsT, RhsT const&> const {
+ static_assert(always_false<T>::value,
+ "chained comparisons are not supported inside assertions, "
+ "wrap the expression inside parentheses, or decompose it");
+ }
+
+ template<typename T>
+ auto operator == ( T ) const -> BinaryExpr<LhsT, RhsT const&> const {
+ static_assert(always_false<T>::value,
+ "chained comparisons are not supported inside assertions, "
+ "wrap the expression inside parentheses, or decompose it");
+ }
+
+ template<typename T>
+ auto operator != ( T ) const -> BinaryExpr<LhsT, RhsT const&> const {
+ static_assert(always_false<T>::value,
+ "chained comparisons are not supported inside assertions, "
+ "wrap the expression inside parentheses, or decompose it");
+ }
+
+ template<typename T>
+ auto operator > ( T ) const -> BinaryExpr<LhsT, RhsT const&> const {
+ static_assert(always_false<T>::value,
+ "chained comparisons are not supported inside assertions, "
+ "wrap the expression inside parentheses, or decompose it");
+ }
+
+ template<typename T>
+ auto operator < ( T ) const -> BinaryExpr<LhsT, RhsT const&> const {
+ static_assert(always_false<T>::value,
+ "chained comparisons are not supported inside assertions, "
+ "wrap the expression inside parentheses, or decompose it");
+ }
+
+ template<typename T>
+ auto operator >= ( T ) const -> BinaryExpr<LhsT, RhsT const&> const {
+ static_assert(always_false<T>::value,
+ "chained comparisons are not supported inside assertions, "
+ "wrap the expression inside parentheses, or decompose it");
+ }
+
+ template<typename T>
+ auto operator <= ( T ) const -> BinaryExpr<LhsT, RhsT const&> const {
+ static_assert(always_false<T>::value,
+ "chained comparisons are not supported inside assertions, "
+ "wrap the expression inside parentheses, or decompose it");
+ }
+ };
+
+ template<typename LhsT>
+ class UnaryExpr : public ITransientExpression {
+ LhsT m_lhs;
+
+ void streamReconstructedExpression( std::ostream &os ) const override {
+ os << Catch::Detail::stringify( m_lhs );
+ }
+
+ public:
+ explicit UnaryExpr( LhsT lhs )
+ : ITransientExpression{ false, static_cast<bool>(lhs) },
+ m_lhs( lhs )
+ {}
+ };
+
+
+ // Specialised comparison functions to handle equality comparisons between ints and pointers (NULL deduces as an int)
+ template<typename LhsT, typename RhsT>
+ auto compareEqual( LhsT const& lhs, RhsT const& rhs ) -> bool { return static_cast<bool>(lhs == rhs); }
+ template<typename T>
+ auto compareEqual( T* const& lhs, int rhs ) -> bool { return lhs == reinterpret_cast<void const*>( rhs ); }
+ template<typename T>
+ auto compareEqual( T* const& lhs, long rhs ) -> bool { return lhs == reinterpret_cast<void const*>( rhs ); }
+ template<typename T>
+ auto compareEqual( int lhs, T* const& rhs ) -> bool { return reinterpret_cast<void const*>( lhs ) == rhs; }
+ template<typename T>
+ auto compareEqual( long lhs, T* const& rhs ) -> bool { return reinterpret_cast<void const*>( lhs ) == rhs; }
+
+ template<typename LhsT, typename RhsT>
+ auto compareNotEqual( LhsT const& lhs, RhsT&& rhs ) -> bool { return static_cast<bool>(lhs != rhs); }
+ template<typename T>
+ auto compareNotEqual( T* const& lhs, int rhs ) -> bool { return lhs != reinterpret_cast<void const*>( rhs ); }
+ template<typename T>
+ auto compareNotEqual( T* const& lhs, long rhs ) -> bool { return lhs != reinterpret_cast<void const*>( rhs ); }
+ template<typename T>
+ auto compareNotEqual( int lhs, T* const& rhs ) -> bool { return reinterpret_cast<void const*>( lhs ) != rhs; }
+ template<typename T>
+ auto compareNotEqual( long lhs, T* const& rhs ) -> bool { return reinterpret_cast<void const*>( lhs ) != rhs; }
+
+
+ template<typename LhsT>
+ class ExprLhs {
+ LhsT m_lhs;
+ public:
+ explicit ExprLhs( LhsT lhs ) : m_lhs( lhs ) {}
+
+ template<typename RhsT, std::enable_if_t<!std::is_arithmetic<std::remove_reference_t<RhsT>>::value, int> = 0>
+ friend auto operator == ( ExprLhs && lhs, RhsT && rhs ) -> BinaryExpr<LhsT, RhsT const&> {
+ return { compareEqual( lhs.m_lhs, rhs ), lhs.m_lhs, "=="_sr, rhs };
+ }
+ template<typename RhsT, std::enable_if_t<std::is_arithmetic<RhsT>::value, int> = 0>
+ friend auto operator == ( ExprLhs && lhs, RhsT rhs ) -> BinaryExpr<LhsT, RhsT> {
+ return { compareEqual( lhs.m_lhs, rhs ), lhs.m_lhs, "=="_sr, rhs };
+ }
+
+ template<typename RhsT, std::enable_if_t<!std::is_arithmetic<std::remove_reference_t<RhsT>>::value, int> = 0>
+ friend auto operator != ( ExprLhs && lhs, RhsT && rhs ) -> BinaryExpr<LhsT, RhsT const&> {
+ return { compareNotEqual( lhs.m_lhs, rhs ), lhs.m_lhs, "!="_sr, rhs };
+ }
+ template<typename RhsT, std::enable_if_t<std::is_arithmetic<RhsT>::value, int> = 0>
+ friend auto operator != ( ExprLhs && lhs, RhsT rhs ) -> BinaryExpr<LhsT, RhsT> {
+ return { compareNotEqual( lhs.m_lhs, rhs ), lhs.m_lhs, "!="_sr, rhs };
+ }
+
+ #define CATCH_INTERNAL_DEFINE_EXPRESSION_OPERATOR(op) \
+ template<typename RhsT, std::enable_if_t<!std::is_arithmetic<std::remove_reference_t<RhsT>>::value, int> = 0> \
+ friend auto operator op ( ExprLhs && lhs, RhsT && rhs ) -> BinaryExpr<LhsT, RhsT const&> { \
+ return { static_cast<bool>(lhs.m_lhs op rhs), lhs.m_lhs, #op##_sr, rhs }; \
+ } \
+ template<typename RhsT, std::enable_if_t<std::is_arithmetic<RhsT>::value, int> = 0> \
+ friend auto operator op ( ExprLhs && lhs, RhsT rhs ) -> BinaryExpr<LhsT, RhsT> { \
+ return { static_cast<bool>(lhs.m_lhs op rhs), lhs.m_lhs, #op##_sr, rhs }; \
+ }
+
+ CATCH_INTERNAL_DEFINE_EXPRESSION_OPERATOR(<)
+ CATCH_INTERNAL_DEFINE_EXPRESSION_OPERATOR(>)
+ CATCH_INTERNAL_DEFINE_EXPRESSION_OPERATOR(<=)
+ CATCH_INTERNAL_DEFINE_EXPRESSION_OPERATOR(>=)
+ CATCH_INTERNAL_DEFINE_EXPRESSION_OPERATOR(|)
+ CATCH_INTERNAL_DEFINE_EXPRESSION_OPERATOR(&)
+ CATCH_INTERNAL_DEFINE_EXPRESSION_OPERATOR(^)
+
+ #undef CATCH_INTERNAL_DEFINE_EXPRESSION_OPERATOR
+
+ template<typename RhsT>
+ friend auto operator && ( ExprLhs &&, RhsT && ) -> BinaryExpr<LhsT, RhsT const&> {
+ static_assert(always_false<RhsT>::value,
+ "operator&& is not supported inside assertions, "
+ "wrap the expression inside parentheses, or decompose it");
+ }
+
+ template<typename RhsT>
+ friend auto operator || ( ExprLhs &&, RhsT && ) -> BinaryExpr<LhsT, RhsT const&> {
+ static_assert(always_false<RhsT>::value,
+ "operator|| is not supported inside assertions, "
+ "wrap the expression inside parentheses, or decompose it");
+ }
+
+ auto makeUnaryExpr() const -> UnaryExpr<LhsT> {
+ return UnaryExpr<LhsT>{ m_lhs };
+ }
+ };
+
+ struct Decomposer {
+ template<typename T, std::enable_if_t<!std::is_arithmetic<std::remove_reference_t<T>>::value, int> = 0>
+ friend auto operator <= ( Decomposer &&, T && lhs ) -> ExprLhs<T const&> {
+ return ExprLhs<const T&>{ lhs };
+ }
+
+ template<typename T, std::enable_if_t<std::is_arithmetic<T>::value, int> = 0>
+ friend auto operator <= ( Decomposer &&, T value ) -> ExprLhs<T> {
+ return ExprLhs<T>{ value };
+ }
+ };
+
+} // end namespace Catch
+
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+#ifdef __clang__
+# pragma clang diagnostic pop
+#elif defined __GNUC__
+# pragma GCC diagnostic pop
+#endif
+
+#endif // CATCH_DECOMPOSER_HPP_INCLUDED
+
+#include <string>
+
+namespace Catch {
+
+ class IResultCapture;
+
+ struct AssertionReaction {
+ bool shouldDebugBreak = false;
+ bool shouldThrow = false;
+ };
+
+ class AssertionHandler {
+ AssertionInfo m_assertionInfo;
+ AssertionReaction m_reaction;
+ bool m_completed = false;
+ IResultCapture& m_resultCapture;
+
+ public:
+ AssertionHandler
+ ( StringRef macroName,
+ SourceLineInfo const& lineInfo,
+ StringRef capturedExpression,
+ ResultDisposition::Flags resultDisposition );
+ ~AssertionHandler() {
+ if ( !m_completed ) {
+ m_resultCapture.handleIncomplete( m_assertionInfo );
+ }
+ }
+
+
+ template<typename T>
+ void handleExpr( ExprLhs<T> const& expr ) {
+ handleExpr( expr.makeUnaryExpr() );
+ }
+ void handleExpr( ITransientExpression const& expr );
+
+ void handleMessage(ResultWas::OfType resultType, StringRef message);
+
+ void handleExceptionThrownAsExpected();
+ void handleUnexpectedExceptionNotThrown();
+ void handleExceptionNotThrownAsExpected();
+ void handleThrowingCallSkipped();
+ void handleUnexpectedInflightException();
+
+ void complete();
+ void setCompleted();
+
+ // query
+ auto allowThrows() const -> bool;
+ };
+
+ void handleExceptionMatchExpr( AssertionHandler& handler, std::string const& str, StringRef matcherString );
+
+} // namespace Catch
+
+#endif // CATCH_ASSERTION_HANDLER_HPP_INCLUDED
+
+// We need this suppression to leak, because it took until GCC 10
+// for the front end to handle local suppression via _Pragma properly
+#if defined(__GNUC__) && !defined(__clang__) && !defined(__ICC) && __GNUC__ <= 9
+ #pragma GCC diagnostic ignored "-Wparentheses"
+#endif
+
+#if !defined(CATCH_CONFIG_DISABLE)
+
+#if !defined(CATCH_CONFIG_DISABLE_STRINGIFICATION)
+ #define CATCH_INTERNAL_STRINGIFY(...) #__VA_ARGS__
+#else
+ #define CATCH_INTERNAL_STRINGIFY(...) "Disabled by CATCH_CONFIG_DISABLE_STRINGIFICATION"
+#endif
+
+#if defined(CATCH_CONFIG_FAST_COMPILE) || defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
+
+///////////////////////////////////////////////////////////////////////////////
+// Another way to speed-up compilation is to omit local try-catch for REQUIRE*
+// macros.
+#define INTERNAL_CATCH_TRY
+#define INTERNAL_CATCH_CATCH( capturer )
+
+#else // CATCH_CONFIG_FAST_COMPILE
+
+#define INTERNAL_CATCH_TRY try
+#define INTERNAL_CATCH_CATCH( handler ) catch(...) { handler.handleUnexpectedInflightException(); }
+
+#endif
+
+#define INTERNAL_CATCH_REACT( handler ) handler.complete();
+
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CATCH_TEST( macroName, resultDisposition, ... ) \
+ do { /* NOLINT(bugprone-infinite-loop) */ \
+ /* The expression should not be evaluated, but warnings should hopefully be checked */ \
+ CATCH_INTERNAL_IGNORE_BUT_WARN(__VA_ARGS__); \
+ Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__), resultDisposition ); \
+ INTERNAL_CATCH_TRY { \
+ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
+ CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \
+ catchAssertionHandler.handleExpr( Catch::Decomposer() <= __VA_ARGS__ ); \
+ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
+ } INTERNAL_CATCH_CATCH( catchAssertionHandler ) \
+ INTERNAL_CATCH_REACT( catchAssertionHandler ) \
+ } while( (void)0, (false) && static_cast<const bool&>( !!(__VA_ARGS__) ) ) // the expression here is never evaluated at runtime but it forces the compiler to give it a look
+ // The double negation silences MSVC's C4800 warning, the static_cast forces short-circuit evaluation if the type has overloaded &&.
+
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CATCH_IF( macroName, resultDisposition, ... ) \
+ INTERNAL_CATCH_TEST( macroName, resultDisposition, __VA_ARGS__ ); \
+ if( Catch::getResultCapture().lastAssertionPassed() )
+
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CATCH_ELSE( macroName, resultDisposition, ... ) \
+ INTERNAL_CATCH_TEST( macroName, resultDisposition, __VA_ARGS__ ); \
+ if( !Catch::getResultCapture().lastAssertionPassed() )
+
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CATCH_NO_THROW( macroName, resultDisposition, ... ) \
+ do { \
+ Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__), resultDisposition ); \
+ try { \
+ static_cast<void>(__VA_ARGS__); \
+ catchAssertionHandler.handleExceptionNotThrownAsExpected(); \
+ } \
+ catch( ... ) { \
+ catchAssertionHandler.handleUnexpectedInflightException(); \
+ } \
+ INTERNAL_CATCH_REACT( catchAssertionHandler ) \
+ } while( false )
+
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CATCH_THROWS( macroName, resultDisposition, ... ) \
+ do { \
+ Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__), resultDisposition); \
+ if( catchAssertionHandler.allowThrows() ) \
+ try { \
+ static_cast<void>(__VA_ARGS__); \
+ catchAssertionHandler.handleUnexpectedExceptionNotThrown(); \
+ } \
+ catch( ... ) { \
+ catchAssertionHandler.handleExceptionThrownAsExpected(); \
+ } \
+ else \
+ catchAssertionHandler.handleThrowingCallSkipped(); \
+ INTERNAL_CATCH_REACT( catchAssertionHandler ) \
+ } while( false )
+
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CATCH_THROWS_AS( macroName, exceptionType, resultDisposition, expr ) \
+ do { \
+ Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(expr) ", " CATCH_INTERNAL_STRINGIFY(exceptionType), resultDisposition ); \
+ if( catchAssertionHandler.allowThrows() ) \
+ try { \
+ static_cast<void>(expr); \
+ catchAssertionHandler.handleUnexpectedExceptionNotThrown(); \
+ } \
+ catch( exceptionType const& ) { \
+ catchAssertionHandler.handleExceptionThrownAsExpected(); \
+ } \
+ catch( ... ) { \
+ catchAssertionHandler.handleUnexpectedInflightException(); \
+ } \
+ else \
+ catchAssertionHandler.handleThrowingCallSkipped(); \
+ INTERNAL_CATCH_REACT( catchAssertionHandler ) \
+ } while( false )
+
+
+
+///////////////////////////////////////////////////////////////////////////////
+// Although this is matcher-based, it can be used with just a string
+#define INTERNAL_CATCH_THROWS_STR_MATCHES( macroName, resultDisposition, matcher, ... ) \
+ do { \
+ Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__) ", " CATCH_INTERNAL_STRINGIFY(matcher), resultDisposition ); \
+ if( catchAssertionHandler.allowThrows() ) \
+ try { \
+ static_cast<void>(__VA_ARGS__); \
+ catchAssertionHandler.handleUnexpectedExceptionNotThrown(); \
+ } \
+ catch( ... ) { \
+ Catch::handleExceptionMatchExpr( catchAssertionHandler, matcher, #matcher##_catch_sr ); \
+ } \
+ else \
+ catchAssertionHandler.handleThrowingCallSkipped(); \
+ INTERNAL_CATCH_REACT( catchAssertionHandler ) \
+ } while( false )
+
+#endif // CATCH_CONFIG_DISABLE
+
+#endif // CATCH_TEST_MACRO_IMPL_HPP_INCLUDED
+
+
+#ifndef CATCH_SECTION_HPP_INCLUDED
+#define CATCH_SECTION_HPP_INCLUDED
+
+
+
+#ifndef CATCH_TIMER_HPP_INCLUDED
+#define CATCH_TIMER_HPP_INCLUDED
+
+#include <cstdint>
+
+namespace Catch {
+
+ class Timer {
+ uint64_t m_nanoseconds = 0;
+ public:
+ void start();
+ auto getElapsedNanoseconds() const -> uint64_t;
+ auto getElapsedMicroseconds() const -> uint64_t;
+ auto getElapsedMilliseconds() const -> unsigned int;
+ auto getElapsedSeconds() const -> double;
+ };
+
+} // namespace Catch
+
+#endif // CATCH_TIMER_HPP_INCLUDED
+
+namespace Catch {
+
+ class Section : Detail::NonCopyable {
+ public:
+ Section( SectionInfo&& info );
+ ~Section();
+
+ // This indicates whether the section should be executed or not
+ explicit operator bool() const;
+
+ private:
+ SectionInfo m_info;
+
+ Counts m_assertions;
+ bool m_sectionIncluded;
+ Timer m_timer;
+ };
+
+} // end namespace Catch
+
+#define INTERNAL_CATCH_SECTION( ... ) \
+ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
+ CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \
+ if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::SectionInfo( CATCH_INTERNAL_LINEINFO, __VA_ARGS__ ) ) \
+ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
+
+#define INTERNAL_CATCH_DYNAMIC_SECTION( ... ) \
+ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
+ CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \
+ if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::SectionInfo( CATCH_INTERNAL_LINEINFO, (Catch::ReusableStringStream() << __VA_ARGS__).str() ) ) \
+ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
+
+#endif // CATCH_SECTION_HPP_INCLUDED
+
+
+#ifndef CATCH_TEST_REGISTRY_HPP_INCLUDED
+#define CATCH_TEST_REGISTRY_HPP_INCLUDED
+
+
+
+#ifndef CATCH_INTERFACES_TESTCASE_HPP_INCLUDED
+#define CATCH_INTERFACES_TESTCASE_HPP_INCLUDED
+
+#include <vector>
+
+namespace Catch {
+
+ class TestSpec;
+ struct TestCaseInfo;
+
+ class ITestInvoker {
+ public:
+ virtual void invoke () const = 0;
+ virtual ~ITestInvoker(); // = default
+ };
+
+ class TestCaseHandle;
+ class IConfig;
+
+ class ITestCaseRegistry {
+ public:
+ virtual ~ITestCaseRegistry(); // = default
+ // TODO: this exists only for adding filenames to test cases -- let's expose this in a saner way later
+ virtual std::vector<TestCaseInfo* > const& getAllInfos() const = 0;
+ virtual std::vector<TestCaseHandle> const& getAllTests() const = 0;
+ virtual std::vector<TestCaseHandle> const& getAllTestsSorted( IConfig const& config ) const = 0;
+ };
+
+ bool isThrowSafe( TestCaseHandle const& testCase, IConfig const& config );
+ bool matchTest( TestCaseHandle const& testCase, TestSpec const& testSpec, IConfig const& config );
+ std::vector<TestCaseHandle> filterTests( std::vector<TestCaseHandle> const& testCases, TestSpec const& testSpec, IConfig const& config );
+ std::vector<TestCaseHandle> const& getAllTestCasesSorted( IConfig const& config );
+
+}
+
+#endif // CATCH_INTERFACES_TESTCASE_HPP_INCLUDED
+
+
+#ifndef CATCH_PREPROCESSOR_REMOVE_PARENS_HPP_INCLUDED
+#define CATCH_PREPROCESSOR_REMOVE_PARENS_HPP_INCLUDED
+
+#define INTERNAL_CATCH_EXPAND1( param ) INTERNAL_CATCH_EXPAND2( param )
+#define INTERNAL_CATCH_EXPAND2( ... ) INTERNAL_CATCH_NO##__VA_ARGS__
+#define INTERNAL_CATCH_DEF( ... ) INTERNAL_CATCH_DEF __VA_ARGS__
+#define INTERNAL_CATCH_NOINTERNAL_CATCH_DEF
+
+#define INTERNAL_CATCH_REMOVE_PARENS( ... ) \
+ INTERNAL_CATCH_EXPAND1( INTERNAL_CATCH_DEF __VA_ARGS__ )
+
+#endif // CATCH_PREPROCESSOR_REMOVE_PARENS_HPP_INCLUDED
+
+// GCC 5 and older do not properly handle disabling unused-variable warning
+// with a _Pragma. This means that we have to leak the suppression to the
+// user code as well :-(
+#if defined(__GNUC__) && !defined(__clang__) && __GNUC__ <= 5
+#pragma GCC diagnostic ignored "-Wunused-variable"
+#endif
+
+
+
+namespace Catch {
+
+template<typename C>
+class TestInvokerAsMethod : public ITestInvoker {
+ void (C::*m_testAsMethod)();
+public:
+ TestInvokerAsMethod( void (C::*testAsMethod)() ) noexcept : m_testAsMethod( testAsMethod ) {}
+
+ void invoke() const override {
+ C obj;
+ (obj.*m_testAsMethod)();
+ }
+};
+
+Detail::unique_ptr<ITestInvoker> makeTestInvoker( void(*testAsFunction)() );
+
+template<typename C>
+Detail::unique_ptr<ITestInvoker> makeTestInvoker( void (C::*testAsMethod)() ) {
+ return Detail::make_unique<TestInvokerAsMethod<C>>( testAsMethod );
+}
+
+struct NameAndTags {
+ constexpr NameAndTags( StringRef name_ = StringRef(),
+ StringRef tags_ = StringRef() ) noexcept:
+ name( name_ ), tags( tags_ ) {}
+ StringRef name;
+ StringRef tags;
+};
+
+struct AutoReg : Detail::NonCopyable {
+ AutoReg( Detail::unique_ptr<ITestInvoker> invoker, SourceLineInfo const& lineInfo, StringRef classOrMethod, NameAndTags const& nameAndTags ) noexcept;
+};
+
+} // end namespace Catch
+
+#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(); \
+ }; \
+ } \
+ void TestName::test()
+#endif
+
+ ///////////////////////////////////////////////////////////////////////////////
+ #define INTERNAL_CATCH_TESTCASE2( TestName, ... ) \
+ static void TestName(); \
+ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
+ CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
+ CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \
+ namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( Catch::makeTestInvoker( &TestName ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ __VA_ARGS__ } ); } /* NOLINT */ \
+ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
+ static void TestName()
+ #define INTERNAL_CATCH_TESTCASE( ... ) \
+ INTERNAL_CATCH_TESTCASE2( INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEST_ ), __VA_ARGS__ )
+
+ ///////////////////////////////////////////////////////////////////////////////
+ #define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, ... ) \
+ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
+ CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
+ CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \
+ namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( Catch::makeTestInvoker( &QualifiedMethod ), CATCH_INTERNAL_LINEINFO, "&" #QualifiedMethod, Catch::NameAndTags{ __VA_ARGS__ } ); } /* NOLINT */ \
+ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
+
+ ///////////////////////////////////////////////////////////////////////////////
+ #define INTERNAL_CATCH_TEST_CASE_METHOD2( TestName, ClassName, ... )\
+ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
+ CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
+ CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_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_REGISTER_TESTCASE( Function, ... ) \
+ do { \
+ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
+ CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
+ CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_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
+
+
+// All of our user-facing macros support configuration toggle, that
+// forces them to be defined prefixed with CATCH_. We also like to
+// support another toggle that can minimize (disable) their implementation.
+// Given this, we have 4 different configuration options below
+
+#if defined(CATCH_CONFIG_PREFIX_ALL) && !defined(CATCH_CONFIG_DISABLE)
+
+ #define CATCH_REQUIRE( ... ) INTERNAL_CATCH_TEST( "CATCH_REQUIRE", Catch::ResultDisposition::Normal, __VA_ARGS__ )
+ #define CATCH_REQUIRE_FALSE( ... ) INTERNAL_CATCH_TEST( "CATCH_REQUIRE_FALSE", Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, __VA_ARGS__ )
+
+ #define CATCH_REQUIRE_THROWS( ... ) INTERNAL_CATCH_THROWS( "CATCH_REQUIRE_THROWS", Catch::ResultDisposition::Normal, __VA_ARGS__ )
+ #define CATCH_REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "CATCH_REQUIRE_THROWS_AS", exceptionType, Catch::ResultDisposition::Normal, expr )
+ #define CATCH_REQUIRE_NOTHROW( ... ) INTERNAL_CATCH_NO_THROW( "CATCH_REQUIRE_NOTHROW", Catch::ResultDisposition::Normal, __VA_ARGS__ )
+
+ #define CATCH_CHECK( ... ) INTERNAL_CATCH_TEST( "CATCH_CHECK", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
+ #define CATCH_CHECK_FALSE( ... ) INTERNAL_CATCH_TEST( "CATCH_CHECK_FALSE", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, __VA_ARGS__ )
+ #define CATCH_CHECKED_IF( ... ) INTERNAL_CATCH_IF( "CATCH_CHECKED_IF", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, __VA_ARGS__ )
+ #define CATCH_CHECKED_ELSE( ... ) INTERNAL_CATCH_ELSE( "CATCH_CHECKED_ELSE", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, __VA_ARGS__ )
+ #define CATCH_CHECK_NOFAIL( ... ) INTERNAL_CATCH_TEST( "CATCH_CHECK_NOFAIL", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, __VA_ARGS__ )
+
+ #define CATCH_CHECK_THROWS( ... ) INTERNAL_CATCH_THROWS( "CATCH_CHECK_THROWS", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
+ #define CATCH_CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "CATCH_CHECK_THROWS_AS", exceptionType, Catch::ResultDisposition::ContinueOnFailure, expr )
+ #define CATCH_CHECK_NOTHROW( ... ) INTERNAL_CATCH_NO_THROW( "CATCH_CHECK_NOTHROW", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
+
+ #define CATCH_TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ )
+ #define CATCH_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ )
+ #define CATCH_METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ )
+ #define CATCH_REGISTER_TEST_CASE( Function, ... ) INTERNAL_CATCH_REGISTER_TESTCASE( Function, __VA_ARGS__ )
+ #define CATCH_SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ )
+ #define CATCH_DYNAMIC_SECTION( ... ) INTERNAL_CATCH_DYNAMIC_SECTION( __VA_ARGS__ )
+ #define CATCH_FAIL( ... ) INTERNAL_CATCH_MSG( "CATCH_FAIL", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, __VA_ARGS__ )
+ #define CATCH_FAIL_CHECK( ... ) INTERNAL_CATCH_MSG( "CATCH_FAIL_CHECK", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
+ #define CATCH_SUCCEED( ... ) INTERNAL_CATCH_MSG( "CATCH_SUCCEED", Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
+
+
+ #if !defined(CATCH_CONFIG_RUNTIME_STATIC_REQUIRE)
+ #define CATCH_STATIC_REQUIRE( ... ) static_assert( __VA_ARGS__ , #__VA_ARGS__ ); CATCH_SUCCEED( #__VA_ARGS__ )
+ #define CATCH_STATIC_REQUIRE_FALSE( ... ) static_assert( !(__VA_ARGS__), "!(" #__VA_ARGS__ ")" ); CATCH_SUCCEED( #__VA_ARGS__ )
+ #define CATCH_STATIC_CHECK( ... ) static_assert( __VA_ARGS__ , #__VA_ARGS__ ); CATCH_SUCCEED( #__VA_ARGS__ )
+ #define CATCH_STATIC_CHECK_FALSE( ... ) static_assert( !(__VA_ARGS__), "!(" #__VA_ARGS__ ")" ); CATCH_SUCCEED( #__VA_ARGS__ )
+ #else
+ #define CATCH_STATIC_REQUIRE( ... ) CATCH_REQUIRE( __VA_ARGS__ )
+ #define CATCH_STATIC_REQUIRE_FALSE( ... ) CATCH_REQUIRE_FALSE( __VA_ARGS__ )
+ #define CATCH_STATIC_CHECK( ... ) CATCH_CHECK( __VA_ARGS__ )
+ #define CATCH_STATIC_CHECK_FALSE( ... ) CATCH_CHECK_FALSE( __VA_ARGS__ )
+ #endif
+
+
+ // "BDD-style" convenience wrappers
+ #define CATCH_SCENARIO( ... ) CATCH_TEST_CASE( "Scenario: " __VA_ARGS__ )
+ #define CATCH_SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " __VA_ARGS__ )
+ #define CATCH_GIVEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " Given: " << desc )
+ #define CATCH_AND_GIVEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( "And given: " << desc )
+ #define CATCH_WHEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " When: " << desc )
+ #define CATCH_AND_WHEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " And when: " << desc )
+ #define CATCH_THEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " Then: " << desc )
+ #define CATCH_AND_THEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " And: " << desc )
+
+#elif defined(CATCH_CONFIG_PREFIX_ALL) && defined(CATCH_CONFIG_DISABLE) // ^^ prefixed, implemented | vv prefixed, disabled
+
+ #define CATCH_REQUIRE( ... ) (void)(0)
+ #define CATCH_REQUIRE_FALSE( ... ) (void)(0)
+
+ #define CATCH_REQUIRE_THROWS( ... ) (void)(0)
+ #define CATCH_REQUIRE_THROWS_AS( expr, exceptionType ) (void)(0)
+ #define CATCH_REQUIRE_NOTHROW( ... ) (void)(0)
+
+ #define CATCH_CHECK( ... ) (void)(0)
+ #define CATCH_CHECK_FALSE( ... ) (void)(0)
+ #define CATCH_CHECKED_IF( ... ) if (__VA_ARGS__)
+ #define CATCH_CHECKED_ELSE( ... ) if (!(__VA_ARGS__))
+ #define CATCH_CHECK_NOFAIL( ... ) (void)(0)
+
+ #define CATCH_CHECK_THROWS( ... ) (void)(0)
+ #define CATCH_CHECK_THROWS_AS( expr, exceptionType ) (void)(0)
+ #define CATCH_CHECK_NOTHROW( ... ) (void)(0)
+
+ #define CATCH_TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEST_ ))
+ #define CATCH_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEST_ ))
+ #define CATCH_METHOD_AS_TEST_CASE( method, ... )
+ #define CATCH_REGISTER_TEST_CASE( Function, ... ) (void)(0)
+ #define CATCH_SECTION( ... )
+ #define CATCH_DYNAMIC_SECTION( ... )
+ #define CATCH_FAIL( ... ) (void)(0)
+ #define CATCH_FAIL_CHECK( ... ) (void)(0)
+ #define CATCH_SUCCEED( ... ) (void)(0)
+
+ #define CATCH_STATIC_REQUIRE( ... ) (void)(0)
+ #define CATCH_STATIC_REQUIRE_FALSE( ... ) (void)(0)
+ #define CATCH_STATIC_CHECK( ... ) (void)(0)
+ #define CATCH_STATIC_CHECK_FALSE( ... ) (void)(0)
+
+ // "BDD-style" convenience wrappers
+ #define CATCH_SCENARIO( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEST_ ))
+ #define CATCH_SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_METHOD_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEST_ ), className )
+ #define CATCH_GIVEN( desc )
+ #define CATCH_AND_GIVEN( desc )
+ #define CATCH_WHEN( desc )
+ #define CATCH_AND_WHEN( desc )
+ #define CATCH_THEN( desc )
+ #define CATCH_AND_THEN( desc )
+
+#elif !defined(CATCH_CONFIG_PREFIX_ALL) && !defined(CATCH_CONFIG_DISABLE) // ^^ prefixed, disabled | vv unprefixed, implemented
+
+ #define REQUIRE( ... ) INTERNAL_CATCH_TEST( "REQUIRE", Catch::ResultDisposition::Normal, __VA_ARGS__ )
+ #define REQUIRE_FALSE( ... ) INTERNAL_CATCH_TEST( "REQUIRE_FALSE", Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, __VA_ARGS__ )
+
+ #define REQUIRE_THROWS( ... ) INTERNAL_CATCH_THROWS( "REQUIRE_THROWS", Catch::ResultDisposition::Normal, __VA_ARGS__ )
+ #define REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "REQUIRE_THROWS_AS", exceptionType, Catch::ResultDisposition::Normal, expr )
+ #define REQUIRE_NOTHROW( ... ) INTERNAL_CATCH_NO_THROW( "REQUIRE_NOTHROW", Catch::ResultDisposition::Normal, __VA_ARGS__ )
+
+ #define CHECK( ... ) INTERNAL_CATCH_TEST( "CHECK", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
+ #define CHECK_FALSE( ... ) INTERNAL_CATCH_TEST( "CHECK_FALSE", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, __VA_ARGS__ )
+ #define CHECKED_IF( ... ) INTERNAL_CATCH_IF( "CHECKED_IF", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, __VA_ARGS__ )
+ #define CHECKED_ELSE( ... ) INTERNAL_CATCH_ELSE( "CHECKED_ELSE", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, __VA_ARGS__ )
+ #define CHECK_NOFAIL( ... ) INTERNAL_CATCH_TEST( "CHECK_NOFAIL", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, __VA_ARGS__ )
+
+ #define CHECK_THROWS( ... ) INTERNAL_CATCH_THROWS( "CHECK_THROWS", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
+ #define CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "CHECK_THROWS_AS", exceptionType, Catch::ResultDisposition::ContinueOnFailure, expr )
+ #define CHECK_NOTHROW( ... ) INTERNAL_CATCH_NO_THROW( "CHECK_NOTHROW", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
+
+ #define TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ )
+ #define TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ )
+ #define METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ )
+ #define REGISTER_TEST_CASE( Function, ... ) INTERNAL_CATCH_REGISTER_TESTCASE( Function, __VA_ARGS__ )
+ #define SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ )
+ #define DYNAMIC_SECTION( ... ) INTERNAL_CATCH_DYNAMIC_SECTION( __VA_ARGS__ )
+ #define FAIL( ... ) INTERNAL_CATCH_MSG( "FAIL", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, __VA_ARGS__ )
+ #define FAIL_CHECK( ... ) INTERNAL_CATCH_MSG( "FAIL_CHECK", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
+ #define SUCCEED( ... ) INTERNAL_CATCH_MSG( "SUCCEED", Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
+
+
+ #if !defined(CATCH_CONFIG_RUNTIME_STATIC_REQUIRE)
+ #define STATIC_REQUIRE( ... ) static_assert( __VA_ARGS__, #__VA_ARGS__ ); SUCCEED( #__VA_ARGS__ )
+ #define STATIC_REQUIRE_FALSE( ... ) static_assert( !(__VA_ARGS__), "!(" #__VA_ARGS__ ")" ); SUCCEED( "!(" #__VA_ARGS__ ")" )
+ #define STATIC_CHECK( ... ) static_assert( __VA_ARGS__, #__VA_ARGS__ ); SUCCEED( #__VA_ARGS__ )
+ #define STATIC_CHECK_FALSE( ... ) static_assert( !(__VA_ARGS__), "!(" #__VA_ARGS__ ")" ); SUCCEED( "!(" #__VA_ARGS__ ")" )
+ #else
+ #define STATIC_REQUIRE( ... ) REQUIRE( __VA_ARGS__ )
+ #define STATIC_REQUIRE_FALSE( ... ) REQUIRE_FALSE( __VA_ARGS__ )
+ #define STATIC_CHECK( ... ) CHECK( __VA_ARGS__ )
+ #define STATIC_CHECK_FALSE( ... ) CHECK_FALSE( __VA_ARGS__ )
+ #endif
+
+ // "BDD-style" convenience wrappers
+ #define SCENARIO( ... ) TEST_CASE( "Scenario: " __VA_ARGS__ )
+ #define SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " __VA_ARGS__ )
+ #define GIVEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " Given: " << desc )
+ #define AND_GIVEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( "And given: " << desc )
+ #define WHEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " When: " << desc )
+ #define AND_WHEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " And when: " << desc )
+ #define THEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " Then: " << desc )
+ #define AND_THEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " And: " << desc )
+
+#elif !defined(CATCH_CONFIG_PREFIX_ALL) && defined(CATCH_CONFIG_DISABLE) // ^^ unprefixed, implemented | vv unprefixed, disabled
+
+ #define REQUIRE( ... ) (void)(0)
+ #define REQUIRE_FALSE( ... ) (void)(0)
+
+ #define REQUIRE_THROWS( ... ) (void)(0)
+ #define REQUIRE_THROWS_AS( expr, exceptionType ) (void)(0)
+ #define REQUIRE_NOTHROW( ... ) (void)(0)
+
+ #define CHECK( ... ) (void)(0)
+ #define CHECK_FALSE( ... ) (void)(0)
+ #define CHECKED_IF( ... ) if (__VA_ARGS__)
+ #define CHECKED_ELSE( ... ) if (!(__VA_ARGS__))
+ #define CHECK_NOFAIL( ... ) (void)(0)
+
+ #define CHECK_THROWS( ... ) (void)(0)
+ #define CHECK_THROWS_AS( expr, exceptionType ) (void)(0)
+ #define CHECK_NOTHROW( ... ) (void)(0)
+
+ #define TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEST_ ), __VA_ARGS__)
+ #define TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEST_ ))
+ #define METHOD_AS_TEST_CASE( method, ... )
+ #define REGISTER_TEST_CASE( Function, ... ) (void)(0)
+ #define SECTION( ... )
+ #define DYNAMIC_SECTION( ... )
+ #define FAIL( ... ) (void)(0)
+ #define FAIL_CHECK( ... ) (void)(0)
+ #define SUCCEED( ... ) (void)(0)
+
+ #define STATIC_REQUIRE( ... ) (void)(0)
+ #define STATIC_REQUIRE_FALSE( ... ) (void)(0)
+ #define STATIC_CHECK( ... ) (void)(0)
+ #define STATIC_CHECK_FALSE( ... ) (void)(0)
+
+ // "BDD-style" convenience wrappers
+ #define SCENARIO( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEST_ ) )
+ #define SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_METHOD_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEST_ ), className )
+
+ #define GIVEN( desc )
+ #define AND_GIVEN( desc )
+ #define WHEN( desc )
+ #define AND_WHEN( desc )
+ #define THEN( desc )
+ #define AND_THEN( desc )
+
+#endif // ^^ unprefixed, disabled
+
+// end of user facing macros
+
+#endif // CATCH_TEST_MACROS_HPP_INCLUDED
+
+
+#ifndef CATCH_TEMPLATE_TEST_REGISTRY_HPP_INCLUDED
+#define CATCH_TEMPLATE_TEST_REGISTRY_HPP_INCLUDED
+
+
+
+#ifndef CATCH_PREPROCESSOR_HPP_INCLUDED
+#define CATCH_PREPROCESSOR_HPP_INCLUDED
+
+
+#if defined(__GNUC__)
+// We need to silence "empty __VA_ARGS__ warning", and using just _Pragma does not work
+#pragma GCC system_header
+#endif
+
+
+#define CATCH_RECURSION_LEVEL0(...) __VA_ARGS__
+#define CATCH_RECURSION_LEVEL1(...) CATCH_RECURSION_LEVEL0(CATCH_RECURSION_LEVEL0(CATCH_RECURSION_LEVEL0(__VA_ARGS__)))
+#define CATCH_RECURSION_LEVEL2(...) CATCH_RECURSION_LEVEL1(CATCH_RECURSION_LEVEL1(CATCH_RECURSION_LEVEL1(__VA_ARGS__)))
+#define CATCH_RECURSION_LEVEL3(...) CATCH_RECURSION_LEVEL2(CATCH_RECURSION_LEVEL2(CATCH_RECURSION_LEVEL2(__VA_ARGS__)))
+#define CATCH_RECURSION_LEVEL4(...) CATCH_RECURSION_LEVEL3(CATCH_RECURSION_LEVEL3(CATCH_RECURSION_LEVEL3(__VA_ARGS__)))
+#define CATCH_RECURSION_LEVEL5(...) CATCH_RECURSION_LEVEL4(CATCH_RECURSION_LEVEL4(CATCH_RECURSION_LEVEL4(__VA_ARGS__)))
+
+#ifdef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
+#define INTERNAL_CATCH_EXPAND_VARGS(...) __VA_ARGS__
+// MSVC needs more evaluations
+#define CATCH_RECURSION_LEVEL6(...) CATCH_RECURSION_LEVEL5(CATCH_RECURSION_LEVEL5(CATCH_RECURSION_LEVEL5(__VA_ARGS__)))
+#define CATCH_RECURSE(...) CATCH_RECURSION_LEVEL6(CATCH_RECURSION_LEVEL6(__VA_ARGS__))
+#else
+#define CATCH_RECURSE(...) CATCH_RECURSION_LEVEL5(__VA_ARGS__)
+#endif
+
+#define CATCH_REC_END(...)
+#define CATCH_REC_OUT
+
+#define CATCH_EMPTY()
+#define CATCH_DEFER(id) id CATCH_EMPTY()
+
+#define CATCH_REC_GET_END2() 0, CATCH_REC_END
+#define CATCH_REC_GET_END1(...) CATCH_REC_GET_END2
+#define CATCH_REC_GET_END(...) CATCH_REC_GET_END1
+#define CATCH_REC_NEXT0(test, next, ...) next CATCH_REC_OUT
+#define CATCH_REC_NEXT1(test, next) CATCH_DEFER ( CATCH_REC_NEXT0 ) ( test, next, 0)
+#define CATCH_REC_NEXT(test, next) CATCH_REC_NEXT1(CATCH_REC_GET_END test, next)
+
+#define CATCH_REC_LIST0(f, x, peek, ...) , f(x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1) ) ( f, peek, __VA_ARGS__ )
+#define CATCH_REC_LIST1(f, x, peek, ...) , f(x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST0) ) ( f, peek, __VA_ARGS__ )
+#define CATCH_REC_LIST2(f, x, peek, ...) f(x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1) ) ( f, peek, __VA_ARGS__ )
+
+#define CATCH_REC_LIST0_UD(f, userdata, x, peek, ...) , f(userdata, x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1_UD) ) ( f, userdata, peek, __VA_ARGS__ )
+#define CATCH_REC_LIST1_UD(f, userdata, x, peek, ...) , f(userdata, x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST0_UD) ) ( f, userdata, peek, __VA_ARGS__ )
+#define CATCH_REC_LIST2_UD(f, userdata, x, peek, ...) f(userdata, x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1_UD) ) ( f, userdata, peek, __VA_ARGS__ )
+
+// Applies the function macro `f` to each of the remaining parameters, inserts commas between the results,
+// and passes userdata as the first parameter to each invocation,
+// e.g. CATCH_REC_LIST_UD(f, x, a, b, c) evaluates to f(x, a), f(x, b), f(x, c)
+#define CATCH_REC_LIST_UD(f, userdata, ...) CATCH_RECURSE(CATCH_REC_LIST2_UD(f, userdata, __VA_ARGS__, ()()(), ()()(), ()()(), 0))
+
+#define CATCH_REC_LIST(f, ...) CATCH_RECURSE(CATCH_REC_LIST2(f, __VA_ARGS__, ()()(), ()()(), ()()(), 0))
+
+#define INTERNAL_CATCH_STRINGIZE(...) INTERNAL_CATCH_STRINGIZE2(__VA_ARGS__)
+#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
+#define INTERNAL_CATCH_STRINGIZE2(...) #__VA_ARGS__
+#define INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS(param) INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_REMOVE_PARENS(param))
+#else
+// MSVC is adding extra space and needs another indirection to expand INTERNAL_CATCH_NOINTERNAL_CATCH_DEF
+#define INTERNAL_CATCH_STRINGIZE2(...) INTERNAL_CATCH_STRINGIZE3(__VA_ARGS__)
+#define INTERNAL_CATCH_STRINGIZE3(...) #__VA_ARGS__
+#define INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS(param) (INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_REMOVE_PARENS(param)) + 1)
+#endif
+
+#define INTERNAL_CATCH_MAKE_NAMESPACE2(...) ns_##__VA_ARGS__
+#define INTERNAL_CATCH_MAKE_NAMESPACE(name) INTERNAL_CATCH_MAKE_NAMESPACE2(name)
+
+#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
+#define INTERNAL_CATCH_MAKE_TYPE_LIST2(...) decltype(get_wrapper<INTERNAL_CATCH_REMOVE_PARENS_GEN(__VA_ARGS__)>())
+#define INTERNAL_CATCH_MAKE_TYPE_LIST(...) INTERNAL_CATCH_MAKE_TYPE_LIST2(INTERNAL_CATCH_REMOVE_PARENS(__VA_ARGS__))
+#else
+#define INTERNAL_CATCH_MAKE_TYPE_LIST2(...) INTERNAL_CATCH_EXPAND_VARGS(decltype(get_wrapper<INTERNAL_CATCH_REMOVE_PARENS_GEN(__VA_ARGS__)>()))
+#define INTERNAL_CATCH_MAKE_TYPE_LIST(...) INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_MAKE_TYPE_LIST2(INTERNAL_CATCH_REMOVE_PARENS(__VA_ARGS__)))
+#endif
+
+#define INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES(...)\
+ CATCH_REC_LIST(INTERNAL_CATCH_MAKE_TYPE_LIST,__VA_ARGS__)
+
+#define INTERNAL_CATCH_REMOVE_PARENS_1_ARG(_0) INTERNAL_CATCH_REMOVE_PARENS(_0)
+#define INTERNAL_CATCH_REMOVE_PARENS_2_ARG(_0, _1) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_1_ARG(_1)
+#define INTERNAL_CATCH_REMOVE_PARENS_3_ARG(_0, _1, _2) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_2_ARG(_1, _2)
+#define INTERNAL_CATCH_REMOVE_PARENS_4_ARG(_0, _1, _2, _3) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_3_ARG(_1, _2, _3)
+#define INTERNAL_CATCH_REMOVE_PARENS_5_ARG(_0, _1, _2, _3, _4) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_4_ARG(_1, _2, _3, _4)
+#define INTERNAL_CATCH_REMOVE_PARENS_6_ARG(_0, _1, _2, _3, _4, _5) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_5_ARG(_1, _2, _3, _4, _5)
+#define INTERNAL_CATCH_REMOVE_PARENS_7_ARG(_0, _1, _2, _3, _4, _5, _6) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_6_ARG(_1, _2, _3, _4, _5, _6)
+#define INTERNAL_CATCH_REMOVE_PARENS_8_ARG(_0, _1, _2, _3, _4, _5, _6, _7) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_7_ARG(_1, _2, _3, _4, _5, _6, _7)
+#define INTERNAL_CATCH_REMOVE_PARENS_9_ARG(_0, _1, _2, _3, _4, _5, _6, _7, _8) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_8_ARG(_1, _2, _3, _4, _5, _6, _7, _8)
+#define INTERNAL_CATCH_REMOVE_PARENS_10_ARG(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_9_ARG(_1, _2, _3, _4, _5, _6, _7, _8, _9)
+#define INTERNAL_CATCH_REMOVE_PARENS_11_ARG(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_10_ARG(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10)
+
+#define INTERNAL_CATCH_VA_NARGS_IMPL(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, N, ...) N
+
+#define INTERNAL_CATCH_TYPE_GEN\
+ template<typename...> struct TypeList {};\
+ template<typename...Ts>\
+ constexpr auto get_wrapper() noexcept -> TypeList<Ts...> { return {}; }\
+ template<template<typename...> class...> struct TemplateTypeList{};\
+ template<template<typename...> class...Cs>\
+ constexpr auto get_wrapper() noexcept -> TemplateTypeList<Cs...> { return {}; }\
+ template<typename...>\
+ struct append;\
+ template<typename...>\
+ struct rewrap;\
+ template<template<typename...> class, typename...>\
+ struct create;\
+ template<template<typename...> class, typename>\
+ struct convert;\
+ \
+ template<typename T> \
+ struct append<T> { using type = T; };\
+ template< template<typename...> class L1, typename...E1, template<typename...> class L2, typename...E2, typename...Rest>\
+ struct append<L1<E1...>, L2<E2...>, Rest...> { using type = typename append<L1<E1...,E2...>, Rest...>::type; };\
+ template< template<typename...> class L1, typename...E1, typename...Rest>\
+ struct append<L1<E1...>, TypeList<mpl_::na>, Rest...> { using type = L1<E1...>; };\
+ \
+ template< template<typename...> class Container, template<typename...> class List, typename...elems>\
+ struct rewrap<TemplateTypeList<Container>, List<elems...>> { using type = TypeList<Container<elems...>>; };\
+ template< template<typename...> class Container, template<typename...> class List, class...Elems, typename...Elements>\
+ struct rewrap<TemplateTypeList<Container>, List<Elems...>, Elements...> { using type = typename append<TypeList<Container<Elems...>>, typename rewrap<TemplateTypeList<Container>, Elements...>::type>::type; };\
+ \
+ template<template <typename...> class Final, template< typename...> class...Containers, typename...Types>\
+ struct create<Final, TemplateTypeList<Containers...>, TypeList<Types...>> { using type = typename append<Final<>, typename rewrap<TemplateTypeList<Containers>, Types...>::type...>::type; };\
+ template<template <typename...> class Final, template <typename...> class List, typename...Ts>\
+ struct convert<Final, List<Ts...>> { using type = typename append<Final<>,TypeList<Ts>...>::type; };
+
+#define INTERNAL_CATCH_NTTP_1(signature, ...)\
+ template<INTERNAL_CATCH_REMOVE_PARENS(signature)> struct Nttp{};\
+ template<INTERNAL_CATCH_REMOVE_PARENS(signature)>\
+ constexpr auto get_wrapper() noexcept -> Nttp<__VA_ARGS__> { return {}; } \
+ template<template<INTERNAL_CATCH_REMOVE_PARENS(signature)> class...> struct NttpTemplateTypeList{};\
+ template<template<INTERNAL_CATCH_REMOVE_PARENS(signature)> class...Cs>\
+ constexpr auto get_wrapper() noexcept -> NttpTemplateTypeList<Cs...> { return {}; } \
+ \
+ template< template<INTERNAL_CATCH_REMOVE_PARENS(signature)> class Container, template<INTERNAL_CATCH_REMOVE_PARENS(signature)> class List, INTERNAL_CATCH_REMOVE_PARENS(signature)>\
+ struct rewrap<NttpTemplateTypeList<Container>, List<__VA_ARGS__>> { using type = TypeList<Container<__VA_ARGS__>>; };\
+ template< template<INTERNAL_CATCH_REMOVE_PARENS(signature)> class Container, template<INTERNAL_CATCH_REMOVE_PARENS(signature)> class List, INTERNAL_CATCH_REMOVE_PARENS(signature), typename...Elements>\
+ struct rewrap<NttpTemplateTypeList<Container>, List<__VA_ARGS__>, Elements...> { using type = typename append<TypeList<Container<__VA_ARGS__>>, typename rewrap<NttpTemplateTypeList<Container>, Elements...>::type>::type; };\
+ template<template <typename...> class Final, template<INTERNAL_CATCH_REMOVE_PARENS(signature)> class...Containers, typename...Types>\
+ struct create<Final, NttpTemplateTypeList<Containers...>, TypeList<Types...>> { using type = typename append<Final<>, typename rewrap<NttpTemplateTypeList<Containers>, Types...>::type...>::type; };
+
+#define INTERNAL_CATCH_DECLARE_SIG_TEST0(TestName)
+#define INTERNAL_CATCH_DECLARE_SIG_TEST1(TestName, signature)\
+ template<INTERNAL_CATCH_REMOVE_PARENS(signature)>\
+ static void TestName()
+#define INTERNAL_CATCH_DECLARE_SIG_TEST_X(TestName, signature, ...)\
+ template<INTERNAL_CATCH_REMOVE_PARENS(signature)>\
+ static void TestName()
+
+#define INTERNAL_CATCH_DEFINE_SIG_TEST0(TestName)
+#define INTERNAL_CATCH_DEFINE_SIG_TEST1(TestName, signature)\
+ template<INTERNAL_CATCH_REMOVE_PARENS(signature)>\
+ static void TestName()
+#define INTERNAL_CATCH_DEFINE_SIG_TEST_X(TestName, signature,...)\
+ template<INTERNAL_CATCH_REMOVE_PARENS(signature)>\
+ static void TestName()
+
+#define INTERNAL_CATCH_NTTP_REGISTER0(TestFunc, signature)\
+ template<typename Type>\
+ void reg_test(TypeList<Type>, Catch::NameAndTags nameAndTags)\
+ {\
+ Catch::AutoReg( Catch::makeTestInvoker(&TestFunc<Type>), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), nameAndTags);\
+ }
+
+#define INTERNAL_CATCH_NTTP_REGISTER(TestFunc, signature, ...)\
+ template<INTERNAL_CATCH_REMOVE_PARENS(signature)>\
+ void reg_test(Nttp<__VA_ARGS__>, Catch::NameAndTags nameAndTags)\
+ {\
+ Catch::AutoReg( Catch::makeTestInvoker(&TestFunc<__VA_ARGS__>), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), nameAndTags);\
+ }
+
+#define INTERNAL_CATCH_NTTP_REGISTER_METHOD0(TestName, signature, ...)\
+ template<typename Type>\
+ void reg_test(TypeList<Type>, Catch::StringRef className, Catch::NameAndTags nameAndTags)\
+ {\
+ Catch::AutoReg( Catch::makeTestInvoker(&TestName<Type>::test), CATCH_INTERNAL_LINEINFO, className, nameAndTags);\
+ }
+
+#define INTERNAL_CATCH_NTTP_REGISTER_METHOD(TestName, signature, ...)\
+ template<INTERNAL_CATCH_REMOVE_PARENS(signature)>\
+ void reg_test(Nttp<__VA_ARGS__>, Catch::StringRef className, Catch::NameAndTags nameAndTags)\
+ {\
+ Catch::AutoReg( Catch::makeTestInvoker(&TestName<__VA_ARGS__>::test), CATCH_INTERNAL_LINEINFO, className, nameAndTags);\
+ }
+
+#define INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD0(TestName, ClassName)
+#define INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD1(TestName, ClassName, signature)\
+ template<typename TestType> \
+ struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName)<TestType> { \
+ void test();\
+ }
+
+#define INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X(TestName, ClassName, signature, ...)\
+ template<INTERNAL_CATCH_REMOVE_PARENS(signature)> \
+ struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName)<__VA_ARGS__> { \
+ void test();\
+ }
+
+#define INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD0(TestName)
+#define INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD1(TestName, signature)\
+ template<typename TestType> \
+ void INTERNAL_CATCH_MAKE_NAMESPACE(TestName)::TestName<TestType>::test()
+#define INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X(TestName, signature, ...)\
+ template<INTERNAL_CATCH_REMOVE_PARENS(signature)> \
+ void INTERNAL_CATCH_MAKE_NAMESPACE(TestName)::TestName<__VA_ARGS__>::test()
+
+#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
+#define INTERNAL_CATCH_NTTP_0
+#define INTERNAL_CATCH_NTTP_GEN(...) INTERNAL_CATCH_VA_NARGS_IMPL(__VA_ARGS__, INTERNAL_CATCH_NTTP_1(__VA_ARGS__), INTERNAL_CATCH_NTTP_1(__VA_ARGS__), INTERNAL_CATCH_NTTP_1(__VA_ARGS__), INTERNAL_CATCH_NTTP_1(__VA_ARGS__), INTERNAL_CATCH_NTTP_1(__VA_ARGS__), INTERNAL_CATCH_NTTP_1( __VA_ARGS__), INTERNAL_CATCH_NTTP_1( __VA_ARGS__), INTERNAL_CATCH_NTTP_1( __VA_ARGS__), INTERNAL_CATCH_NTTP_1( __VA_ARGS__),INTERNAL_CATCH_NTTP_1( __VA_ARGS__), INTERNAL_CATCH_NTTP_0)
+#define INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD(TestName, ...) INTERNAL_CATCH_VA_NARGS_IMPL( "dummy", __VA_ARGS__, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD1, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD0)(TestName, __VA_ARGS__)
+#define INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD(TestName, ClassName, ...) INTERNAL_CATCH_VA_NARGS_IMPL( "dummy", __VA_ARGS__, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD1, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD0)(TestName, ClassName, __VA_ARGS__)
+#define INTERNAL_CATCH_NTTP_REG_METHOD_GEN(TestName, ...) INTERNAL_CATCH_VA_NARGS_IMPL( "dummy", __VA_ARGS__, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD0, INTERNAL_CATCH_NTTP_REGISTER_METHOD0)(TestName, __VA_ARGS__)
+#define INTERNAL_CATCH_NTTP_REG_GEN(TestFunc, ...) INTERNAL_CATCH_VA_NARGS_IMPL( "dummy", __VA_ARGS__, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER0, INTERNAL_CATCH_NTTP_REGISTER0)(TestFunc, __VA_ARGS__)
+#define INTERNAL_CATCH_DEFINE_SIG_TEST(TestName, ...) INTERNAL_CATCH_VA_NARGS_IMPL( "dummy", __VA_ARGS__, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X,INTERNAL_CATCH_DEFINE_SIG_TEST_X,INTERNAL_CATCH_DEFINE_SIG_TEST1, INTERNAL_CATCH_DEFINE_SIG_TEST0)(TestName, __VA_ARGS__)
+#define INTERNAL_CATCH_DECLARE_SIG_TEST(TestName, ...) INTERNAL_CATCH_VA_NARGS_IMPL( "dummy", __VA_ARGS__, INTERNAL_CATCH_DECLARE_SIG_TEST_X,INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X,INTERNAL_CATCH_DECLARE_SIG_TEST_X,INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DECLARE_SIG_TEST1, INTERNAL_CATCH_DECLARE_SIG_TEST0)(TestName, __VA_ARGS__)
+#define INTERNAL_CATCH_REMOVE_PARENS_GEN(...) INTERNAL_CATCH_VA_NARGS_IMPL(__VA_ARGS__, INTERNAL_CATCH_REMOVE_PARENS_11_ARG,INTERNAL_CATCH_REMOVE_PARENS_10_ARG,INTERNAL_CATCH_REMOVE_PARENS_9_ARG,INTERNAL_CATCH_REMOVE_PARENS_8_ARG,INTERNAL_CATCH_REMOVE_PARENS_7_ARG,INTERNAL_CATCH_REMOVE_PARENS_6_ARG,INTERNAL_CATCH_REMOVE_PARENS_5_ARG,INTERNAL_CATCH_REMOVE_PARENS_4_ARG,INTERNAL_CATCH_REMOVE_PARENS_3_ARG,INTERNAL_CATCH_REMOVE_PARENS_2_ARG,INTERNAL_CATCH_REMOVE_PARENS_1_ARG)(__VA_ARGS__)
+#else
+#define INTERNAL_CATCH_NTTP_0(signature)
+#define INTERNAL_CATCH_NTTP_GEN(...) INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_VA_NARGS_IMPL(__VA_ARGS__, INTERNAL_CATCH_NTTP_1, INTERNAL_CATCH_NTTP_1, INTERNAL_CATCH_NTTP_1, INTERNAL_CATCH_NTTP_1, INTERNAL_CATCH_NTTP_1, INTERNAL_CATCH_NTTP_1, INTERNAL_CATCH_NTTP_1, INTERNAL_CATCH_NTTP_1, INTERNAL_CATCH_NTTP_1,INTERNAL_CATCH_NTTP_1, INTERNAL_CATCH_NTTP_0)( __VA_ARGS__))
+#define INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD(TestName, ...) INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_VA_NARGS_IMPL( "dummy", __VA_ARGS__, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD1, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD0)(TestName, __VA_ARGS__))
+#define INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD(TestName, ClassName, ...) INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_VA_NARGS_IMPL( "dummy", __VA_ARGS__, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD1, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD0)(TestName, ClassName, __VA_ARGS__))
+#define INTERNAL_CATCH_NTTP_REG_METHOD_GEN(TestName, ...) INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_VA_NARGS_IMPL( "dummy", __VA_ARGS__, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD0, INTERNAL_CATCH_NTTP_REGISTER_METHOD0)(TestName, __VA_ARGS__))
+#define INTERNAL_CATCH_NTTP_REG_GEN(TestFunc, ...) INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_VA_NARGS_IMPL( "dummy", __VA_ARGS__, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER0, INTERNAL_CATCH_NTTP_REGISTER0)(TestFunc, __VA_ARGS__))
+#define INTERNAL_CATCH_DEFINE_SIG_TEST(TestName, ...) INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_VA_NARGS_IMPL( "dummy", __VA_ARGS__, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X,INTERNAL_CATCH_DEFINE_SIG_TEST_X,INTERNAL_CATCH_DEFINE_SIG_TEST1, INTERNAL_CATCH_DEFINE_SIG_TEST0)(TestName, __VA_ARGS__))
+#define INTERNAL_CATCH_DECLARE_SIG_TEST(TestName, ...) INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_VA_NARGS_IMPL( "dummy", __VA_ARGS__, INTERNAL_CATCH_DECLARE_SIG_TEST_X,INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X,INTERNAL_CATCH_DECLARE_SIG_TEST_X,INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DECLARE_SIG_TEST1, INTERNAL_CATCH_DECLARE_SIG_TEST0)(TestName, __VA_ARGS__))
+#define INTERNAL_CATCH_REMOVE_PARENS_GEN(...) INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_VA_NARGS_IMPL(__VA_ARGS__, INTERNAL_CATCH_REMOVE_PARENS_11_ARG,INTERNAL_CATCH_REMOVE_PARENS_10_ARG,INTERNAL_CATCH_REMOVE_PARENS_9_ARG,INTERNAL_CATCH_REMOVE_PARENS_8_ARG,INTERNAL_CATCH_REMOVE_PARENS_7_ARG,INTERNAL_CATCH_REMOVE_PARENS_6_ARG,INTERNAL_CATCH_REMOVE_PARENS_5_ARG,INTERNAL_CATCH_REMOVE_PARENS_4_ARG,INTERNAL_CATCH_REMOVE_PARENS_3_ARG,INTERNAL_CATCH_REMOVE_PARENS_2_ARG,INTERNAL_CATCH_REMOVE_PARENS_1_ARG)(__VA_ARGS__))
+#endif
+
+#endif // CATCH_PREPROCESSOR_HPP_INCLUDED
+
+
+// GCC 5 and older do not properly handle disabling unused-variable warning
+// with a _Pragma. This means that we have to leak the suppression to the
+// user code as well :-(
+#if defined(__GNUC__) && !defined(__clang__) && __GNUC__ <= 5
+#pragma GCC diagnostic ignored "-Wunused-variable"
+#endif
+
+#if defined(CATCH_CONFIG_DISABLE)
+ #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION_2( TestName, TestFunc, Name, Tags, Signature, ... ) \
+ INTERNAL_CATCH_DEFINE_SIG_TEST(TestFunc, INTERNAL_CATCH_REMOVE_PARENS(Signature))
+ #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION_2( TestNameClass, TestName, ClassName, Name, Tags, Signature, ... ) \
+ namespace{ \
+ namespace INTERNAL_CATCH_MAKE_NAMESPACE(TestName) { \
+ INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD(TestName, ClassName, INTERNAL_CATCH_REMOVE_PARENS(Signature));\
+ } \
+ } \
+ INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD(TestName, INTERNAL_CATCH_REMOVE_PARENS(Signature))
+
+ #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
+ #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(Name, Tags, ...) \
+ INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ), INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ), Name, Tags, typename TestType, __VA_ARGS__ )
+ #else
+ #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(Name, Tags, ...) \
+ INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ), INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ), Name, Tags, typename TestType, __VA_ARGS__ ) )
+ #endif
+
+ #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
+ #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG_NO_REGISTRATION(Name, Tags, Signature, ...) \
+ INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ), INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ), Name, Tags, Signature, __VA_ARGS__ )
+ #else
+ #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG_NO_REGISTRATION(Name, Tags, Signature, ...) \
+ INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ), INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ), Name, Tags, Signature, __VA_ARGS__ ) )
+ #endif
+
+ #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
+ #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION( ClassName, Name, Tags,... ) \
+ INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_CLASS_ ), INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ) , ClassName, Name, Tags, typename T, __VA_ARGS__ )
+ #else
+ #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION( ClassName, Name, Tags,... ) \
+ INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_CLASS_ ), INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ) , ClassName, Name, Tags, typename T, __VA_ARGS__ ) )
+ #endif
+
+ #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
+ #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG_NO_REGISTRATION( ClassName, Name, Tags, Signature, ... ) \
+ INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_CLASS_ ), INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ) , ClassName, Name, Tags, Signature, __VA_ARGS__ )
+ #else
+ #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG_NO_REGISTRATION( ClassName, Name, Tags, Signature, ... ) \
+ INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_CLASS_ ), INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ) , ClassName, Name, Tags, Signature, __VA_ARGS__ ) )
+ #endif
+#endif
+
+
+ ///////////////////////////////////////////////////////////////////////////////
+ #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_2(TestName, TestFunc, Name, Tags, Signature, ... )\
+ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
+ CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
+ CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS \
+ CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \
+ CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \
+ INTERNAL_CATCH_DECLARE_SIG_TEST(TestFunc, INTERNAL_CATCH_REMOVE_PARENS(Signature));\
+ namespace {\
+ namespace INTERNAL_CATCH_MAKE_NAMESPACE(TestName){\
+ INTERNAL_CATCH_TYPE_GEN\
+ INTERNAL_CATCH_NTTP_GEN(INTERNAL_CATCH_REMOVE_PARENS(Signature))\
+ INTERNAL_CATCH_NTTP_REG_GEN(TestFunc,INTERNAL_CATCH_REMOVE_PARENS(Signature))\
+ template<typename...Types> \
+ struct TestName{\
+ TestName(){\
+ size_t index = 0; \
+ constexpr char const* tmpl_types[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, __VA_ARGS__)};\
+ using expander = size_t[];\
+ (void)expander{(reg_test(Types{}, Catch::NameAndTags{ Name " - " + std::string(tmpl_types[index]), Tags } ), index++)... };/* NOLINT */ \
+ }\
+ };\
+ static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){\
+ TestName<INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES(__VA_ARGS__)>();\
+ return 0;\
+ }();\
+ }\
+ }\
+ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
+ INTERNAL_CATCH_DEFINE_SIG_TEST(TestFunc,INTERNAL_CATCH_REMOVE_PARENS(Signature))
+
+#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
+ #define INTERNAL_CATCH_TEMPLATE_TEST_CASE(Name, Tags, ...) \
+ INTERNAL_CATCH_TEMPLATE_TEST_CASE_2( INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ), INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ), Name, Tags, typename TestType, __VA_ARGS__ )
+#else
+ #define INTERNAL_CATCH_TEMPLATE_TEST_CASE(Name, Tags, ...) \
+ INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_2( INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ), INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ), Name, Tags, typename TestType, __VA_ARGS__ ) )
+#endif
+
+#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
+ #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG(Name, Tags, Signature, ...) \
+ INTERNAL_CATCH_TEMPLATE_TEST_CASE_2( INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ), INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ), Name, Tags, Signature, __VA_ARGS__ )
+#else
+ #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG(Name, Tags, Signature, ...) \
+ INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_2( INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ), INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ), Name, Tags, Signature, __VA_ARGS__ ) )
+#endif
+
+ #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE2(TestName, TestFuncName, Name, Tags, Signature, TmplTypes, TypesList) \
+ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
+ CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
+ CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS \
+ CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \
+ CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \
+ template<typename TestType> static void TestFuncName(); \
+ namespace {\
+ namespace INTERNAL_CATCH_MAKE_NAMESPACE(TestName) { \
+ INTERNAL_CATCH_TYPE_GEN \
+ INTERNAL_CATCH_NTTP_GEN(INTERNAL_CATCH_REMOVE_PARENS(Signature)) \
+ template<typename... Types> \
+ struct TestName { \
+ void reg_tests() { \
+ size_t index = 0; \
+ using expander = size_t[]; \
+ constexpr char const* tmpl_types[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, INTERNAL_CATCH_REMOVE_PARENS(TmplTypes))};\
+ constexpr char const* types_list[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, INTERNAL_CATCH_REMOVE_PARENS(TypesList))};\
+ constexpr auto num_types = sizeof(types_list) / sizeof(types_list[0]);\
+ (void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestFuncName<Types> ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ Name " - " + std::string(tmpl_types[index / num_types]) + '<' + std::string(types_list[index % num_types]) + '>', Tags } ), index++)... };/* NOLINT */\
+ } \
+ }; \
+ static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){ \
+ using TestInit = typename create<TestName, decltype(get_wrapper<INTERNAL_CATCH_REMOVE_PARENS(TmplTypes)>()), TypeList<INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES(INTERNAL_CATCH_REMOVE_PARENS(TypesList))>>::type; \
+ TestInit t; \
+ t.reg_tests(); \
+ return 0; \
+ }(); \
+ } \
+ } \
+ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
+ template<typename TestType> \
+ static void TestFuncName()
+
+#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
+ #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE(Name, Tags, ...)\
+ INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE2(INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ), INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ), Name, Tags, typename T,__VA_ARGS__)
+#else
+ #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE(Name, Tags, ...)\
+ INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE2( INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ), INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ), Name, Tags, typename T, __VA_ARGS__ ) )
+#endif
+
+#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
+ #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG(Name, Tags, Signature, ...)\
+ INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE2(INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ), INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ), Name, Tags, Signature, __VA_ARGS__)
+#else
+ #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG(Name, Tags, Signature, ...)\
+ INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE2( INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ), INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ), Name, Tags, Signature, __VA_ARGS__ ) )
+#endif
+
+ #define INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_2(TestName, TestFunc, Name, Tags, TmplList)\
+ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
+ CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
+ CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \
+ CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \
+ template<typename TestType> static void TestFunc(); \
+ namespace {\
+ namespace INTERNAL_CATCH_MAKE_NAMESPACE(TestName){\
+ INTERNAL_CATCH_TYPE_GEN\
+ template<typename... Types> \
+ struct TestName { \
+ void reg_tests() { \
+ size_t index = 0; \
+ using expander = size_t[]; \
+ (void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestFunc<Types> ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ Name " - " + std::string(INTERNAL_CATCH_STRINGIZE(TmplList)) + " - " + std::to_string(index), Tags } ), index++)... };/* NOLINT */\
+ } \
+ };\
+ static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){ \
+ using TestInit = typename convert<TestName, TmplList>::type; \
+ TestInit t; \
+ t.reg_tests(); \
+ return 0; \
+ }(); \
+ }}\
+ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
+ template<typename TestType> \
+ static void TestFunc()
+
+ #define INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE(Name, Tags, TmplList) \
+ INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_2( INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ), INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ), Name, Tags, TmplList )
+
+
+ #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_2( TestNameClass, TestName, ClassName, Name, Tags, Signature, ... ) \
+ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
+ CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
+ CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS \
+ CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \
+ CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \
+ namespace {\
+ namespace INTERNAL_CATCH_MAKE_NAMESPACE(TestName){ \
+ INTERNAL_CATCH_TYPE_GEN\
+ INTERNAL_CATCH_NTTP_GEN(INTERNAL_CATCH_REMOVE_PARENS(Signature))\
+ INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD(TestName, ClassName, INTERNAL_CATCH_REMOVE_PARENS(Signature));\
+ INTERNAL_CATCH_NTTP_REG_METHOD_GEN(TestName, INTERNAL_CATCH_REMOVE_PARENS(Signature))\
+ template<typename...Types> \
+ struct TestNameClass{\
+ TestNameClass(){\
+ size_t index = 0; \
+ constexpr char const* tmpl_types[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, __VA_ARGS__)};\
+ using expander = size_t[];\
+ (void)expander{(reg_test(Types{}, #ClassName, Catch::NameAndTags{ Name " - " + std::string(tmpl_types[index]), Tags } ), index++)... };/* NOLINT */ \
+ }\
+ };\
+ static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){\
+ TestNameClass<INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES(__VA_ARGS__)>();\
+ return 0;\
+ }();\
+ }\
+ }\
+ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
+ INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD(TestName, INTERNAL_CATCH_REMOVE_PARENS(Signature))
+
+#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
+ #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( ClassName, Name, Tags,... ) \
+ INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_CLASS_ ), INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ) , ClassName, Name, Tags, typename T, __VA_ARGS__ )
+#else
+ #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( ClassName, Name, Tags,... ) \
+ INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_CLASS_ ), INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ) , ClassName, Name, Tags, typename T, __VA_ARGS__ ) )
+#endif
+
+#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
+ #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( ClassName, Name, Tags, Signature, ... ) \
+ INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_CLASS_ ), INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ) , ClassName, Name, Tags, Signature, __VA_ARGS__ )
+#else
+ #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( ClassName, Name, Tags, Signature, ... ) \
+ INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_CLASS_ ), INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ) , ClassName, Name, Tags, Signature, __VA_ARGS__ ) )
+#endif
+
+ #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_2(TestNameClass, TestName, ClassName, Name, Tags, Signature, TmplTypes, TypesList)\
+ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
+ CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
+ CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS \
+ CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \
+ CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \
+ template<typename TestType> \
+ struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName <TestType>) { \
+ void test();\
+ };\
+ namespace {\
+ namespace INTERNAL_CATCH_MAKE_NAMESPACE(TestNameClass) {\
+ INTERNAL_CATCH_TYPE_GEN \
+ INTERNAL_CATCH_NTTP_GEN(INTERNAL_CATCH_REMOVE_PARENS(Signature))\
+ template<typename...Types>\
+ struct TestNameClass{\
+ void reg_tests(){\
+ std::size_t index = 0;\
+ using expander = std::size_t[];\
+ constexpr char const* tmpl_types[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, INTERNAL_CATCH_REMOVE_PARENS(TmplTypes))};\
+ constexpr char const* types_list[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, INTERNAL_CATCH_REMOVE_PARENS(TypesList))};\
+ constexpr auto num_types = sizeof(types_list) / sizeof(types_list[0]);\
+ (void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestName<Types>::test ), CATCH_INTERNAL_LINEINFO, #ClassName, Catch::NameAndTags{ Name " - " + std::string(tmpl_types[index / num_types]) + '<' + std::string(types_list[index % num_types]) + '>', Tags } ), index++)... };/* NOLINT */ \
+ }\
+ };\
+ static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){\
+ using TestInit = typename create<TestNameClass, decltype(get_wrapper<INTERNAL_CATCH_REMOVE_PARENS(TmplTypes)>()), TypeList<INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES(INTERNAL_CATCH_REMOVE_PARENS(TypesList))>>::type;\
+ TestInit t;\
+ t.reg_tests();\
+ return 0;\
+ }(); \
+ }\
+ }\
+ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
+ template<typename TestType> \
+ void TestName<TestType>::test()
+
+#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
+ #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( ClassName, Name, Tags, ... )\
+ INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ), INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ), ClassName, Name, Tags, typename T, __VA_ARGS__ )
+#else
+ #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( ClassName, Name, Tags, ... )\
+ INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ), INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ), ClassName, Name, Tags, typename T,__VA_ARGS__ ) )
+#endif
+
+#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
+ #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( ClassName, Name, Tags, Signature, ... )\
+ INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ), INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ), ClassName, Name, Tags, Signature, __VA_ARGS__ )
+#else
+ #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( ClassName, Name, Tags, Signature, ... )\
+ INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ), INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ), ClassName, Name, Tags, Signature,__VA_ARGS__ ) )
+#endif
+
+ #define INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_METHOD_2( TestNameClass, TestName, ClassName, Name, Tags, TmplList) \
+ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
+ CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
+ CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \
+ CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \
+ template<typename TestType> \
+ struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName <TestType>) { \
+ void test();\
+ };\
+ namespace {\
+ namespace INTERNAL_CATCH_MAKE_NAMESPACE(TestName){ \
+ INTERNAL_CATCH_TYPE_GEN\
+ template<typename...Types>\
+ struct TestNameClass{\
+ void reg_tests(){\
+ size_t index = 0;\
+ using expander = size_t[];\
+ (void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestName<Types>::test ), CATCH_INTERNAL_LINEINFO, #ClassName, Catch::NameAndTags{ Name " - " + std::string(INTERNAL_CATCH_STRINGIZE(TmplList)) + " - " + std::to_string(index), Tags } ), index++)... };/* NOLINT */ \
+ }\
+ };\
+ static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){\
+ using TestInit = typename convert<TestNameClass, TmplList>::type;\
+ TestInit t;\
+ t.reg_tests();\
+ return 0;\
+ }(); \
+ }}\
+ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
+ template<typename TestType> \
+ void TestName<TestType>::test()
+
+#define INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_METHOD(ClassName, Name, Tags, TmplList) \
+ INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ), INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ), ClassName, Name, Tags, TmplList )
+
+
+#endif // CATCH_TEMPLATE_TEST_REGISTRY_HPP_INCLUDED
+
+
+#if defined(CATCH_CONFIG_PREFIX_ALL) && !defined(CATCH_CONFIG_DISABLE)
+
+ #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
+ #define CATCH_TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ )
+ #define CATCH_TEMPLATE_TEST_CASE_SIG( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG( __VA_ARGS__ )
+ #define CATCH_TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )
+ #define CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( className, __VA_ARGS__ )
+ #define CATCH_TEMPLATE_PRODUCT_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE( __VA_ARGS__ )
+ #define CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG( ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG( __VA_ARGS__ )
+ #define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, __VA_ARGS__ )
+ #define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, __VA_ARGS__ )
+ #define CATCH_TEMPLATE_LIST_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE(__VA_ARGS__)
+ #define CATCH_TEMPLATE_LIST_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_METHOD( className, __VA_ARGS__ )
+ #else
+ #define CATCH_TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ ) )
+ #define CATCH_TEMPLATE_TEST_CASE_SIG( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG( __VA_ARGS__ ) )
+ #define CATCH_TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ ) )
+ #define CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( className, __VA_ARGS__ ) )
+ #define CATCH_TEMPLATE_PRODUCT_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE( __VA_ARGS__ ) )
+ #define CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG( __VA_ARGS__ ) )
+ #define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, __VA_ARGS__ ) )
+ #define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, __VA_ARGS__ ) )
+ #define CATCH_TEMPLATE_LIST_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE( __VA_ARGS__ ) )
+ #define CATCH_TEMPLATE_LIST_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_METHOD( className, __VA_ARGS__ ) )
+ #endif
+
+#elif defined(CATCH_CONFIG_PREFIX_ALL) && defined(CATCH_CONFIG_DISABLE)
+
+ #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
+ #define CATCH_TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(__VA_ARGS__)
+ #define CATCH_TEMPLATE_TEST_CASE_SIG( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG_NO_REGISTRATION(__VA_ARGS__)
+ #define CATCH_TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION(className, __VA_ARGS__)
+ #define CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG_NO_REGISTRATION(className, __VA_ARGS__ )
+ #else
+ #define CATCH_TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(__VA_ARGS__) )
+ #define CATCH_TEMPLATE_TEST_CASE_SIG( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG_NO_REGISTRATION(__VA_ARGS__) )
+ #define CATCH_TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION(className, __VA_ARGS__ ) )
+ #define CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG_NO_REGISTRATION(className, __VA_ARGS__ ) )
+ #endif
+
+ // When disabled, these can be shared between proper preprocessor and MSVC preprocessor
+ #define CATCH_TEMPLATE_PRODUCT_TEST_CASE( ... ) CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ )
+ #define CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG( ... ) CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ )
+ #define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )
+ #define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, ... ) CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )
+ #define CATCH_TEMPLATE_LIST_TEST_CASE( ... ) CATCH_TEMPLATE_TEST_CASE(__VA_ARGS__)
+ #define CATCH_TEMPLATE_LIST_TEST_CASE_METHOD( className, ... ) CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )
+
+#elif !defined(CATCH_CONFIG_PREFIX_ALL) && !defined(CATCH_CONFIG_DISABLE)
+
+ #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
+ #define TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ )
+ #define TEMPLATE_TEST_CASE_SIG( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG( __VA_ARGS__ )
+ #define TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )
+ #define TEMPLATE_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( className, __VA_ARGS__ )
+ #define TEMPLATE_PRODUCT_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE( __VA_ARGS__ )
+ #define TEMPLATE_PRODUCT_TEST_CASE_SIG( ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG( __VA_ARGS__ )
+ #define TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, __VA_ARGS__ )
+ #define TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, __VA_ARGS__ )
+ #define TEMPLATE_LIST_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE(__VA_ARGS__)
+ #define TEMPLATE_LIST_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_METHOD( className, __VA_ARGS__ )
+ #else
+ #define TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ ) )
+ #define TEMPLATE_TEST_CASE_SIG( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG( __VA_ARGS__ ) )
+ #define TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ ) )
+ #define TEMPLATE_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( className, __VA_ARGS__ ) )
+ #define TEMPLATE_PRODUCT_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE( __VA_ARGS__ ) )
+ #define TEMPLATE_PRODUCT_TEST_CASE_SIG( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG( __VA_ARGS__ ) )
+ #define TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, __VA_ARGS__ ) )
+ #define TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, __VA_ARGS__ ) )
+ #define TEMPLATE_LIST_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE( __VA_ARGS__ ) )
+ #define TEMPLATE_LIST_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_METHOD( className, __VA_ARGS__ ) )
+ #endif
+
+#elif !defined(CATCH_CONFIG_PREFIX_ALL) && defined(CATCH_CONFIG_DISABLE)
+
+ #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
+ #define TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(__VA_ARGS__)
+ #define TEMPLATE_TEST_CASE_SIG( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG_NO_REGISTRATION(__VA_ARGS__)
+ #define TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION(className, __VA_ARGS__)
+ #define TEMPLATE_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG_NO_REGISTRATION(className, __VA_ARGS__ )
+ #else
+ #define TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(__VA_ARGS__) )
+ #define TEMPLATE_TEST_CASE_SIG( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG_NO_REGISTRATION(__VA_ARGS__) )
+ #define TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION(className, __VA_ARGS__ ) )
+ #define TEMPLATE_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG_NO_REGISTRATION(className, __VA_ARGS__ ) )
+ #endif
+
+ // When disabled, these can be shared between proper preprocessor and MSVC preprocessor
+ #define TEMPLATE_PRODUCT_TEST_CASE( ... ) TEMPLATE_TEST_CASE( __VA_ARGS__ )
+ #define TEMPLATE_PRODUCT_TEST_CASE_SIG( ... ) TEMPLATE_TEST_CASE( __VA_ARGS__ )
+ #define TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )
+ #define TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, ... ) TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )
+ #define TEMPLATE_LIST_TEST_CASE( ... ) TEMPLATE_TEST_CASE(__VA_ARGS__)
+ #define TEMPLATE_LIST_TEST_CASE_METHOD( className, ... ) TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )
+
+#endif // end of user facing macro declarations
+
+
+#endif // CATCH_TEMPLATE_TEST_MACROS_HPP_INCLUDED
+
+
+#ifndef CATCH_TEST_CASE_INFO_HPP_INCLUDED
+#define CATCH_TEST_CASE_INFO_HPP_INCLUDED
+
+
+
+#include <string>
+#include <vector>
+
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wpadded"
+#endif
+
+namespace Catch {
+
+ /**
+ * A **view** of a tag string that provides case insensitive comparisons
+ *
+ * Note that in Catch2 internals, the square brackets around tags are
+ * not a part of tag's representation, so e.g. "[cool-tag]" is represented
+ * as "cool-tag" internally.
+ */
+ struct Tag {
+ constexpr Tag(StringRef original_):
+ original(original_)
+ {}
+ StringRef original;
+
+ friend bool operator< ( Tag const& lhs, Tag const& rhs );
+ friend bool operator==( Tag const& lhs, Tag const& rhs );
+ };
+
+ class ITestInvoker;
+
+ enum class TestCaseProperties : uint8_t {
+ None = 0,
+ IsHidden = 1 << 1,
+ ShouldFail = 1 << 2,
+ MayFail = 1 << 3,
+ Throws = 1 << 4,
+ NonPortable = 1 << 5,
+ Benchmark = 1 << 6
+ };
+
+ /**
+ * Various metadata about the test case.
+ *
+ * A test case is uniquely identified by its (class)name and tags
+ * combination, with source location being ignored, and other properties
+ * being determined from tags.
+ *
+ * Tags are kept sorted.
+ */
+ struct TestCaseInfo : Detail::NonCopyable {
+
+ TestCaseInfo(StringRef _className,
+ NameAndTags const& _tags,
+ SourceLineInfo const& _lineInfo);
+
+ bool isHidden() const;
+ bool throws() const;
+ bool okToFail() const;
+ bool expectedToFail() const;
+
+ // Adds the tag(s) with test's filename (for the -# flag)
+ void addFilenameTag();
+
+ //! Orders by name, classname and tags
+ friend bool operator<( TestCaseInfo const& lhs,
+ TestCaseInfo const& rhs );
+
+
+ std::string tagsAsString() const;
+
+ std::string name;
+ StringRef className;
+ private:
+ std::string backingTags;
+ // Internally we copy tags to the backing storage and then add
+ // refs to this storage to the tags vector.
+ void internalAppendTag(StringRef tagString);
+ public:
+ std::vector<Tag> tags;
+ SourceLineInfo lineInfo;
+ TestCaseProperties properties = TestCaseProperties::None;
+ };
+
+ /**
+ * Wrapper over the test case information and the test case invoker
+ *
+ * Does not own either, and is specifically made to be cheap
+ * to copy around.
+ */
+ class TestCaseHandle {
+ TestCaseInfo* m_info;
+ ITestInvoker* m_invoker;
+ public:
+ TestCaseHandle(TestCaseInfo* info, ITestInvoker* invoker) :
+ m_info(info), m_invoker(invoker) {}
+
+ void invoke() const {
+ m_invoker->invoke();
+ }
+
+ TestCaseInfo const& getTestCaseInfo() const;
+ };
+
+ Detail::unique_ptr<TestCaseInfo>
+ makeTestCaseInfo( StringRef className,
+ NameAndTags const& nameAndTags,
+ SourceLineInfo const& lineInfo );
+}
+
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+
+#endif // CATCH_TEST_CASE_INFO_HPP_INCLUDED
+
+
+#ifndef CATCH_TRANSLATE_EXCEPTION_HPP_INCLUDED
+#define CATCH_TRANSLATE_EXCEPTION_HPP_INCLUDED
+
+
+
+#ifndef CATCH_INTERFACES_EXCEPTION_HPP_INCLUDED
+#define CATCH_INTERFACES_EXCEPTION_HPP_INCLUDED
+
+
+#include <string>
+#include <vector>
+
+namespace Catch {
+ using exceptionTranslateFunction = std::string(*)();
+
+ class IExceptionTranslator;
+ using ExceptionTranslators = std::vector<Detail::unique_ptr<IExceptionTranslator const>>;
+
+ class IExceptionTranslator {
+ public:
+ virtual ~IExceptionTranslator(); // = default
+ virtual std::string translate( ExceptionTranslators::const_iterator it, ExceptionTranslators::const_iterator itEnd ) const = 0;
+ };
+
+ class IExceptionTranslatorRegistry {
+ public:
+ virtual ~IExceptionTranslatorRegistry(); // = default
+ virtual std::string translateActiveException() const = 0;
+ };
+
+} // namespace Catch
+
+#endif // CATCH_INTERFACES_EXCEPTION_HPP_INCLUDED
+
+#include <exception>
+
+namespace Catch {
+
+ class ExceptionTranslatorRegistrar {
+ template<typename T>
+ class ExceptionTranslator : public IExceptionTranslator {
+ public:
+
+ ExceptionTranslator( std::string(*translateFunction)( T const& ) )
+ : m_translateFunction( translateFunction )
+ {}
+
+ std::string translate( ExceptionTranslators::const_iterator it, ExceptionTranslators::const_iterator itEnd ) const override {
+#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
+ try {
+ if( it == itEnd )
+ std::rethrow_exception(std::current_exception());
+ else
+ return (*it)->translate( it+1, itEnd );
+ }
+ catch( T const& ex ) {
+ return m_translateFunction( ex );
+ }
+#else
+ return "You should never get here!";
+#endif
+ }
+
+ protected:
+ std::string(*m_translateFunction)( T const& );
+ };
+
+ public:
+ template<typename T>
+ ExceptionTranslatorRegistrar( std::string(*translateFunction)( T const& ) ) {
+ getMutableRegistryHub().registerTranslator(
+ Detail::make_unique<ExceptionTranslator<T>>(translateFunction)
+ );
+ }
+ };
+
+} // namespace Catch
+
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CATCH_TRANSLATE_EXCEPTION2( translatorName, signature ) \
+ static std::string translatorName( signature ); \
+ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
+ CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
+ namespace{ Catch::ExceptionTranslatorRegistrar INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionRegistrar )( &translatorName ); } \
+ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
+ static std::string translatorName( signature )
+
+#define INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION2( INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator ), signature )
+
+#if defined(CATCH_CONFIG_DISABLE)
+ #define INTERNAL_CATCH_TRANSLATE_EXCEPTION_NO_REG( translatorName, signature) \
+ static std::string translatorName( signature )
+#endif
+
+
+// This macro is always prefixed
+#if !defined(CATCH_CONFIG_DISABLE)
+#define CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature )
+#else
+#define CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION_NO_REG( INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator ), signature )
+#endif
+
+
+#endif // CATCH_TRANSLATE_EXCEPTION_HPP_INCLUDED
+
+
+#ifndef CATCH_VERSION_HPP_INCLUDED
+#define CATCH_VERSION_HPP_INCLUDED
+
+#include <iosfwd>
+
+namespace Catch {
+
+ // Versioning information
+ struct Version {
+ Version( Version const& ) = delete;
+ Version& operator=( Version const& ) = delete;
+ Version( unsigned int _majorVersion,
+ unsigned int _minorVersion,
+ unsigned int _patchNumber,
+ char const * const _branchName,
+ unsigned int _buildNumber );
+
+ unsigned int const majorVersion;
+ unsigned int const minorVersion;
+ unsigned int const patchNumber;
+
+ // buildNumber is only used if branchName is not null
+ char const * const branchName;
+ unsigned int const buildNumber;
+
+ friend std::ostream& operator << ( std::ostream& os, Version const& version );
+ };
+
+ Version const& libraryVersion();
+}
+
+#endif // CATCH_VERSION_HPP_INCLUDED
+
+
+#ifndef CATCH_VERSION_MACROS_HPP_INCLUDED
+#define CATCH_VERSION_MACROS_HPP_INCLUDED
+
+#define CATCH_VERSION_MAJOR 3
+#define CATCH_VERSION_MINOR 1
+#define CATCH_VERSION_PATCH 0
+
+#endif // CATCH_VERSION_MACROS_HPP_INCLUDED
+
+
+/** \file
+ * This is a convenience header for Catch2's Generator support. It includes
+ * **all** of Catch2 headers related to generators.
+ *
+ * Generally the Catch2 users should use specific includes they need,
+ * but this header can be used instead for ease-of-experimentation, or
+ * just plain convenience, at the cost of (significantly) increased
+ * compilation times.
+ *
+ * When a new header is added to either the `generators` folder,
+ * or to the corresponding internal subfolder, it should be added here.
+ */
+
+#ifndef CATCH_GENERATORS_ALL_HPP_INCLUDED
+#define CATCH_GENERATORS_ALL_HPP_INCLUDED
+
+
+
+#ifndef CATCH_GENERATOR_EXCEPTION_HPP_INCLUDED
+#define CATCH_GENERATOR_EXCEPTION_HPP_INCLUDED
+
+#include <exception>
+
+namespace Catch {
+
+ // Exception type to be thrown when a Generator runs into an error,
+ // e.g. it cannot initialize the first return value based on
+ // runtime information
+ class GeneratorException : public std::exception {
+ const char* const m_msg = "";
+
+ public:
+ GeneratorException(const char* msg):
+ m_msg(msg)
+ {}
+
+ const char* what() const noexcept override final;
+ };
+
+} // end namespace Catch
+
+#endif // CATCH_GENERATOR_EXCEPTION_HPP_INCLUDED
+
+
+#ifndef CATCH_GENERATORS_HPP_INCLUDED
+#define CATCH_GENERATORS_HPP_INCLUDED
+
+
+
+#ifndef CATCH_INTERFACES_GENERATORTRACKER_HPP_INCLUDED
+#define CATCH_INTERFACES_GENERATORTRACKER_HPP_INCLUDED
+
+
+#include <string>
+
+namespace Catch {
+
+ namespace Generators {
+ class GeneratorUntypedBase {
+ // Caches result from `toStringImpl`, assume that when it is an
+ // empty string, the cache is invalidated.
+ mutable std::string m_stringReprCache;
+
+ // Counts based on `next` returning true
+ std::size_t m_currentElementIndex = 0;
+
+ /**
+ * Attempts to move the generator to the next element
+ *
+ * Returns true iff the move succeeded (and a valid element
+ * can be retrieved).
+ */
+ virtual bool next() = 0;
+
+ //! Customization point for `currentElementAsString`
+ virtual std::string stringifyImpl() const = 0;
+
+ public:
+ GeneratorUntypedBase() = default;
+ // Generation of copy ops is deprecated (and Clang will complain)
+ // if there is a user destructor defined
+ GeneratorUntypedBase(GeneratorUntypedBase const&) = default;
+ GeneratorUntypedBase& operator=(GeneratorUntypedBase const&) = default;
+
+ virtual ~GeneratorUntypedBase(); // = default;
+
+ /**
+ * Attempts to move the generator to the next element
+ *
+ * Serves as a non-virtual interface to `next`, so that the
+ * top level interface can provide sanity checking and shared
+ * features.
+ *
+ * As with `next`, returns true iff the move succeeded and
+ * the generator has new valid element to provide.
+ */
+ bool countedNext();
+
+ std::size_t currentElementIndex() const { return m_currentElementIndex; }
+
+ /**
+ * Returns generator's current element as user-friendly string.
+ *
+ * By default returns string equivalent to calling
+ * `Catch::Detail::stringify` on the current element, but generators
+ * can customize their implementation as needed.
+ *
+ * Not thread-safe due to internal caching.
+ *
+ * The returned ref is valid only until the generator instance
+ * is destructed, or it moves onto the next element, whichever
+ * comes first.
+ */
+ StringRef currentElementAsString() const;
+ };
+ using GeneratorBasePtr = Catch::Detail::unique_ptr<GeneratorUntypedBase>;
+
+ } // namespace Generators
+
+ class IGeneratorTracker {
+ public:
+ virtual ~IGeneratorTracker(); // = default;
+ virtual auto hasGenerator() const -> bool = 0;
+ virtual auto getGenerator() const -> Generators::GeneratorBasePtr const& = 0;
+ virtual void setGenerator( Generators::GeneratorBasePtr&& generator ) = 0;
+ };
+
+} // namespace Catch
+
+#endif // CATCH_INTERFACES_GENERATORTRACKER_HPP_INCLUDED
+
+#include <vector>
+#include <tuple>
+
+namespace Catch {
+
+namespace Generators {
+
+namespace Detail {
+
+ //! Throws GeneratorException with the provided message
+ [[noreturn]]
+ void throw_generator_exception(char const * msg);
+
+} // end namespace detail
+
+ template<typename T>
+ class IGenerator : public GeneratorUntypedBase {
+ std::string stringifyImpl() const override {
+ return ::Catch::Detail::stringify( get() );
+ }
+
+ public:
+ ~IGenerator() override = default;
+ IGenerator() = default;
+ IGenerator(IGenerator const&) = default;
+ IGenerator& operator=(IGenerator const&) = default;
+
+
+ // Returns the current element of the generator
+ //
+ // \Precondition The generator is either freshly constructed,
+ // or the last call to `next()` returned true
+ virtual T const& get() const = 0;
+ using type = T;
+ };
+
+ template <typename T>
+ using GeneratorPtr = Catch::Detail::unique_ptr<IGenerator<T>>;
+
+ template <typename T>
+ class GeneratorWrapper final {
+ GeneratorPtr<T> m_generator;
+ public:
+ //! Takes ownership of the passed pointer.
+ GeneratorWrapper(IGenerator<T>* generator):
+ m_generator(generator) {}
+ GeneratorWrapper(GeneratorPtr<T> generator):
+ m_generator(CATCH_MOVE(generator)) {}
+
+ T const& get() const {
+ return m_generator->get();
+ }
+ bool next() {
+ return m_generator->countedNext();
+ }
+ };
+
+
+ template<typename T>
+ class SingleValueGenerator final : public IGenerator<T> {
+ T m_value;
+ public:
+ SingleValueGenerator(T const& value) :
+ m_value(value)
+ {}
+ SingleValueGenerator(T&& value):
+ m_value(CATCH_MOVE(value))
+ {}
+
+ T const& get() const override {
+ return m_value;
+ }
+ bool next() override {
+ return false;
+ }
+ };
+
+ template<typename T>
+ class FixedValuesGenerator final : public IGenerator<T> {
+ static_assert(!std::is_same<T, bool>::value,
+ "FixedValuesGenerator does not support bools because of std::vector<bool>"
+ "specialization, use SingleValue Generator instead.");
+ std::vector<T> m_values;
+ size_t m_idx = 0;
+ public:
+ FixedValuesGenerator( std::initializer_list<T> values ) : m_values( values ) {}
+
+ T const& get() const override {
+ return m_values[m_idx];
+ }
+ bool next() override {
+ ++m_idx;
+ return m_idx < m_values.size();
+ }
+ };
+
+ template <typename T, typename DecayedT = std::decay_t<T>>
+ GeneratorWrapper<DecayedT> value( T&& value ) {
+ return GeneratorWrapper<DecayedT>(
+ Catch::Detail::make_unique<SingleValueGenerator<DecayedT>>(
+ CATCH_FORWARD( value ) ) );
+ }
+ template <typename T>
+ GeneratorWrapper<T> values(std::initializer_list<T> values) {
+ return GeneratorWrapper<T>(Catch::Detail::make_unique<FixedValuesGenerator<T>>(values));
+ }
+
+ template<typename T>
+ class Generators : public IGenerator<T> {
+ std::vector<GeneratorWrapper<T>> m_generators;
+ size_t m_current = 0;
+
+ void add_generator( GeneratorWrapper<T>&& generator ) {
+ m_generators.emplace_back( CATCH_MOVE( generator ) );
+ }
+ void add_generator( T const& val ) {
+ m_generators.emplace_back( value( val ) );
+ }
+ void add_generator( T&& val ) {
+ m_generators.emplace_back( value( CATCH_MOVE( val ) ) );
+ }
+ template <typename U>
+ std::enable_if_t<!std::is_same<std::decay_t<U>, T>::value>
+ add_generator( U&& val ) {
+ add_generator( T( CATCH_FORWARD( val ) ) );
+ }
+
+ template <typename U> void add_generators( U&& valueOrGenerator ) {
+ add_generator( CATCH_FORWARD( valueOrGenerator ) );
+ }
+
+ template <typename U, typename... Gs>
+ void add_generators( U&& valueOrGenerator, Gs&&... moreGenerators ) {
+ add_generator( CATCH_FORWARD( valueOrGenerator ) );
+ add_generators( CATCH_FORWARD( moreGenerators )... );
+ }
+
+ public:
+ template <typename... Gs>
+ Generators(Gs &&... moreGenerators) {
+ m_generators.reserve(sizeof...(Gs));
+ add_generators(CATCH_FORWARD(moreGenerators)...);
+ }
+
+ T const& get() const override {
+ return m_generators[m_current].get();
+ }
+
+ bool next() override {
+ if (m_current >= m_generators.size()) {
+ return false;
+ }
+ const bool current_status = m_generators[m_current].next();
+ if (!current_status) {
+ ++m_current;
+ }
+ return m_current < m_generators.size();
+ }
+ };
+
+
+ template <typename... Ts>
+ GeneratorWrapper<std::tuple<std::decay_t<Ts>...>>
+ table( std::initializer_list<std::tuple<std::decay_t<Ts>...>> tuples ) {
+ return values<std::tuple<Ts...>>( tuples );
+ }
+
+ // Tag type to signal that a generator sequence should convert arguments to a specific type
+ template <typename T>
+ struct as {};
+
+ template<typename T, typename... Gs>
+ auto makeGenerators( GeneratorWrapper<T>&& generator, Gs &&... moreGenerators ) -> Generators<T> {
+ return Generators<T>(CATCH_MOVE(generator), CATCH_FORWARD(moreGenerators)...);
+ }
+ template<typename T>
+ auto makeGenerators( GeneratorWrapper<T>&& generator ) -> Generators<T> {
+ return Generators<T>(CATCH_MOVE(generator));
+ }
+ template<typename T, typename... Gs>
+ auto makeGenerators( T&& val, Gs &&... moreGenerators ) -> Generators<std::decay_t<T>> {
+ return makeGenerators( value( CATCH_FORWARD( val ) ), CATCH_FORWARD( moreGenerators )... );
+ }
+ template<typename T, typename U, typename... Gs>
+ auto makeGenerators( as<T>, U&& val, Gs &&... moreGenerators ) -> Generators<T> {
+ return makeGenerators( value( T( CATCH_FORWARD( val ) ) ), CATCH_FORWARD( moreGenerators )... );
+ }
+
+ auto acquireGeneratorTracker( StringRef generatorName, SourceLineInfo const& lineInfo ) -> IGeneratorTracker&;
+
+ template<typename L>
+ // Note: The type after -> is weird, because VS2015 cannot parse
+ // the expression used in the typedef inside, when it is in
+ // return type. Yeah.
+ auto generate( StringRef generatorName, SourceLineInfo const& lineInfo, L const& generatorExpression ) -> decltype(std::declval<decltype(generatorExpression())>().get()) {
+ using UnderlyingType = typename decltype(generatorExpression())::type;
+
+ IGeneratorTracker& tracker = acquireGeneratorTracker( generatorName, lineInfo );
+ if (!tracker.hasGenerator()) {
+ tracker.setGenerator(Catch::Detail::make_unique<Generators<UnderlyingType>>(generatorExpression()));
+ }
+
+ auto const& generator = static_cast<IGenerator<UnderlyingType> const&>( *tracker.getGenerator() );
+ return generator.get();
+ }
+
+} // namespace Generators
+} // namespace Catch
+
+#define GENERATE( ... ) \
+ Catch::Generators::generate( INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_UNIQUE_NAME(generator)), \
+ CATCH_INTERNAL_LINEINFO, \
+ [ ]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } ) //NOLINT(google-build-using-namespace)
+#define GENERATE_COPY( ... ) \
+ Catch::Generators::generate( INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_UNIQUE_NAME(generator)), \
+ CATCH_INTERNAL_LINEINFO, \
+ [=]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } ) //NOLINT(google-build-using-namespace)
+#define GENERATE_REF( ... ) \
+ Catch::Generators::generate( INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_UNIQUE_NAME(generator)), \
+ CATCH_INTERNAL_LINEINFO, \
+ [&]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } ) //NOLINT(google-build-using-namespace)
+
+#endif // CATCH_GENERATORS_HPP_INCLUDED
+
+
+#ifndef CATCH_GENERATORS_ADAPTERS_HPP_INCLUDED
+#define CATCH_GENERATORS_ADAPTERS_HPP_INCLUDED
+
+
+#include <cassert>
+
+namespace Catch {
+namespace Generators {
+
+ template <typename T>
+ class TakeGenerator final : public IGenerator<T> {
+ GeneratorWrapper<T> m_generator;
+ size_t m_returned = 0;
+ size_t m_target;
+ public:
+ TakeGenerator(size_t target, GeneratorWrapper<T>&& generator):
+ m_generator(CATCH_MOVE(generator)),
+ m_target(target)
+ {
+ assert(target != 0 && "Empty generators are not allowed");
+ }
+ T const& get() const override {
+ return m_generator.get();
+ }
+ bool next() override {
+ ++m_returned;
+ if (m_returned >= m_target) {
+ return false;
+ }
+
+ const auto success = m_generator.next();
+ // If the underlying generator does not contain enough values
+ // then we cut short as well
+ if (!success) {
+ m_returned = m_target;
+ }
+ return success;
+ }
+ };
+
+ template <typename T>
+ GeneratorWrapper<T> take(size_t target, GeneratorWrapper<T>&& generator) {
+ return GeneratorWrapper<T>(Catch::Detail::make_unique<TakeGenerator<T>>(target, CATCH_MOVE(generator)));
+ }
+
+
+ template <typename T, typename Predicate>
+ class FilterGenerator final : public IGenerator<T> {
+ GeneratorWrapper<T> m_generator;
+ Predicate m_predicate;
+ public:
+ template <typename P = Predicate>
+ FilterGenerator(P&& pred, GeneratorWrapper<T>&& generator):
+ m_generator(CATCH_MOVE(generator)),
+ m_predicate(CATCH_FORWARD(pred))
+ {
+ if (!m_predicate(m_generator.get())) {
+ // It might happen that there are no values that pass the
+ // filter. In that case we throw an exception.
+ auto has_initial_value = next();
+ if (!has_initial_value) {
+ Detail::throw_generator_exception("No valid value found in filtered generator");
+ }
+ }
+ }
+
+ T const& get() const override {
+ return m_generator.get();
+ }
+
+ bool next() override {
+ bool success = m_generator.next();
+ if (!success) {
+ return false;
+ }
+ while (!m_predicate(m_generator.get()) && (success = m_generator.next()) == true);
+ return success;
+ }
+ };
+
+
+ template <typename T, typename Predicate>
+ GeneratorWrapper<T> filter(Predicate&& pred, GeneratorWrapper<T>&& generator) {
+ return GeneratorWrapper<T>(Catch::Detail::make_unique<FilterGenerator<T, Predicate>>(CATCH_FORWARD(pred), CATCH_MOVE(generator)));
+ }
+
+ template <typename T>
+ class RepeatGenerator final : public IGenerator<T> {
+ static_assert(!std::is_same<T, bool>::value,
+ "RepeatGenerator currently does not support bools"
+ "because of std::vector<bool> specialization");
+ GeneratorWrapper<T> m_generator;
+ mutable std::vector<T> m_returned;
+ size_t m_target_repeats;
+ size_t m_current_repeat = 0;
+ size_t m_repeat_index = 0;
+ public:
+ RepeatGenerator(size_t repeats, GeneratorWrapper<T>&& generator):
+ m_generator(CATCH_MOVE(generator)),
+ m_target_repeats(repeats)
+ {
+ assert(m_target_repeats > 0 && "Repeat generator must repeat at least once");
+ }
+
+ T const& get() const override {
+ if (m_current_repeat == 0) {
+ m_returned.push_back(m_generator.get());
+ return m_returned.back();
+ }
+ return m_returned[m_repeat_index];
+ }
+
+ bool next() override {
+ // There are 2 basic cases:
+ // 1) We are still reading the generator
+ // 2) We are reading our own cache
+
+ // In the first case, we need to poke the underlying generator.
+ // If it happily moves, we are left in that state, otherwise it is time to start reading from our cache
+ if (m_current_repeat == 0) {
+ const auto success = m_generator.next();
+ if (!success) {
+ ++m_current_repeat;
+ }
+ return m_current_repeat < m_target_repeats;
+ }
+
+ // In the second case, we need to move indices forward and check that we haven't run up against the end
+ ++m_repeat_index;
+ if (m_repeat_index == m_returned.size()) {
+ m_repeat_index = 0;
+ ++m_current_repeat;
+ }
+ return m_current_repeat < m_target_repeats;
+ }
+ };
+
+ template <typename T>
+ GeneratorWrapper<T> repeat(size_t repeats, GeneratorWrapper<T>&& generator) {
+ return GeneratorWrapper<T>(Catch::Detail::make_unique<RepeatGenerator<T>>(repeats, CATCH_MOVE(generator)));
+ }
+
+ template <typename T, typename U, typename Func>
+ class MapGenerator final : public IGenerator<T> {
+ // TBD: provide static assert for mapping function, for friendly error message
+ GeneratorWrapper<U> m_generator;
+ Func m_function;
+ // To avoid returning dangling reference, we have to save the values
+ T m_cache;
+ public:
+ template <typename F2 = Func>
+ MapGenerator(F2&& function, GeneratorWrapper<U>&& generator) :
+ m_generator(CATCH_MOVE(generator)),
+ m_function(CATCH_FORWARD(function)),
+ m_cache(m_function(m_generator.get()))
+ {}
+
+ T const& get() const override {
+ return m_cache;
+ }
+ bool next() override {
+ const auto success = m_generator.next();
+ if (success) {
+ m_cache = m_function(m_generator.get());
+ }
+ return success;
+ }
+ };
+
+ template <typename Func, typename U, typename T = FunctionReturnType<Func, U>>
+ GeneratorWrapper<T> map(Func&& function, GeneratorWrapper<U>&& generator) {
+ return GeneratorWrapper<T>(
+ Catch::Detail::make_unique<MapGenerator<T, U, Func>>(CATCH_FORWARD(function), CATCH_MOVE(generator))
+ );
+ }
+
+ template <typename T, typename U, typename Func>
+ GeneratorWrapper<T> map(Func&& function, GeneratorWrapper<U>&& generator) {
+ return GeneratorWrapper<T>(
+ Catch::Detail::make_unique<MapGenerator<T, U, Func>>(CATCH_FORWARD(function), CATCH_MOVE(generator))
+ );
+ }
+
+ template <typename T>
+ class ChunkGenerator final : public IGenerator<std::vector<T>> {
+ std::vector<T> m_chunk;
+ size_t m_chunk_size;
+ GeneratorWrapper<T> m_generator;
+ bool m_used_up = false;
+ public:
+ ChunkGenerator(size_t size, GeneratorWrapper<T> generator) :
+ m_chunk_size(size), m_generator(CATCH_MOVE(generator))
+ {
+ m_chunk.reserve(m_chunk_size);
+ if (m_chunk_size != 0) {
+ m_chunk.push_back(m_generator.get());
+ for (size_t i = 1; i < m_chunk_size; ++i) {
+ if (!m_generator.next()) {
+ Detail::throw_generator_exception("Not enough values to initialize the first chunk");
+ }
+ m_chunk.push_back(m_generator.get());
+ }
+ }
+ }
+ std::vector<T> const& get() const override {
+ return m_chunk;
+ }
+ bool next() override {
+ m_chunk.clear();
+ for (size_t idx = 0; idx < m_chunk_size; ++idx) {
+ if (!m_generator.next()) {
+ return false;
+ }
+ m_chunk.push_back(m_generator.get());
+ }
+ return true;
+ }
+ };
+
+ template <typename T>
+ GeneratorWrapper<std::vector<T>> chunk(size_t size, GeneratorWrapper<T>&& generator) {
+ return GeneratorWrapper<std::vector<T>>(
+ Catch::Detail::make_unique<ChunkGenerator<T>>(size, CATCH_MOVE(generator))
+ );
+ }
+
+} // namespace Generators
+} // namespace Catch
+
+
+#endif // CATCH_GENERATORS_ADAPTERS_HPP_INCLUDED
+
+
+#ifndef CATCH_GENERATORS_RANDOM_HPP_INCLUDED
+#define CATCH_GENERATORS_RANDOM_HPP_INCLUDED
+
+
+
+#ifndef CATCH_RANDOM_NUMBER_GENERATOR_HPP_INCLUDED
+#define CATCH_RANDOM_NUMBER_GENERATOR_HPP_INCLUDED
+
+#include <cstdint>
+
+namespace Catch {
+
+ // This is a simple implementation of C++11 Uniform Random Number
+ // Generator. It does not provide all operators, because Catch2
+ // does not use it, but it should behave as expected inside stdlib's
+ // distributions.
+ // The implementation is based on the PCG family (http://pcg-random.org)
+ class SimplePcg32 {
+ using state_type = std::uint64_t;
+ public:
+ using result_type = std::uint32_t;
+ static constexpr result_type (min)() {
+ return 0;
+ }
+ static constexpr result_type (max)() {
+ return static_cast<result_type>(-1);
+ }
+
+ // Provide some default initial state for the default constructor
+ SimplePcg32():SimplePcg32(0xed743cc4U) {}
+
+ explicit SimplePcg32(result_type seed_);
+
+ void seed(result_type seed_);
+ void discard(uint64_t skip);
+
+ result_type operator()();
+
+ private:
+ friend bool operator==(SimplePcg32 const& lhs, SimplePcg32 const& rhs);
+ friend bool operator!=(SimplePcg32 const& lhs, SimplePcg32 const& rhs);
+
+ // In theory we also need operator<< and operator>>
+ // In practice we do not use them, so we will skip them for now
+
+
+ std::uint64_t m_state;
+ // This part of the state determines which "stream" of the numbers
+ // is chosen -- we take it as a constant for Catch2, so we only
+ // need to deal with seeding the main state.
+ // Picked by reading 8 bytes from `/dev/random` :-)
+ static const std::uint64_t s_inc = (0x13ed0cc53f939476ULL << 1ULL) | 1ULL;
+ };
+
+} // end namespace Catch
+
+#endif // CATCH_RANDOM_NUMBER_GENERATOR_HPP_INCLUDED
+
+#include <random>
+
+namespace Catch {
+namespace Generators {
+namespace Detail {
+ // Returns a suitable seed for a random floating generator based off
+ // the primary internal rng. It does so by taking current value from
+ // the rng and returning it as the seed.
+ std::uint32_t getSeed();
+}
+
+template <typename Float>
+class RandomFloatingGenerator final : public IGenerator<Float> {
+ Catch::SimplePcg32 m_rng;
+ std::uniform_real_distribution<Float> m_dist;
+ Float m_current_number;
+public:
+ RandomFloatingGenerator( Float a, Float b, std::uint32_t seed ):
+ m_rng(seed),
+ m_dist(a, b) {
+ static_cast<void>(next());
+ }
+
+ Float const& get() const override {
+ return m_current_number;
+ }
+ bool next() override {
+ m_current_number = m_dist(m_rng);
+ return true;
+ }
+};
+
+template <typename Integer>
+class RandomIntegerGenerator final : public IGenerator<Integer> {
+ Catch::SimplePcg32 m_rng;
+ std::uniform_int_distribution<Integer> m_dist;
+ Integer m_current_number;
+public:
+ RandomIntegerGenerator( Integer a, Integer b, std::uint32_t seed ):
+ m_rng(seed),
+ m_dist(a, b) {
+ static_cast<void>(next());
+ }
+
+ Integer const& get() const override {
+ return m_current_number;
+ }
+ bool next() override {
+ m_current_number = m_dist(m_rng);
+ return true;
+ }
+};
+
+template <typename T>
+std::enable_if_t<std::is_integral<T>::value, GeneratorWrapper<T>>
+random(T a, T b) {
+ static_assert(
+ !std::is_same<T, char>::value &&
+ !std::is_same<T, int8_t>::value &&
+ !std::is_same<T, uint8_t>::value &&
+ !std::is_same<T, signed char>::value &&
+ !std::is_same<T, unsigned char>::value &&
+ !std::is_same<T, bool>::value,
+ "The requested type is not supported by the underlying random distributions from std" );
+ return GeneratorWrapper<T>(
+ Catch::Detail::make_unique<RandomIntegerGenerator<T>>(a, b, Detail::getSeed())
+ );
+}
+
+template <typename T>
+std::enable_if_t<std::is_floating_point<T>::value,
+GeneratorWrapper<T>>
+random(T a, T b) {
+ return GeneratorWrapper<T>(
+ Catch::Detail::make_unique<RandomFloatingGenerator<T>>(a, b, Detail::getSeed())
+ );
+}
+
+
+} // namespace Generators
+} // namespace Catch
+
+
+#endif // CATCH_GENERATORS_RANDOM_HPP_INCLUDED
+
+
+#ifndef CATCH_GENERATORS_RANGE_HPP_INCLUDED
+#define CATCH_GENERATORS_RANGE_HPP_INCLUDED
+
+
+#include <iterator>
+#include <type_traits>
+
+namespace Catch {
+namespace Generators {
+
+
+template <typename T>
+class RangeGenerator final : public IGenerator<T> {
+ T m_current;
+ T m_end;
+ T m_step;
+ bool m_positive;
+
+public:
+ RangeGenerator(T const& start, T const& end, T const& step):
+ m_current(start),
+ m_end(end),
+ m_step(step),
+ m_positive(m_step > T(0))
+ {
+ assert(m_current != m_end && "Range start and end cannot be equal");
+ assert(m_step != T(0) && "Step size cannot be zero");
+ assert(((m_positive && m_current <= m_end) || (!m_positive && m_current >= m_end)) && "Step moves away from end");
+ }
+
+ RangeGenerator(T const& start, T const& end):
+ RangeGenerator(start, end, (start < end) ? T(1) : T(-1))
+ {}
+
+ T const& get() const override {
+ return m_current;
+ }
+
+ bool next() override {
+ m_current += m_step;
+ return (m_positive) ? (m_current < m_end) : (m_current > m_end);
+ }
+};
+
+template <typename T>
+GeneratorWrapper<T> range(T const& start, T const& end, T const& step) {
+ static_assert(std::is_arithmetic<T>::value && !std::is_same<T, bool>::value, "Type must be numeric");
+ return GeneratorWrapper<T>(Catch::Detail::make_unique<RangeGenerator<T>>(start, end, step));
+}
+
+template <typename T>
+GeneratorWrapper<T> range(T const& start, T const& end) {
+ static_assert(std::is_integral<T>::value && !std::is_same<T, bool>::value, "Type must be an integer");
+ return GeneratorWrapper<T>(Catch::Detail::make_unique<RangeGenerator<T>>(start, end));
+}
+
+
+template <typename T>
+class IteratorGenerator final : public IGenerator<T> {
+ static_assert(!std::is_same<T, bool>::value,
+ "IteratorGenerator currently does not support bools"
+ "because of std::vector<bool> specialization");
+
+ std::vector<T> m_elems;
+ size_t m_current = 0;
+public:
+ template <typename InputIterator, typename InputSentinel>
+ IteratorGenerator(InputIterator first, InputSentinel last):m_elems(first, last) {
+ if (m_elems.empty()) {
+ Detail::throw_generator_exception("IteratorGenerator received no valid values");
+ }
+ }
+
+ T const& get() const override {
+ return m_elems[m_current];
+ }
+
+ bool next() override {
+ ++m_current;
+ return m_current != m_elems.size();
+ }
+};
+
+template <typename InputIterator,
+ typename InputSentinel,
+ typename ResultType = typename std::iterator_traits<InputIterator>::value_type>
+GeneratorWrapper<ResultType> from_range(InputIterator from, InputSentinel to) {
+ return GeneratorWrapper<ResultType>(Catch::Detail::make_unique<IteratorGenerator<ResultType>>(from, to));
+}
+
+template <typename Container,
+ typename ResultType = typename Container::value_type>
+GeneratorWrapper<ResultType> from_range(Container const& cnt) {
+ return GeneratorWrapper<ResultType>(Catch::Detail::make_unique<IteratorGenerator<ResultType>>(cnt.begin(), cnt.end()));
+}
+
+
+} // namespace Generators
+} // namespace Catch
+
+
+#endif // CATCH_GENERATORS_RANGE_HPP_INCLUDED
+
+#endif // CATCH_GENERATORS_ALL_HPP_INCLUDED
+
+
+/** \file
+ * This is a convenience header for Catch2's interfaces. It includes
+ * **all** of Catch2 headers related to interfaces.
+ *
+ * Generally the Catch2 users should use specific includes they need,
+ * but this header can be used instead for ease-of-experimentation, or
+ * just plain convenience, at the cost of somewhat increased compilation
+ * times.
+ *
+ * When a new header is added to either the `interfaces` folder, or to
+ * the corresponding internal subfolder, it should be added here.
+ */
+
+
+#ifndef CATCH_INTERFACES_ALL_HPP_INCLUDED
+#define CATCH_INTERFACES_ALL_HPP_INCLUDED
+
+
+
+#ifndef CATCH_INTERFACES_REPORTER_FACTORY_HPP_INCLUDED
+#define CATCH_INTERFACES_REPORTER_FACTORY_HPP_INCLUDED
+
+
+#include <string>
+
+namespace Catch {
+
+ struct ReporterConfig;
+ class IConfig;
+ class IEventListener;
+ using IEventListenerPtr = Detail::unique_ptr<IEventListener>;
+
+
+ class IReporterFactory {
+ public:
+ virtual ~IReporterFactory(); // = default
+
+ virtual IEventListenerPtr
+ create( ReporterConfig&& config ) const = 0;
+ virtual std::string getDescription() const = 0;
+ };
+ using IReporterFactoryPtr = Detail::unique_ptr<IReporterFactory>;
+
+ class EventListenerFactory {
+ public:
+ virtual ~EventListenerFactory(); // = default
+ virtual IEventListenerPtr create( IConfig const* config ) const = 0;
+ //! Return a meaningful name for the listener, e.g. its type name
+ virtual StringRef getName() const = 0;
+ //! Return listener's description if available
+ virtual std::string getDescription() const = 0;
+ };
+} // namespace Catch
+
+#endif // CATCH_INTERFACES_REPORTER_FACTORY_HPP_INCLUDED
+
+
+#ifndef CATCH_INTERFACES_REPORTER_REGISTRY_HPP_INCLUDED
+#define CATCH_INTERFACES_REPORTER_REGISTRY_HPP_INCLUDED
+
+
+
+#ifndef CATCH_CASE_INSENSITIVE_COMPARISONS_HPP_INCLUDED
+#define CATCH_CASE_INSENSITIVE_COMPARISONS_HPP_INCLUDED
+
+
+namespace Catch {
+ namespace Detail {
+ //! Provides case-insensitive `op<` semantics when called
+ struct CaseInsensitiveLess {
+ bool operator()( StringRef lhs,
+ StringRef rhs ) const;
+ };
+
+ //! Provides case-insensitive `op==` semantics when called
+ struct CaseInsensitiveEqualTo {
+ bool operator()( StringRef lhs,
+ StringRef rhs ) const;
+ };
+
+ } // namespace Detail
+} // namespace Catch
+
+#endif // CATCH_CASE_INSENSITIVE_COMPARISONS_HPP_INCLUDED
+
+#include <string>
+#include <vector>
+#include <map>
+
+namespace Catch {
+
+ class IConfig;
+
+ class IEventListener;
+ using IEventListenerPtr = Detail::unique_ptr<IEventListener>;
+ class IReporterFactory;
+ using IReporterFactoryPtr = Detail::unique_ptr<IReporterFactory>;
+ struct ReporterConfig;
+ class EventListenerFactory;
+
+ class IReporterRegistry {
+ public:
+ using FactoryMap = std::map<std::string, IReporterFactoryPtr, Detail::CaseInsensitiveLess>;
+ using Listeners = std::vector<Detail::unique_ptr<EventListenerFactory>>;
+
+ virtual ~IReporterRegistry(); // = default
+ virtual IEventListenerPtr create( std::string const& name, ReporterConfig&& config ) const = 0;
+ virtual FactoryMap const& getFactories() const = 0;
+ virtual Listeners const& getListeners() const = 0;
+ };
+
+} // end namespace Catch
+
+#endif // CATCH_INTERFACES_REPORTER_REGISTRY_HPP_INCLUDED
+
+
+#ifndef CATCH_INTERFACES_TAG_ALIAS_REGISTRY_HPP_INCLUDED
+#define CATCH_INTERFACES_TAG_ALIAS_REGISTRY_HPP_INCLUDED
+
+#include <string>
+
+namespace Catch {
+
+ struct TagAlias;
+
+ class ITagAliasRegistry {
+ public:
+ virtual ~ITagAliasRegistry(); // = default
+ // Nullptr if not present
+ virtual TagAlias const* find( std::string const& alias ) const = 0;
+ virtual std::string expandAliases( std::string const& unexpandedTestSpec ) const = 0;
+
+ static ITagAliasRegistry const& get();
+ };
+
+} // end namespace Catch
+
+#endif // CATCH_INTERFACES_TAG_ALIAS_REGISTRY_HPP_INCLUDED
+
+#endif // CATCH_INTERFACES_ALL_HPP_INCLUDED
+
+
+
+/** \file
+ * Wrapper for ANDROID_LOGWRITE configuration option
+ *
+ * We want to default to enabling it when compiled for android, but
+ * users of the library should also be able to disable it if they want
+ * to.
+ */
+
+#ifndef CATCH_CONFIG_ANDROID_LOGWRITE_HPP_INCLUDED
+#define CATCH_CONFIG_ANDROID_LOGWRITE_HPP_INCLUDED
+
+
+#if defined(__ANDROID__)
+# define CATCH_INTERNAL_CONFIG_ANDROID_LOGWRITE
+#endif
+
+
+#if defined( CATCH_INTERNAL_CONFIG_ANDROID_LOGWRITE ) && \
+ !defined( CATCH_CONFIG_NO_ANDROID_LOGWRITE ) && \
+ !defined( CATCH_CONFIG_ANDROID_LOGWRITE )
+# define CATCH_CONFIG_ANDROID_LOGWRITE
+#endif
+
+#endif // CATCH_CONFIG_ANDROID_LOGWRITE_HPP_INCLUDED
+
+
+
+/** \file
+ * Wrapper for UNCAUGHT_EXCEPTIONS configuration option
+ *
+ * For some functionality, Catch2 requires to know whether there is
+ * an active exception. Because `std::uncaught_exception` is deprecated
+ * in C++17, we want to use `std::uncaught_exceptions` if possible.
+ */
+
+#ifndef CATCH_CONFIG_UNCAUGHT_EXCEPTIONS_HPP_INCLUDED
+#define CATCH_CONFIG_UNCAUGHT_EXCEPTIONS_HPP_INCLUDED
+
+#if defined(_MSC_VER)
+# if _MSC_VER >= 1900 // Visual Studio 2015 or newer
+# define CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS
+# endif
+#endif
+
+
+#include <exception>
+
+#if defined(__cpp_lib_uncaught_exceptions) \
+ && !defined(CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS)
+
+# define CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS
+#endif // __cpp_lib_uncaught_exceptions
+
+
+#if defined(CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS) \
+ && !defined(CATCH_CONFIG_NO_CPP17_UNCAUGHT_EXCEPTIONS) \
+ && !defined(CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS)
+
+# define CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS
+#endif
+
+
+#endif // CATCH_CONFIG_UNCAUGHT_EXCEPTIONS_HPP_INCLUDED
+
+
+#ifndef CATCH_CONSOLE_WIDTH_HPP_INCLUDED
+#define CATCH_CONSOLE_WIDTH_HPP_INCLUDED
+
+// This include must be kept so that user's configured value for CONSOLE_WIDTH
+// is used before we attempt to provide a default value
+
+#ifndef CATCH_CONFIG_CONSOLE_WIDTH
+#define CATCH_CONFIG_CONSOLE_WIDTH 80
+#endif
+
+#endif // CATCH_CONSOLE_WIDTH_HPP_INCLUDED
+
+
+#ifndef CATCH_CONTAINER_NONMEMBERS_HPP_INCLUDED
+#define CATCH_CONTAINER_NONMEMBERS_HPP_INCLUDED
+
+
+#include <cstddef>
+#include <initializer_list>
+
+// We want a simple polyfill over `std::empty`, `std::size` and so on
+// for C++14 or C++ libraries with incomplete support.
+// We also have to handle that MSVC std lib will happily provide these
+// under older standards.
+#if defined(CATCH_CPP17_OR_GREATER) || defined(_MSC_VER)
+
+// We are already using this header either way, so there shouldn't
+// be much additional overhead in including it to get the feature
+// test macros
+#include <string>
+
+# if !defined(__cpp_lib_nonmember_container_access)
+# define CATCH_CONFIG_POLYFILL_NONMEMBER_CONTAINER_ACCESS
+# endif
+
+#else
+#define CATCH_CONFIG_POLYFILL_NONMEMBER_CONTAINER_ACCESS
+#endif
+
+
+
+namespace Catch {
+namespace Detail {
+
+#if defined(CATCH_CONFIG_POLYFILL_NONMEMBER_CONTAINER_ACCESS)
+ template <typename Container>
+ constexpr auto empty(Container const& cont) -> decltype(cont.empty()) {
+ return cont.empty();
+ }
+ template <typename T, std::size_t N>
+ constexpr bool empty(const T (&)[N]) noexcept {
+ // GCC < 7 does not support the const T(&)[] parameter syntax
+ // so we have to ignore the length explicitly
+ (void)N;
+ return false;
+ }
+ template <typename T>
+ constexpr bool empty(std::initializer_list<T> list) noexcept {
+ return list.size() > 0;
+ }
+
+
+ template <typename Container>
+ constexpr auto size(Container const& cont) -> decltype(cont.size()) {
+ return cont.size();
+ }
+ template <typename T, std::size_t N>
+ constexpr std::size_t size(const T(&)[N]) noexcept {
+ return N;
+ }
+#endif // CATCH_CONFIG_POLYFILL_NONMEMBER_CONTAINER_ACCESS
+
+} // end namespace Detail
+} // end namespace Catch
+
+
+
+#endif // CATCH_CONTAINER_NONMEMBERS_HPP_INCLUDED
+
+
+#ifndef CATCH_DEBUG_CONSOLE_HPP_INCLUDED
+#define CATCH_DEBUG_CONSOLE_HPP_INCLUDED
+
+#include <string>
+
+namespace Catch {
+ void writeToDebugConsole( std::string const& text );
+}
+
+#endif // CATCH_DEBUG_CONSOLE_HPP_INCLUDED
+
+
+#ifndef CATCH_DEBUGGER_HPP_INCLUDED
+#define CATCH_DEBUGGER_HPP_INCLUDED
+
+
+namespace Catch {
+ bool isDebuggerActive();
+}
+
+#ifdef CATCH_PLATFORM_MAC
+
+ #if defined(__i386__) || defined(__x86_64__)
+ #define CATCH_TRAP() __asm__("int $3\n" : : ) /* NOLINT */
+ #elif defined(__aarch64__)
+ #define CATCH_TRAP() __asm__(".inst 0xd43e0000")
+ #endif
+
+#elif defined(CATCH_PLATFORM_IPHONE)
+
+ // use inline assembler
+ #if defined(__i386__) || defined(__x86_64__)
+ #define CATCH_TRAP() __asm__("int $3")
+ #elif defined(__aarch64__)
+ #define CATCH_TRAP() __asm__(".inst 0xd4200000")
+ #elif defined(__arm__) && !defined(__thumb__)
+ #define CATCH_TRAP() __asm__(".inst 0xe7f001f0")
+ #elif defined(__arm__) && defined(__thumb__)
+ #define CATCH_TRAP() __asm__(".inst 0xde01")
+ #endif
+
+#elif defined(CATCH_PLATFORM_LINUX)
+ // If we can use inline assembler, do it because this allows us to break
+ // directly at the location of the failing check instead of breaking inside
+ // raise() called from it, i.e. one stack frame below.
+ #if defined(__GNUC__) && (defined(__i386) || defined(__x86_64))
+ #define CATCH_TRAP() asm volatile ("int $3") /* NOLINT */
+ #else // Fall back to the generic way.
+ #include <signal.h>
+
+ #define CATCH_TRAP() raise(SIGTRAP)
+ #endif
+#elif defined(_MSC_VER)
+ #define CATCH_TRAP() __debugbreak()
+#elif defined(__MINGW32__)
+ extern "C" __declspec(dllimport) void __stdcall DebugBreak();
+ #define CATCH_TRAP() DebugBreak()
+#endif
+
+#ifndef CATCH_BREAK_INTO_DEBUGGER
+ #ifdef CATCH_TRAP
+ #define CATCH_BREAK_INTO_DEBUGGER() []{ if( Catch::isDebuggerActive() ) { CATCH_TRAP(); } }()
+ #else
+ #define CATCH_BREAK_INTO_DEBUGGER() []{}()
+ #endif
+#endif
+
+#endif // CATCH_DEBUGGER_HPP_INCLUDED
+
+
+#ifndef CATCH_ENFORCE_HPP_INCLUDED
+#define CATCH_ENFORCE_HPP_INCLUDED
+
+
+#include <exception>
+
+namespace Catch {
+#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
+ template <typename Ex>
+ [[noreturn]]
+ void throw_exception(Ex const& e) {
+ throw e;
+ }
+#else // ^^ Exceptions are enabled // Exceptions are disabled vv
+ [[noreturn]]
+ void throw_exception(std::exception const& e);
+#endif
+
+ [[noreturn]]
+ void throw_logic_error(std::string const& msg);
+ [[noreturn]]
+ void throw_domain_error(std::string const& msg);
+ [[noreturn]]
+ void throw_runtime_error(std::string const& msg);
+
+} // namespace Catch;
+
+#define CATCH_MAKE_MSG(...) \
+ (Catch::ReusableStringStream() << __VA_ARGS__).str()
+
+#define CATCH_INTERNAL_ERROR(...) \
+ Catch::throw_logic_error(CATCH_MAKE_MSG( CATCH_INTERNAL_LINEINFO << ": Internal Catch2 error: " << __VA_ARGS__))
+
+#define CATCH_ERROR(...) \
+ Catch::throw_domain_error(CATCH_MAKE_MSG( __VA_ARGS__ ))
+
+#define CATCH_RUNTIME_ERROR(...) \
+ Catch::throw_runtime_error(CATCH_MAKE_MSG( __VA_ARGS__ ))
+
+#define CATCH_ENFORCE( condition, ... ) \
+ do{ if( !(condition) ) CATCH_ERROR( __VA_ARGS__ ); } while(false)
+
+
+#endif // CATCH_ENFORCE_HPP_INCLUDED
+
+
+#ifndef CATCH_ENUM_VALUES_REGISTRY_HPP_INCLUDED
+#define CATCH_ENUM_VALUES_REGISTRY_HPP_INCLUDED
+
+
+#include <vector>
+
+namespace Catch {
+
+ namespace Detail {
+
+ Catch::Detail::unique_ptr<EnumInfo> makeEnumInfo( StringRef enumName, StringRef allValueNames, std::vector<int> const& values );
+
+ class EnumValuesRegistry : public IMutableEnumValuesRegistry {
+
+ std::vector<Catch::Detail::unique_ptr<EnumInfo>> m_enumInfos;
+
+ EnumInfo const& registerEnum( StringRef enumName, StringRef allEnums, std::vector<int> const& values) override;
+ };
+
+ std::vector<StringRef> parseEnums( StringRef enums );
+
+ } // Detail
+
+} // Catch
+
+#endif // CATCH_ENUM_VALUES_REGISTRY_HPP_INCLUDED
+
+
+#ifndef CATCH_ERRNO_GUARD_HPP_INCLUDED
+#define CATCH_ERRNO_GUARD_HPP_INCLUDED
+
+namespace Catch {
+
+ //! Simple RAII class that stores the value of `errno`
+ //! at construction and restores it at destruction.
+ class ErrnoGuard {
+ public:
+ // Keep these outlined to avoid dragging in macros from <cerrno>
+
+ ErrnoGuard();
+ ~ErrnoGuard();
+ private:
+ int m_oldErrno;
+ };
+
+}
+
+#endif // CATCH_ERRNO_GUARD_HPP_INCLUDED
+
+
+#ifndef CATCH_EXCEPTION_TRANSLATOR_REGISTRY_HPP_INCLUDED
+#define CATCH_EXCEPTION_TRANSLATOR_REGISTRY_HPP_INCLUDED
+
+
+#include <vector>
+#include <string>
+
+namespace Catch {
+
+ class ExceptionTranslatorRegistry : public IExceptionTranslatorRegistry {
+ public:
+ ~ExceptionTranslatorRegistry() override;
+ void registerTranslator( Detail::unique_ptr<IExceptionTranslator>&& translator );
+ std::string translateActiveException() const override;
+ std::string tryTranslators() const;
+
+ private:
+ ExceptionTranslators m_translators;
+ };
+}
+
+#endif // CATCH_EXCEPTION_TRANSLATOR_REGISTRY_HPP_INCLUDED
+
+
+#ifndef CATCH_FATAL_CONDITION_HANDLER_HPP_INCLUDED
+#define CATCH_FATAL_CONDITION_HANDLER_HPP_INCLUDED
+
+
+#include <cassert>
+
+namespace Catch {
+
+ /**
+ * Wrapper for platform-specific fatal error (signals/SEH) handlers
+ *
+ * Tries to be cooperative with other handlers, and not step over
+ * other handlers. This means that unknown structured exceptions
+ * are passed on, previous signal handlers are called, and so on.
+ *
+ * Can only be instantiated once, and assumes that once a signal
+ * is caught, the binary will end up terminating. Thus, there
+ */
+ class FatalConditionHandler {
+ bool m_started = false;
+
+ // Install/disengage implementation for specific platform.
+ // Should be if-defed to work on current platform, can assume
+ // engage-disengage 1:1 pairing.
+ void engage_platform();
+ void disengage_platform() noexcept;
+ public:
+ // Should also have platform-specific implementations as needed
+ FatalConditionHandler();
+ ~FatalConditionHandler();
+
+ void engage() {
+ assert(!m_started && "Handler cannot be installed twice.");
+ m_started = true;
+ engage_platform();
+ }
+
+ void disengage() noexcept {
+ assert(m_started && "Handler cannot be uninstalled without being installed first");
+ m_started = false;
+ disengage_platform();
+ }
+ };
+
+ //! Simple RAII guard for (dis)engaging the FatalConditionHandler
+ class FatalConditionHandlerGuard {
+ FatalConditionHandler* m_handler;
+ public:
+ FatalConditionHandlerGuard(FatalConditionHandler* handler):
+ m_handler(handler) {
+ m_handler->engage();
+ }
+ ~FatalConditionHandlerGuard() {
+ m_handler->disengage();
+ }
+ };
+
+} // end namespace Catch
+
+#endif // CATCH_FATAL_CONDITION_HANDLER_HPP_INCLUDED
+
+
+#ifndef CATCH_FLOATING_POINT_HELPERS_HPP_INCLUDED
+#define CATCH_FLOATING_POINT_HELPERS_HPP_INCLUDED
+
+
+
+#ifndef CATCH_POLYFILLS_HPP_INCLUDED
+#define CATCH_POLYFILLS_HPP_INCLUDED
+
+namespace Catch {
+ bool isnan(float f);
+ bool isnan(double d);
+}
+
+#endif // CATCH_POLYFILLS_HPP_INCLUDED
+
+#include <cassert>
+#include <cmath>
+#include <cstdint>
+#include <utility>
+#include <limits>
+
+namespace Catch {
+ namespace Detail {
+
+ uint32_t convertToBits(float f);
+ uint64_t convertToBits(double d);
+
+ } // end namespace Detail
+
+
+
+#if defined( __GNUC__ ) || defined( __clang__ )
+# pragma GCC diagnostic push
+ // We do a bunch of direct compensations of floating point numbers,
+ // because we know what we are doing and actually do want the direct
+ // comparison behaviour.
+# pragma GCC diagnostic ignored "-Wfloat-equal"
+#endif
+
+ /**
+ * Calculates the ULP distance between two floating point numbers
+ *
+ * The ULP distance of two floating point numbers is the count of
+ * valid floating point numbers representable between them.
+ *
+ * There are some exceptions between how this function counts the
+ * distance, and the interpretation of the standard as implemented.
+ * by e.g. `nextafter`. For this function it always holds that:
+ * * `(x == y) => ulpDistance(x, y) == 0` (so `ulpDistance(-0, 0) == 0`)
+ * * `ulpDistance(maxFinite, INF) == 1`
+ * * `ulpDistance(x, -x) == 2 * ulpDistance(x, 0)`
+ *
+ * \pre `!isnan( lhs )`
+ * \pre `!isnan( rhs )`
+ * \pre floating point numbers are represented in IEEE-754 format
+ */
+ template <typename FP>
+ uint64_t ulpDistance( FP lhs, FP rhs ) {
+ assert( std::numeric_limits<FP>::is_iec559 &&
+ "ulpDistance assumes IEEE-754 format for floating point types" );
+ assert( !Catch::isnan( lhs ) &&
+ "Distance between NaN and number is not meaningful" );
+ assert( !Catch::isnan( rhs ) &&
+ "Distance between NaN and number is not meaningful" );
+
+ // We want X == Y to imply 0 ULP distance even if X and Y aren't
+ // bit-equal (-0 and 0), or X - Y != 0 (same sign infinities).
+ if ( lhs == rhs ) { return 0; }
+
+ // We need a properly typed positive zero for type inference.
+ static constexpr FP positive_zero{};
+
+ // We want to ensure that +/- 0 is always represented as positive zero
+ if ( lhs == positive_zero ) { lhs = positive_zero; }
+ if ( rhs == positive_zero ) { rhs = positive_zero; }
+
+ // If arguments have different signs, we can handle them by summing
+ // how far are they from 0 each.
+ if ( std::signbit( lhs ) != std::signbit( rhs ) ) {
+ return ulpDistance( std::abs( lhs ), positive_zero ) +
+ ulpDistance( std::abs( rhs ), positive_zero );
+ }
+
+ // When both lhs and rhs are of the same sign, we can just
+ // read the numbers bitwise as integers, and then subtract them
+ // (assuming IEEE).
+ uint64_t lc = Detail::convertToBits( lhs );
+ uint64_t rc = Detail::convertToBits( rhs );
+
+ // The ulp distance between two numbers is symmetric, so to avoid
+ // dealing with overflows we want the bigger converted number on the lhs
+ if ( lc < rc ) {
+ std::swap( lc, rc );
+ }
+
+ return lc - rc;
+ }
+
+#if defined( __GNUC__ ) || defined( __clang__ )
+# pragma GCC diagnostic pop
+#endif
+
+
+} // end namespace Catch
+
+#endif // CATCH_FLOATING_POINT_HELPERS_HPP_INCLUDED
+
+
+#ifndef CATCH_ISTREAM_HPP_INCLUDED
+#define CATCH_ISTREAM_HPP_INCLUDED
+
+
+#include <iosfwd>
+#include <cstddef>
+#include <ostream>
+#include <string>
+
+namespace Catch {
+
+ class IStream {
+ public:
+ virtual ~IStream(); // = default
+ virtual std::ostream& stream() = 0;
+ /**
+ * Best guess on whether the instance is writing to a console (e.g. via stdout/stderr)
+ *
+ * This is useful for e.g. Win32 colour support, because the Win32
+ * API manipulates console directly, unlike POSIX escape codes,
+ * that can be written anywhere.
+ *
+ * Due to variety of ways to change where the stdout/stderr is
+ * _actually_ being written, users should always assume that
+ * the answer might be wrong.
+ */
+ virtual bool isConsole() const { return false; }
+ };
+
+ /**
+ * Creates a stream wrapper that writes to specific file.
+ *
+ * Also recognizes 4 special filenames
+ * * `-` for stdout
+ * * `%stdout` for stdout
+ * * `%stderr` for stderr
+ * * `%debug` for platform specific debugging output
+ *
+ * \throws if passed an unrecognized %-prefixed stream
+ */
+ auto makeStream( std::string const& filename ) -> Detail::unique_ptr<IStream>;
+
+}
+
+#endif // CATCH_STREAM_HPP_INCLUDED
+
+
+#ifndef CATCH_LEAK_DETECTOR_HPP_INCLUDED
+#define CATCH_LEAK_DETECTOR_HPP_INCLUDED
+
+namespace Catch {
+
+ struct LeakDetector {
+ LeakDetector();
+ ~LeakDetector();
+ };
+
+}
+#endif // CATCH_LEAK_DETECTOR_HPP_INCLUDED
+
+
+#ifndef CATCH_LIST_HPP_INCLUDED
+#define CATCH_LIST_HPP_INCLUDED
+
+
+#include <set>
+#include <string>
+
+
+namespace Catch {
+
+ class IEventListener;
+ class Config;
+
+
+ struct ReporterDescription {
+ std::string name, description;
+ };
+ struct ListenerDescription {
+ StringRef name;
+ std::string description;
+ };
+
+ struct TagInfo {
+ void add(StringRef spelling);
+ std::string all() const;
+
+ std::set<StringRef> spellings;
+ std::size_t count = 0;
+ };
+
+ bool list( IEventListener& reporter, Config const& config );
+
+} // end namespace Catch
+
+#endif // CATCH_LIST_HPP_INCLUDED
+
+
+#ifndef CATCH_OUTPUT_REDIRECT_HPP_INCLUDED
+#define CATCH_OUTPUT_REDIRECT_HPP_INCLUDED
+
+
+#include <cstdio>
+#include <iosfwd>
+#include <string>
+
+namespace Catch {
+
+ class RedirectedStream {
+ std::ostream& m_originalStream;
+ std::ostream& m_redirectionStream;
+ std::streambuf* m_prevBuf;
+
+ public:
+ RedirectedStream( std::ostream& originalStream, std::ostream& redirectionStream );
+ ~RedirectedStream();
+ };
+
+ class RedirectedStdOut {
+ ReusableStringStream m_rss;
+ RedirectedStream m_cout;
+ public:
+ RedirectedStdOut();
+ auto str() const -> std::string;
+ };
+
+ // StdErr has two constituent streams in C++, std::cerr and std::clog
+ // This means that we need to redirect 2 streams into 1 to keep proper
+ // order of writes
+ class RedirectedStdErr {
+ ReusableStringStream m_rss;
+ RedirectedStream m_cerr;
+ RedirectedStream m_clog;
+ public:
+ RedirectedStdErr();
+ auto str() const -> std::string;
+ };
+
+ class RedirectedStreams {
+ public:
+ RedirectedStreams(RedirectedStreams const&) = delete;
+ RedirectedStreams& operator=(RedirectedStreams const&) = delete;
+ RedirectedStreams(RedirectedStreams&&) = delete;
+ RedirectedStreams& operator=(RedirectedStreams&&) = delete;
+
+ RedirectedStreams(std::string& redirectedCout, std::string& redirectedCerr);
+ ~RedirectedStreams();
+ private:
+ std::string& m_redirectedCout;
+ std::string& m_redirectedCerr;
+ RedirectedStdOut m_redirectedStdOut;
+ RedirectedStdErr m_redirectedStdErr;
+ };
+
+#if defined(CATCH_CONFIG_NEW_CAPTURE)
+
+ // Windows's implementation of std::tmpfile is terrible (it tries
+ // to create a file inside system folder, thus requiring elevated
+ // privileges for the binary), so we have to use tmpnam(_s) and
+ // create the file ourselves there.
+ class TempFile {
+ public:
+ TempFile(TempFile const&) = delete;
+ TempFile& operator=(TempFile const&) = delete;
+ TempFile(TempFile&&) = delete;
+ TempFile& operator=(TempFile&&) = delete;
+
+ TempFile();
+ ~TempFile();
+
+ std::FILE* getFile();
+ std::string getContents();
+
+ private:
+ std::FILE* m_file = nullptr;
+ #if defined(_MSC_VER)
+ char m_buffer[L_tmpnam] = { 0 };
+ #endif
+ };
+
+
+ class OutputRedirect {
+ public:
+ OutputRedirect(OutputRedirect const&) = delete;
+ OutputRedirect& operator=(OutputRedirect const&) = delete;
+ OutputRedirect(OutputRedirect&&) = delete;
+ OutputRedirect& operator=(OutputRedirect&&) = delete;
+
+
+ OutputRedirect(std::string& stdout_dest, std::string& stderr_dest);
+ ~OutputRedirect();
+
+ private:
+ int m_originalStdout = -1;
+ int m_originalStderr = -1;
+ TempFile m_stdoutFile;
+ TempFile m_stderrFile;
+ std::string& m_stdoutDest;
+ std::string& m_stderrDest;
+ };
+
+#endif
+
+} // end namespace Catch
+
+#endif // CATCH_OUTPUT_REDIRECT_HPP_INCLUDED
+
+
+#ifndef CATCH_REPORTER_REGISTRY_HPP_INCLUDED
+#define CATCH_REPORTER_REGISTRY_HPP_INCLUDED
+
+
+#include <map>
+
+namespace Catch {
+
+ class ReporterRegistry : public IReporterRegistry {
+ public:
+
+ ReporterRegistry();
+ ~ReporterRegistry() override; // = default, out of line to allow fwd decl
+
+ IEventListenerPtr create( std::string const& name, ReporterConfig&& config ) const override;
+
+ void registerReporter( std::string const& name, IReporterFactoryPtr factory );
+ void registerListener( Detail::unique_ptr<EventListenerFactory> factory );
+
+ FactoryMap const& getFactories() const override;
+ Listeners const& getListeners() const override;
+
+ private:
+ FactoryMap m_factories;
+ Listeners m_listeners;
+ };
+}
+
+#endif // CATCH_REPORTER_REGISTRY_HPP_INCLUDED
+
+
+#ifndef CATCH_RUN_CONTEXT_HPP_INCLUDED
+#define CATCH_RUN_CONTEXT_HPP_INCLUDED
+
+
+
+#ifndef CATCH_TEST_CASE_TRACKER_HPP_INCLUDED
+#define CATCH_TEST_CASE_TRACKER_HPP_INCLUDED
+
+
+#include <string>
+#include <vector>
+
+namespace Catch {
+namespace TestCaseTracking {
+
+ struct NameAndLocation {
+ std::string name;
+ SourceLineInfo location;
+
+ NameAndLocation( std::string const& _name, SourceLineInfo const& _location );
+ friend bool operator==(NameAndLocation const& lhs, NameAndLocation const& rhs) {
+ return lhs.name == rhs.name
+ && lhs.location == rhs.location;
+ }
+ };
+
+ class ITracker;
+
+ using ITrackerPtr = Catch::Detail::unique_ptr<ITracker>;
+
+ class ITracker {
+ NameAndLocation m_nameAndLocation;
+
+ using Children = std::vector<ITrackerPtr>;
+
+ protected:
+ enum CycleState {
+ NotStarted,
+ Executing,
+ ExecutingChildren,
+ NeedsAnotherRun,
+ CompletedSuccessfully,
+ Failed
+ };
+
+ ITracker* m_parent = nullptr;
+ Children m_children;
+ CycleState m_runState = NotStarted;
+
+ public:
+ ITracker( NameAndLocation const& nameAndLoc, ITracker* parent ):
+ m_nameAndLocation( nameAndLoc ),
+ m_parent( parent )
+ {}
+
+
+ // static queries
+ NameAndLocation const& nameAndLocation() const {
+ return m_nameAndLocation;
+ }
+ ITracker* parent() const {
+ return m_parent;
+ }
+
+ virtual ~ITracker(); // = default
+
+
+ // dynamic queries
+
+ //! Returns true if tracker run to completion (successfully or not)
+ virtual bool isComplete() const = 0;
+ //! Returns true if tracker run to completion succesfully
+ bool isSuccessfullyCompleted() const;
+ //! Returns true if tracker has started but hasn't been completed
+ bool isOpen() const;
+ //! Returns true iff tracker has started
+ bool hasStarted() const;
+
+ // actions
+ virtual void close() = 0; // Successfully complete
+ virtual void fail() = 0;
+ void markAsNeedingAnotherRun();
+
+ //! Register a nested ITracker
+ void addChild( ITrackerPtr&& child );
+ /**
+ * Returns ptr to specific child if register with this tracker.
+ *
+ * Returns nullptr if not found.
+ */
+ ITracker* findChild( NameAndLocation const& nameAndLocation );
+ //! Have any children been added?
+ bool hasChildren() const {
+ return !m_children.empty();
+ }
+
+
+ //! Marks tracker as executing a child, doing se recursively up the tree
+ void openChild();
+
+ /**
+ * Returns true if the instance is a section tracker
+ *
+ * Subclasses should override to true if they are, replaces RTTI
+ * for internal debug checks.
+ */
+ virtual bool isSectionTracker() const;
+ /**
+ * Returns true if the instance is a generator tracker
+ *
+ * Subclasses should override to true if they are, replaces RTTI
+ * for internal debug checks.
+ */
+ virtual bool isGeneratorTracker() const;
+ };
+
+ class TrackerContext {
+
+ enum RunState {
+ NotStarted,
+ Executing,
+ CompletedCycle
+ };
+
+ ITrackerPtr m_rootTracker;
+ ITracker* m_currentTracker = nullptr;
+ RunState m_runState = NotStarted;
+
+ public:
+
+ ITracker& startRun();
+ void endRun();
+
+ void startCycle();
+ void completeCycle();
+
+ bool completedCycle() const;
+ ITracker& currentTracker();
+ void setCurrentTracker( ITracker* tracker );
+ };
+
+ class TrackerBase : public ITracker {
+ protected:
+
+ TrackerContext& m_ctx;
+
+ public:
+ TrackerBase( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent );
+
+ bool isComplete() const override;
+
+ void open();
+
+ void close() override;
+ void fail() override;
+
+ private:
+ void moveToParent();
+ void moveToThis();
+ };
+
+ class SectionTracker : public TrackerBase {
+ std::vector<StringRef> m_filters;
+ std::string m_trimmed_name;
+ public:
+ SectionTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent );
+
+ bool isSectionTracker() const override;
+
+ bool isComplete() const override;
+
+ static SectionTracker& acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation );
+
+ void tryOpen();
+
+ void addInitialFilters( std::vector<std::string> const& filters );
+ void addNextFilters( std::vector<StringRef> const& filters );
+ //! Returns filters active in this tracker
+ std::vector<StringRef> const& getFilters() const;
+ //! Returns whitespace-trimmed name of the tracked section
+ StringRef trimmedName() const;
+ };
+
+} // namespace TestCaseTracking
+
+using TestCaseTracking::ITracker;
+using TestCaseTracking::TrackerContext;
+using TestCaseTracking::SectionTracker;
+
+} // namespace Catch
+
+#endif // CATCH_TEST_CASE_TRACKER_HPP_INCLUDED
+
+#include <string>
+
+namespace Catch {
+
+ class IMutableContext;
+ class IGeneratorTracker;
+ class IConfig;
+
+ ///////////////////////////////////////////////////////////////////////////
+
+ class RunContext : public IResultCapture {
+
+ public:
+ RunContext( RunContext const& ) = delete;
+ RunContext& operator =( RunContext const& ) = delete;
+
+ explicit RunContext( IConfig const* _config, IEventListenerPtr&& reporter );
+
+ ~RunContext() override;
+
+ Totals runTest(TestCaseHandle const& testCase);
+
+ public: // IResultCapture
+
+ // Assertion handlers
+ void handleExpr
+ ( AssertionInfo const& info,
+ ITransientExpression const& expr,
+ AssertionReaction& reaction ) override;
+ void handleMessage
+ ( AssertionInfo const& info,
+ ResultWas::OfType resultType,
+ StringRef message,
+ AssertionReaction& reaction ) override;
+ void handleUnexpectedExceptionNotThrown
+ ( AssertionInfo const& info,
+ AssertionReaction& reaction ) override;
+ void handleUnexpectedInflightException
+ ( AssertionInfo const& info,
+ std::string const& message,
+ AssertionReaction& reaction ) override;
+ void handleIncomplete
+ ( AssertionInfo const& info ) override;
+ void handleNonExpr
+ ( AssertionInfo const &info,
+ ResultWas::OfType resultType,
+ AssertionReaction &reaction ) override;
+
+ bool sectionStarted( SectionInfo const& sectionInfo, Counts& assertions ) override;
+
+ void sectionEnded( SectionEndInfo const& endInfo ) override;
+ void sectionEndedEarly( SectionEndInfo const& endInfo ) override;
+
+ auto acquireGeneratorTracker( StringRef generatorName, SourceLineInfo const& lineInfo ) -> IGeneratorTracker& override;
+
+ void benchmarkPreparing( StringRef name ) override;
+ void benchmarkStarting( BenchmarkInfo const& info ) override;
+ void benchmarkEnded( BenchmarkStats<> const& stats ) override;
+ void benchmarkFailed( StringRef error ) override;
+
+ void pushScopedMessage( MessageInfo const& message ) override;
+ void popScopedMessage( MessageInfo const& message ) override;
+
+ void emplaceUnscopedMessage( MessageBuilder const& builder ) override;
+
+ std::string getCurrentTestName() const override;
+
+ const AssertionResult* getLastResult() const override;
+
+ void exceptionEarlyReported() override;
+
+ void handleFatalErrorCondition( StringRef message ) override;
+
+ bool lastAssertionPassed() override;
+
+ void assertionPassed() override;
+
+ public:
+ // !TBD We need to do this another way!
+ bool aborting() const;
+
+ private:
+
+ void runCurrentTest( std::string& redirectedCout, std::string& redirectedCerr );
+ void invokeActiveTestCase();
+
+ void resetAssertionInfo();
+ bool testForMissingAssertions( Counts& assertions );
+
+ void assertionEnded( AssertionResult const& result );
+ void reportExpr
+ ( AssertionInfo const &info,
+ ResultWas::OfType resultType,
+ ITransientExpression const *expr,
+ bool negated );
+
+ void populateReaction( AssertionReaction& reaction );
+
+ private:
+
+ void handleUnfinishedSections();
+
+ TestRunInfo m_runInfo;
+ IMutableContext& m_context;
+ TestCaseHandle const* m_activeTestCase = nullptr;
+ ITracker* m_testCaseTracker = nullptr;
+ Optional<AssertionResult> m_lastResult;
+
+ IConfig const* m_config;
+ Totals m_totals;
+ IEventListenerPtr m_reporter;
+ std::vector<MessageInfo> m_messages;
+ std::vector<ScopedMessage> m_messageScopes; /* Keeps owners of so-called unscoped messages. */
+ AssertionInfo m_lastAssertionInfo;
+ std::vector<SectionEndInfo> m_unfinishedSections;
+ std::vector<ITracker*> m_activeSections;
+ TrackerContext m_trackerContext;
+ FatalConditionHandler m_fatalConditionhandler;
+ bool m_lastAssertionPassed = false;
+ bool m_shouldReportUnexpected = true;
+ bool m_includeSuccessfulResults;
+ };
+
+ void seedRng(IConfig const& config);
+ unsigned int rngSeed();
+} // end namespace Catch
+
+#endif // CATCH_RUN_CONTEXT_HPP_INCLUDED
+
+
+#ifndef CATCH_SHARDING_HPP_INCLUDED
+#define CATCH_SHARDING_HPP_INCLUDED
+
+
+#include <cmath>
+
+namespace Catch {
+
+ template<typename Container>
+ Container createShard(Container const& container, std::size_t const shardCount, std::size_t const shardIndex) {
+ assert(shardCount > shardIndex);
+
+ if (shardCount == 1) {
+ return container;
+ }
+
+ const std::size_t totalTestCount = container.size();
+
+ const std::size_t shardSize = totalTestCount / shardCount;
+ const std::size_t leftoverTests = totalTestCount % shardCount;
+
+ const std::size_t startIndex = shardIndex * shardSize + (std::min)(shardIndex, leftoverTests);
+ const std::size_t endIndex = (shardIndex + 1) * shardSize + (std::min)(shardIndex + 1, leftoverTests);
+
+ auto startIterator = std::next(container.begin(), static_cast<std::ptrdiff_t>(startIndex));
+ auto endIterator = std::next(container.begin(), static_cast<std::ptrdiff_t>(endIndex));
+
+ return Container(startIterator, endIterator);
+ }
+
+}
+
+#endif // CATCH_SHARDING_HPP_INCLUDED
+
+
+#ifndef CATCH_SINGLETONS_HPP_INCLUDED
+#define CATCH_SINGLETONS_HPP_INCLUDED
+
+namespace Catch {
+
+ struct ISingleton {
+ virtual ~ISingleton(); // = default
+ };
+
+
+ void addSingleton( ISingleton* singleton );
+ void cleanupSingletons();
+
+
+ template<typename SingletonImplT, typename InterfaceT = SingletonImplT, typename MutableInterfaceT = InterfaceT>
+ class Singleton : SingletonImplT, public ISingleton {
+
+ static auto getInternal() -> Singleton* {
+ static Singleton* s_instance = nullptr;
+ if( !s_instance ) {
+ s_instance = new Singleton;
+ addSingleton( s_instance );
+ }
+ return s_instance;
+ }
+
+ public:
+ static auto get() -> InterfaceT const& {
+ return *getInternal();
+ }
+ static auto getMutable() -> MutableInterfaceT& {
+ return *getInternal();
+ }
+ };
+
+} // namespace Catch
+
+#endif // CATCH_SINGLETONS_HPP_INCLUDED
+
+
+#ifndef CATCH_STARTUP_EXCEPTION_REGISTRY_HPP_INCLUDED
+#define CATCH_STARTUP_EXCEPTION_REGISTRY_HPP_INCLUDED
+
+
+#include <vector>
+#include <exception>
+
+namespace Catch {
+
+ class StartupExceptionRegistry {
+#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
+ public:
+ void add(std::exception_ptr const& exception) noexcept;
+ std::vector<std::exception_ptr> const& getExceptions() const noexcept;
+ private:
+ std::vector<std::exception_ptr> m_exceptions;
+#endif
+ };
+
+} // end namespace Catch
+
+#endif // CATCH_STARTUP_EXCEPTION_REGISTRY_HPP_INCLUDED
+
+
+
+#ifndef CATCH_STDSTREAMS_HPP_INCLUDED
+#define CATCH_STDSTREAMS_HPP_INCLUDED
+
+#include <iosfwd>
+
+namespace Catch {
+
+ std::ostream& cout();
+ std::ostream& cerr();
+ std::ostream& clog();
+
+} // namespace Catch
+
+#endif
+
+
+#ifndef CATCH_STRING_MANIP_HPP_INCLUDED
+#define CATCH_STRING_MANIP_HPP_INCLUDED
+
+
+#include <string>
+#include <iosfwd>
+#include <vector>
+
+namespace Catch {
+
+ bool startsWith( std::string const& s, std::string const& prefix );
+ bool startsWith( StringRef s, char prefix );
+ bool endsWith( std::string const& s, std::string const& suffix );
+ bool endsWith( std::string const& s, char suffix );
+ bool contains( std::string const& s, std::string const& infix );
+ void toLowerInPlace( std::string& s );
+ std::string toLower( std::string const& s );
+ char toLower( char c );
+ //! Returns a new string without whitespace at the start/end
+ std::string trim( std::string const& str );
+ //! Returns a substring of the original ref without whitespace. Beware lifetimes!
+ StringRef trim(StringRef ref);
+
+ // !!! Be aware, returns refs into original string - make sure original string outlives them
+ std::vector<StringRef> splitStringRef( StringRef str, char delimiter );
+ bool replaceInPlace( std::string& str, std::string const& replaceThis, std::string const& withThis );
+
+ /**
+ * Helper for streaming a "count [maybe-plural-of-label]" human-friendly string
+ *
+ * Usage example:
+ * ```cpp
+ * std::cout << "Found " << pluralise(count, "error") << '\n';
+ * ```
+ *
+ * **Important:** The provided string must outlive the instance
+ */
+ class pluralise {
+ std::uint64_t m_count;
+ StringRef m_label;
+
+ public:
+ constexpr pluralise(std::uint64_t count, StringRef label):
+ m_count(count),
+ m_label(label)
+ {}
+
+ friend std::ostream& operator << ( std::ostream& os, pluralise const& pluraliser );
+ };
+}
+
+#endif // CATCH_STRING_MANIP_HPP_INCLUDED
+
+
+#ifndef CATCH_TAG_ALIAS_REGISTRY_HPP_INCLUDED
+#define CATCH_TAG_ALIAS_REGISTRY_HPP_INCLUDED
+
+
+#include <map>
+#include <string>
+
+namespace Catch {
+ struct SourceLineInfo;
+
+ class TagAliasRegistry : public ITagAliasRegistry {
+ public:
+ ~TagAliasRegistry() override;
+ TagAlias const* find( std::string const& alias ) const override;
+ std::string expandAliases( std::string const& unexpandedTestSpec ) const override;
+ void add( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo );
+
+ private:
+ std::map<std::string, TagAlias> m_registry;
+ };
+
+} // end namespace Catch
+
+#endif // CATCH_TAG_ALIAS_REGISTRY_HPP_INCLUDED
+
+
+#ifndef CATCH_TEST_CASE_INFO_HASHER_HPP_INCLUDED
+#define CATCH_TEST_CASE_INFO_HASHER_HPP_INCLUDED
+
+#include <cstdint>
+
+namespace Catch {
+
+ struct TestCaseInfo;
+
+ class TestCaseInfoHasher {
+ public:
+ using hash_t = std::uint64_t;
+ TestCaseInfoHasher( hash_t seed );
+ uint32_t operator()( TestCaseInfo const& t ) const;
+
+ private:
+ hash_t m_seed;
+ };
+
+} // namespace Catch
+
+#endif /* CATCH_TEST_CASE_INFO_HASHER_HPP_INCLUDED */
+
+
+#ifndef CATCH_TEST_CASE_REGISTRY_IMPL_HPP_INCLUDED
+#define CATCH_TEST_CASE_REGISTRY_IMPL_HPP_INCLUDED
+
+
+#include <vector>
+
+namespace Catch {
+
+ class TestCaseHandle;
+ class IConfig;
+ class TestSpec;
+
+ std::vector<TestCaseHandle> sortTests( IConfig const& config, std::vector<TestCaseHandle> const& unsortedTestCases );
+
+ bool isThrowSafe( TestCaseHandle const& testCase, IConfig const& config );
+ bool matchTest( TestCaseHandle const& testCase, TestSpec const& testSpec, IConfig const& config );
+
+ void enforceNoDuplicateTestCases( std::vector<TestCaseHandle> const& functions );
+
+ std::vector<TestCaseHandle> filterTests( std::vector<TestCaseHandle> const& testCases, TestSpec const& testSpec, IConfig const& config );
+ std::vector<TestCaseHandle> const& getAllTestCasesSorted( IConfig const& config );
+
+ class TestRegistry : public ITestCaseRegistry {
+ public:
+ ~TestRegistry() override = default;
+
+ void registerTest( Detail::unique_ptr<TestCaseInfo> testInfo, Detail::unique_ptr<ITestInvoker> testInvoker );
+
+ std::vector<TestCaseInfo*> const& getAllInfos() const override;
+ std::vector<TestCaseHandle> const& getAllTests() const override;
+ std::vector<TestCaseHandle> const& getAllTestsSorted( IConfig const& config ) const override;
+
+ private:
+ std::vector<Detail::unique_ptr<TestCaseInfo>> m_owned_test_infos;
+ // Keeps a materialized vector for `getAllInfos`.
+ // We should get rid of that eventually (see interface note)
+ std::vector<TestCaseInfo*> m_viewed_test_infos;
+
+ std::vector<Detail::unique_ptr<ITestInvoker>> m_invokers;
+ std::vector<TestCaseHandle> m_handles;
+ mutable TestRunOrder m_currentSortOrder = TestRunOrder::Declared;
+ mutable std::vector<TestCaseHandle> m_sortedFunctions;
+ };
+
+ ///////////////////////////////////////////////////////////////////////////
+
+ class TestInvokerAsFunction final : public ITestInvoker {
+ using TestType = void(*)();
+ TestType m_testAsFunction;
+ public:
+ TestInvokerAsFunction(TestType testAsFunction) noexcept:
+ m_testAsFunction(testAsFunction) {}
+
+ void invoke() const override;
+ };
+
+ ///////////////////////////////////////////////////////////////////////////
+
+
+} // end namespace Catch
+
+
+#endif // CATCH_TEST_CASE_REGISTRY_IMPL_HPP_INCLUDED
+
+
+#ifndef CATCH_TEST_SPEC_PARSER_HPP_INCLUDED
+#define CATCH_TEST_SPEC_PARSER_HPP_INCLUDED
+
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wpadded"
+#endif
+
+
+#include <vector>
+#include <string>
+
+namespace Catch {
+
+ class ITagAliasRegistry;
+
+ class TestSpecParser {
+ enum Mode{ None, Name, QuotedName, Tag, EscapedName };
+ Mode m_mode = None;
+ Mode lastMode = None;
+ bool m_exclusion = false;
+ std::size_t m_pos = 0;
+ std::size_t m_realPatternPos = 0;
+ std::string m_arg;
+ std::string m_substring;
+ std::string m_patternName;
+ std::vector<std::size_t> m_escapeChars;
+ TestSpec::Filter m_currentFilter;
+ TestSpec m_testSpec;
+ ITagAliasRegistry const* m_tagAliases = nullptr;
+
+ public:
+ TestSpecParser( ITagAliasRegistry const& tagAliases );
+
+ TestSpecParser& parse( std::string const& arg );
+ TestSpec testSpec();
+
+ private:
+ bool visitChar( char c );
+ void startNewMode( Mode mode );
+ bool processNoneChar( char c );
+ void processNameChar( char c );
+ bool processOtherChar( char c );
+ void endMode();
+ void escape();
+ bool isControlChar( char c ) const;
+ void saveLastMode();
+ void revertBackToLastMode();
+ void addFilter();
+ bool separate();
+
+ // Handles common preprocessing of the pattern for name/tag patterns
+ std::string preprocessPattern();
+ // Adds the current pattern as a test name
+ void addNamePattern();
+ // Adds the current pattern as a tag
+ void addTagPattern();
+
+ inline void addCharToPattern(char c) {
+ m_substring += c;
+ m_patternName += c;
+ m_realPatternPos++;
+ }
+
+ };
+ TestSpec parseTestSpec( std::string const& arg );
+
+} // namespace Catch
+
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+
+#endif // CATCH_TEST_SPEC_PARSER_HPP_INCLUDED
+
+
+#ifndef CATCH_TEXTFLOW_HPP_INCLUDED
+#define CATCH_TEXTFLOW_HPP_INCLUDED
+
+#include <cassert>
+#include <string>
+#include <vector>
+
+namespace Catch {
+ namespace TextFlow {
+
+ class Columns;
+
+ /**
+ * Represents a column of text with specific width and indentation
+ *
+ * When written out to a stream, it will perform linebreaking
+ * of the provided text so that the written lines fit within
+ * target width.
+ */
+ class Column {
+ // String to be written out
+ std::string m_string;
+ // Width of the column for linebreaking
+ size_t m_width = CATCH_CONFIG_CONSOLE_WIDTH - 1;
+ // Indentation of other lines (including first if initial indent is unset)
+ size_t m_indent = 0;
+ // Indentation of the first line
+ size_t m_initialIndent = std::string::npos;
+
+ public:
+ /**
+ * Iterates "lines" in `Column` and return sthem
+ */
+ class const_iterator {
+ friend Column;
+ struct EndTag {};
+
+ Column const& m_column;
+ // Where does the current line start?
+ size_t m_lineStart = 0;
+ // How long should the current line be?
+ size_t m_lineLength = 0;
+ // How far have we checked the string to iterate?
+ size_t m_parsedTo = 0;
+ // Should a '-' be appended to the line?
+ bool m_addHyphen = false;
+
+ const_iterator( Column const& column, EndTag ):
+ m_column( column ), m_lineStart( m_column.m_string.size() ) {}
+
+ // Calculates the length of the current line
+ void calcLength();
+
+ // Returns current indention width
+ size_t indentSize() const;
+
+ // Creates an indented and (optionally) suffixed string from
+ // current iterator position, indentation and length.
+ std::string addIndentAndSuffix( size_t position,
+ size_t length ) const;
+
+ public:
+ using difference_type = std::ptrdiff_t;
+ using value_type = std::string;
+ using pointer = value_type*;
+ using reference = value_type&;
+ using iterator_category = std::forward_iterator_tag;
+
+ explicit const_iterator( Column const& column );
+
+ std::string operator*() const;
+
+ const_iterator& operator++();
+ const_iterator operator++( int );
+
+ bool operator==( const_iterator const& other ) const {
+ return m_lineStart == other.m_lineStart && &m_column == &other.m_column;
+ }
+ bool operator!=( const_iterator const& other ) const {
+ return !operator==( other );
+ }
+ };
+ using iterator = const_iterator;
+
+ explicit Column( std::string const& text ): m_string( text ) {}
+
+ Column& width( size_t newWidth ) {
+ assert( newWidth > 0 );
+ m_width = newWidth;
+ return *this;
+ }
+ Column& indent( size_t newIndent ) {
+ m_indent = newIndent;
+ return *this;
+ }
+ Column& initialIndent( size_t newIndent ) {
+ m_initialIndent = newIndent;
+ return *this;
+ }
+
+ size_t width() const { return m_width; }
+ const_iterator begin() const { return const_iterator( *this ); }
+ const_iterator end() const { return { *this, const_iterator::EndTag{} }; }
+
+ friend std::ostream& operator<<( std::ostream& os,
+ Column const& col );
+
+ Columns operator+( Column const& other );
+ };
+
+ //! Creates a column that serves as an empty space of specific width
+ Column Spacer( size_t spaceWidth );
+
+ class Columns {
+ std::vector<Column> m_columns;
+
+ public:
+ class iterator {
+ friend Columns;
+ struct EndTag {};
+
+ std::vector<Column> const& m_columns;
+ std::vector<Column::const_iterator> m_iterators;
+ size_t m_activeIterators;
+
+ iterator( Columns const& columns, EndTag );
+
+ public:
+ using difference_type = std::ptrdiff_t;
+ using value_type = std::string;
+ using pointer = value_type*;
+ using reference = value_type&;
+ using iterator_category = std::forward_iterator_tag;
+
+ explicit iterator( Columns const& columns );
+
+ auto operator==( iterator const& other ) const -> bool {
+ return m_iterators == other.m_iterators;
+ }
+ auto operator!=( iterator const& other ) const -> bool {
+ return m_iterators != other.m_iterators;
+ }
+ std::string operator*() const;
+ iterator& operator++();
+ iterator operator++( int );
+ };
+ using const_iterator = iterator;
+
+ iterator begin() const { return iterator( *this ); }
+ iterator end() const { return { *this, iterator::EndTag() }; }
+
+ Columns& operator+=( Column const& col );
+ Columns operator+( Column const& col );
+
+ friend std::ostream& operator<<( std::ostream& os,
+ Columns const& cols );
+ };
+
+ } // namespace TextFlow
+} // namespace Catch
+#endif // CATCH_TEXTFLOW_HPP_INCLUDED
+
+
+#ifndef CATCH_TO_STRING_HPP_INCLUDED
+#define CATCH_TO_STRING_HPP_INCLUDED
+
+#include <string>
+
+
+namespace Catch {
+ template <typename T>
+ std::string to_string(T const& t) {
+#if defined(CATCH_CONFIG_CPP11_TO_STRING)
+ return std::to_string(t);
+#else
+ ReusableStringStream rss;
+ rss << t;
+ return rss.str();
+#endif
+ }
+} // end namespace Catch
+
+#endif // CATCH_TO_STRING_HPP_INCLUDED
+
+
+#ifndef CATCH_UNCAUGHT_EXCEPTIONS_HPP_INCLUDED
+#define CATCH_UNCAUGHT_EXCEPTIONS_HPP_INCLUDED
+
+namespace Catch {
+ bool uncaught_exceptions();
+} // end namespace Catch
+
+#endif // CATCH_UNCAUGHT_EXCEPTIONS_HPP_INCLUDED
+
+
+#ifndef CATCH_WINDOWS_H_PROXY_HPP_INCLUDED
+#define CATCH_WINDOWS_H_PROXY_HPP_INCLUDED
+
+
+#if defined(CATCH_PLATFORM_WINDOWS)
+
+// We might end up with the define made globally through the compiler,
+// and we don't want to trigger warnings for this
+#if !defined(NOMINMAX)
+# define NOMINMAX
+#endif
+#if !defined(WIN32_LEAN_AND_MEAN)
+# define WIN32_LEAN_AND_MEAN
+#endif
+
+#ifdef __AFXDLL
+#include <AfxWin.h>
+#else
+#include <windows.h>
+#endif
+
+#endif // defined(CATCH_PLATFORM_WINDOWS)
+
+#endif // CATCH_WINDOWS_H_PROXY_HPP_INCLUDED
+
+
+#ifndef CATCH_XMLWRITER_HPP_INCLUDED
+#define CATCH_XMLWRITER_HPP_INCLUDED
+
+
+#include <iosfwd>
+#include <vector>
+
+namespace Catch {
+ enum class XmlFormatting {
+ None = 0x00,
+ Indent = 0x01,
+ Newline = 0x02,
+ };
+
+ XmlFormatting operator | (XmlFormatting lhs, XmlFormatting rhs);
+ XmlFormatting operator & (XmlFormatting lhs, XmlFormatting rhs);
+
+ /**
+ * Helper for XML-encoding text (escaping angle brackets, quotes, etc)
+ *
+ * Note: doesn't take ownership of passed strings, and thus the
+ * encoded string must outlive the encoding instance.
+ */
+ class XmlEncode {
+ public:
+ enum ForWhat { ForTextNodes, ForAttributes };
+
+ XmlEncode( StringRef str, ForWhat forWhat = ForTextNodes );
+
+ void encodeTo( std::ostream& os ) const;
+
+ friend std::ostream& operator << ( std::ostream& os, XmlEncode const& xmlEncode );
+
+ private:
+ StringRef m_str;
+ ForWhat m_forWhat;
+ };
+
+ class XmlWriter {
+ public:
+
+ class ScopedElement {
+ public:
+ ScopedElement( XmlWriter* writer, XmlFormatting fmt );
+
+ ScopedElement( ScopedElement&& other ) noexcept;
+ ScopedElement& operator=( ScopedElement&& other ) noexcept;
+
+ ~ScopedElement();
+
+ ScopedElement&
+ writeText( StringRef text,
+ XmlFormatting fmt = XmlFormatting::Newline |
+ XmlFormatting::Indent );
+
+ ScopedElement& writeAttribute( StringRef name,
+ StringRef attribute );
+ template <typename T,
+ // Without this SFINAE, this overload is a better match
+ // for `std::string`, `char const*`, `char const[N]` args.
+ // While it would still work, it would cause code bloat
+ // and multiple iteration over the strings
+ typename = typename std::enable_if_t<
+ !std::is_convertible<T, StringRef>::value>>
+ ScopedElement& writeAttribute( StringRef name,
+ T const& attribute ) {
+ m_writer->writeAttribute( name, attribute );
+ return *this;
+ }
+
+ private:
+ XmlWriter* m_writer = nullptr;
+ XmlFormatting m_fmt;
+ };
+
+ XmlWriter( std::ostream& os );
+ ~XmlWriter();
+
+ XmlWriter( XmlWriter const& ) = delete;
+ XmlWriter& operator=( XmlWriter const& ) = delete;
+
+ XmlWriter& startElement( std::string const& name, XmlFormatting fmt = XmlFormatting::Newline | XmlFormatting::Indent);
+
+ ScopedElement scopedElement( std::string const& name, XmlFormatting fmt = XmlFormatting::Newline | XmlFormatting::Indent);
+
+ XmlWriter& endElement(XmlFormatting fmt = XmlFormatting::Newline | XmlFormatting::Indent);
+
+ //! The attribute content is XML-encoded
+ XmlWriter& writeAttribute( StringRef name, StringRef attribute );
+
+ //! Writes the attribute as "true/false"
+ XmlWriter& writeAttribute( StringRef name, bool attribute );
+
+ //! The attribute content is XML-encoded
+ XmlWriter& writeAttribute( StringRef name, char const* attribute );
+
+ //! The attribute value must provide op<<(ostream&, T). The resulting
+ //! serialization is XML-encoded
+ template <typename T,
+ // Without this SFINAE, this overload is a better match
+ // for `std::string`, `char const*`, `char const[N]` args.
+ // While it would still work, it would cause code bloat
+ // and multiple iteration over the strings
+ typename = typename std::enable_if_t<
+ !std::is_convertible<T, StringRef>::value>>
+ XmlWriter& writeAttribute( StringRef name, T const& attribute ) {
+ ReusableStringStream rss;
+ rss << attribute;
+ return writeAttribute( name, rss.str() );
+ }
+
+ //! Writes escaped `text` in a element
+ XmlWriter& writeText( StringRef text,
+ XmlFormatting fmt = XmlFormatting::Newline |
+ XmlFormatting::Indent );
+
+ //! Writes XML comment as "<!-- text -->"
+ XmlWriter& writeComment( StringRef text,
+ XmlFormatting fmt = XmlFormatting::Newline |
+ XmlFormatting::Indent );
+
+ void writeStylesheetRef( StringRef url );
+
+ void ensureTagClosed();
+
+ private:
+
+ void applyFormatting(XmlFormatting fmt);
+
+ void writeDeclaration();
+
+ void newlineIfNecessary();
+
+ bool m_tagIsOpen = false;
+ bool m_needsNewline = false;
+ std::vector<std::string> m_tags;
+ std::string m_indent;
+ std::ostream& m_os;
+ };
+
+}
+
+#endif // CATCH_XMLWRITER_HPP_INCLUDED
+
+
+/** \file
+ * This is a convenience header for Catch2's Matcher support. It includes
+ * **all** of Catch2 headers related to matchers.
+ *
+ * Generally the Catch2 users should use specific includes they need,
+ * but this header can be used instead for ease-of-experimentation, or
+ * just plain convenience, at the cost of increased compilation times.
+ *
+ * When a new header is added to either the `matchers` folder, or to
+ * the corresponding internal subfolder, it should be added here.
+ */
+
+#ifndef CATCH_MATCHERS_ALL_HPP_INCLUDED
+#define CATCH_MATCHERS_ALL_HPP_INCLUDED
+
+
+
+#ifndef CATCH_MATCHERS_HPP_INCLUDED
+#define CATCH_MATCHERS_HPP_INCLUDED
+
+
+
+#ifndef CATCH_MATCHERS_IMPL_HPP_INCLUDED
+#define CATCH_MATCHERS_IMPL_HPP_INCLUDED
+
+
+namespace Catch {
+
+ template<typename ArgT, typename MatcherT>
+ class MatchExpr : public ITransientExpression {
+ ArgT && m_arg;
+ MatcherT const& m_matcher;
+ StringRef m_matcherString;
+ public:
+ MatchExpr( ArgT && arg, MatcherT const& matcher, StringRef matcherString )
+ : ITransientExpression{ true, matcher.match( arg ) }, // not forwarding arg here on purpose
+ m_arg( CATCH_FORWARD(arg) ),
+ m_matcher( matcher ),
+ m_matcherString( matcherString )
+ {}
+
+ void streamReconstructedExpression( std::ostream& os ) const override {
+ os << Catch::Detail::stringify( m_arg )
+ << ' '
+ << m_matcher.toString();
+ }
+ };
+
+ namespace Matchers {
+ template <typename ArgT>
+ class MatcherBase;
+ }
+
+ using StringMatcher = Matchers::MatcherBase<std::string>;
+
+ void handleExceptionMatchExpr( AssertionHandler& handler, StringMatcher const& matcher, StringRef matcherString );
+
+ template<typename ArgT, typename MatcherT>
+ auto makeMatchExpr( ArgT && arg, MatcherT const& matcher, StringRef matcherString ) -> MatchExpr<ArgT, MatcherT> {
+ return MatchExpr<ArgT, MatcherT>( CATCH_FORWARD(arg), matcher, matcherString );
+ }
+
+} // namespace Catch
+
+
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CHECK_THAT( macroName, matcher, resultDisposition, arg ) \
+ do { \
+ Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(arg) ", " CATCH_INTERNAL_STRINGIFY(matcher), resultDisposition ); \
+ INTERNAL_CATCH_TRY { \
+ catchAssertionHandler.handleExpr( Catch::makeMatchExpr( arg, matcher, #matcher##_catch_sr ) ); \
+ } INTERNAL_CATCH_CATCH( catchAssertionHandler ) \
+ INTERNAL_CATCH_REACT( catchAssertionHandler ) \
+ } while( false )
+
+
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CATCH_THROWS_MATCHES( macroName, exceptionType, resultDisposition, matcher, ... ) \
+ do { \
+ Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__) ", " CATCH_INTERNAL_STRINGIFY(exceptionType) ", " CATCH_INTERNAL_STRINGIFY(matcher), resultDisposition ); \
+ if( catchAssertionHandler.allowThrows() ) \
+ try { \
+ static_cast<void>(__VA_ARGS__ ); \
+ catchAssertionHandler.handleUnexpectedExceptionNotThrown(); \
+ } \
+ catch( exceptionType const& ex ) { \
+ catchAssertionHandler.handleExpr( Catch::makeMatchExpr( ex, matcher, #matcher##_catch_sr ) ); \
+ } \
+ catch( ... ) { \
+ catchAssertionHandler.handleUnexpectedInflightException(); \
+ } \
+ else \
+ catchAssertionHandler.handleThrowingCallSkipped(); \
+ INTERNAL_CATCH_REACT( catchAssertionHandler ) \
+ } while( false )
+
+
+#endif // CATCH_MATCHERS_IMPL_HPP_INCLUDED
+
+#include <string>
+#include <vector>
+
+namespace Catch {
+namespace Matchers {
+
+ class MatcherUntypedBase {
+ public:
+ MatcherUntypedBase() = default;
+
+ MatcherUntypedBase(MatcherUntypedBase const&) = default;
+ MatcherUntypedBase(MatcherUntypedBase&&) = default;
+
+ MatcherUntypedBase& operator = (MatcherUntypedBase const&) = delete;
+ MatcherUntypedBase& operator = (MatcherUntypedBase&&) = delete;
+
+ std::string toString() const;
+
+ protected:
+ virtual ~MatcherUntypedBase(); // = default;
+ virtual std::string describe() const = 0;
+ mutable std::string m_cachedToString;
+ };
+
+
+ template<typename T>
+ class MatcherBase : public MatcherUntypedBase {
+ public:
+ virtual bool match( T const& arg ) const = 0;
+ };
+
+ namespace Detail {
+
+ template<typename ArgT>
+ class MatchAllOf final : public MatcherBase<ArgT> {
+ std::vector<MatcherBase<ArgT> const*> m_matchers;
+
+ public:
+ MatchAllOf() = default;
+ MatchAllOf(MatchAllOf const&) = delete;
+ MatchAllOf& operator=(MatchAllOf const&) = delete;
+ MatchAllOf(MatchAllOf&&) = default;
+ MatchAllOf& operator=(MatchAllOf&&) = default;
+
+
+ bool match( ArgT const& arg ) const override {
+ for( auto matcher : m_matchers ) {
+ if (!matcher->match(arg))
+ return false;
+ }
+ return true;
+ }
+ std::string describe() const override {
+ std::string description;
+ description.reserve( 4 + m_matchers.size()*32 );
+ description += "( ";
+ bool first = true;
+ for( auto matcher : m_matchers ) {
+ if( first )
+ first = false;
+ else
+ description += " and ";
+ description += matcher->toString();
+ }
+ description += " )";
+ return description;
+ }
+
+ friend MatchAllOf operator&& (MatchAllOf&& lhs, MatcherBase<ArgT> const& rhs) {
+ lhs.m_matchers.push_back(&rhs);
+ return CATCH_MOVE(lhs);
+ }
+ friend MatchAllOf operator&& (MatcherBase<ArgT> const& lhs, MatchAllOf&& rhs) {
+ rhs.m_matchers.insert(rhs.m_matchers.begin(), &lhs);
+ return CATCH_MOVE(rhs);
+ }
+ };
+
+ //! lvalue overload is intentionally deleted, users should
+ //! not be trying to compose stored composition matchers
+ template<typename ArgT>
+ MatchAllOf<ArgT> operator&& (MatchAllOf<ArgT> const& lhs, MatcherBase<ArgT> const& rhs) = delete;
+ //! lvalue overload is intentionally deleted, users should
+ //! not be trying to compose stored composition matchers
+ template<typename ArgT>
+ MatchAllOf<ArgT> operator&& (MatcherBase<ArgT> const& lhs, MatchAllOf<ArgT> const& rhs) = delete;
+
+ template<typename ArgT>
+ class MatchAnyOf final : public MatcherBase<ArgT> {
+ std::vector<MatcherBase<ArgT> const*> m_matchers;
+ public:
+ MatchAnyOf() = default;
+ MatchAnyOf(MatchAnyOf const&) = delete;
+ MatchAnyOf& operator=(MatchAnyOf const&) = delete;
+ MatchAnyOf(MatchAnyOf&&) = default;
+ MatchAnyOf& operator=(MatchAnyOf&&) = default;
+
+ bool match( ArgT const& arg ) const override {
+ for( auto matcher : m_matchers ) {
+ if (matcher->match(arg))
+ return true;
+ }
+ return false;
+ }
+ std::string describe() const override {
+ std::string description;
+ description.reserve( 4 + m_matchers.size()*32 );
+ description += "( ";
+ bool first = true;
+ for( auto matcher : m_matchers ) {
+ if( first )
+ first = false;
+ else
+ description += " or ";
+ description += matcher->toString();
+ }
+ description += " )";
+ return description;
+ }
+
+ friend MatchAnyOf operator|| (MatchAnyOf&& lhs, MatcherBase<ArgT> const& rhs) {
+ lhs.m_matchers.push_back(&rhs);
+ return CATCH_MOVE(lhs);
+ }
+ friend MatchAnyOf operator|| (MatcherBase<ArgT> const& lhs, MatchAnyOf&& rhs) {
+ rhs.m_matchers.insert(rhs.m_matchers.begin(), &lhs);
+ return CATCH_MOVE(rhs);
+ }
+ };
+
+ //! lvalue overload is intentionally deleted, users should
+ //! not be trying to compose stored composition matchers
+ template<typename ArgT>
+ MatchAnyOf<ArgT> operator|| (MatchAnyOf<ArgT> const& lhs, MatcherBase<ArgT> const& rhs) = delete;
+ //! lvalue overload is intentionally deleted, users should
+ //! not be trying to compose stored composition matchers
+ template<typename ArgT>
+ MatchAnyOf<ArgT> operator|| (MatcherBase<ArgT> const& lhs, MatchAnyOf<ArgT> const& rhs) = delete;
+
+ template<typename ArgT>
+ class MatchNotOf final : public MatcherBase<ArgT> {
+ MatcherBase<ArgT> const& m_underlyingMatcher;
+
+ public:
+ explicit MatchNotOf( MatcherBase<ArgT> const& underlyingMatcher ):
+ m_underlyingMatcher( underlyingMatcher )
+ {}
+
+ bool match( ArgT const& arg ) const override {
+ return !m_underlyingMatcher.match( arg );
+ }
+
+ std::string describe() const override {
+ return "not " + m_underlyingMatcher.toString();
+ }
+ };
+
+ } // namespace Detail
+
+ template <typename T>
+ Detail::MatchAllOf<T> operator&& (MatcherBase<T> const& lhs, MatcherBase<T> const& rhs) {
+ return Detail::MatchAllOf<T>{} && lhs && rhs;
+ }
+ template <typename T>
+ Detail::MatchAnyOf<T> operator|| (MatcherBase<T> const& lhs, MatcherBase<T> const& rhs) {
+ return Detail::MatchAnyOf<T>{} || lhs || rhs;
+ }
+
+ template <typename T>
+ Detail::MatchNotOf<T> operator! (MatcherBase<T> const& matcher) {
+ return Detail::MatchNotOf<T>{ matcher };
+ }
+
+
+} // namespace Matchers
+} // namespace Catch
+
+
+#if defined(CATCH_CONFIG_PREFIX_ALL) && !defined(CATCH_CONFIG_DISABLE)
+ #define CATCH_REQUIRE_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS_STR_MATCHES( "CATCH_REQUIRE_THROWS_WITH", Catch::ResultDisposition::Normal, matcher, expr )
+ #define CATCH_REQUIRE_THROWS_MATCHES( expr, exceptionType, matcher ) INTERNAL_CATCH_THROWS_MATCHES( "CATCH_REQUIRE_THROWS_MATCHES", exceptionType, Catch::ResultDisposition::Normal, matcher, expr )
+
+ #define CATCH_CHECK_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS_STR_MATCHES( "CATCH_CHECK_THROWS_WITH", Catch::ResultDisposition::ContinueOnFailure, matcher, expr )
+ #define CATCH_CHECK_THROWS_MATCHES( expr, exceptionType, matcher ) INTERNAL_CATCH_THROWS_MATCHES( "CATCH_CHECK_THROWS_MATCHES", exceptionType, Catch::ResultDisposition::ContinueOnFailure, matcher, expr )
+
+ #define CATCH_CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( "CATCH_CHECK_THAT", matcher, Catch::ResultDisposition::ContinueOnFailure, arg )
+ #define CATCH_REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT( "CATCH_REQUIRE_THAT", matcher, Catch::ResultDisposition::Normal, arg )
+
+#elif defined(CATCH_CONFIG_PREFIX_ALL) && defined(CATCH_CONFIG_DISABLE)
+
+ #define CATCH_REQUIRE_THROWS_WITH( expr, matcher ) (void)(0)
+ #define CATCH_REQUIRE_THROWS_MATCHES( expr, exceptionType, matcher ) (void)(0)
+
+ #define CATCH_CHECK_THROWS_WITH( expr, matcher ) (void)(0)
+ #define CATCH_CHECK_THROWS_MATCHES( expr, exceptionType, matcher ) (void)(0)
+
+ #define CATCH_CHECK_THAT( arg, matcher ) (void)(0)
+ #define CATCH_REQUIRE_THAT( arg, matcher ) (void)(0)
+
+#elif !defined(CATCH_CONFIG_PREFIX_ALL) && !defined(CATCH_CONFIG_DISABLE)
+
+ #define REQUIRE_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS_STR_MATCHES( "REQUIRE_THROWS_WITH", Catch::ResultDisposition::Normal, matcher, expr )
+ #define REQUIRE_THROWS_MATCHES( expr, exceptionType, matcher ) INTERNAL_CATCH_THROWS_MATCHES( "REQUIRE_THROWS_MATCHES", exceptionType, Catch::ResultDisposition::Normal, matcher, expr )
+
+ #define CHECK_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS_STR_MATCHES( "CHECK_THROWS_WITH", Catch::ResultDisposition::ContinueOnFailure, matcher, expr )
+ #define CHECK_THROWS_MATCHES( expr, exceptionType, matcher ) INTERNAL_CATCH_THROWS_MATCHES( "CHECK_THROWS_MATCHES", exceptionType, Catch::ResultDisposition::ContinueOnFailure, matcher, expr )
+
+ #define CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( "CHECK_THAT", matcher, Catch::ResultDisposition::ContinueOnFailure, arg )
+ #define REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT( "REQUIRE_THAT", matcher, Catch::ResultDisposition::Normal, arg )
+
+#elif !defined(CATCH_CONFIG_PREFIX_ALL) && defined(CATCH_CONFIG_DISABLE)
+
+ #define REQUIRE_THROWS_WITH( expr, matcher ) (void)(0)
+ #define REQUIRE_THROWS_MATCHES( expr, exceptionType, matcher ) (void)(0)
+
+ #define CHECK_THROWS_WITH( expr, matcher ) (void)(0)
+ #define CHECK_THROWS_MATCHES( expr, exceptionType, matcher ) (void)(0)
+
+ #define CHECK_THAT( arg, matcher ) (void)(0)
+ #define REQUIRE_THAT( arg, matcher ) (void)(0)
+
+#endif // end of user facing macro declarations
+
+#endif // CATCH_MATCHERS_HPP_INCLUDED
+
+
+#ifndef CATCH_MATCHERS_CONTAINER_PROPERTIES_HPP_INCLUDED
+#define CATCH_MATCHERS_CONTAINER_PROPERTIES_HPP_INCLUDED
+
+
+
+#ifndef CATCH_MATCHERS_TEMPLATED_HPP_INCLUDED
+#define CATCH_MATCHERS_TEMPLATED_HPP_INCLUDED
+
+
+#include <array>
+#include <algorithm>
+#include <string>
+#include <type_traits>
+
+namespace Catch {
+namespace Matchers {
+ class MatcherGenericBase : public MatcherUntypedBase {
+ public:
+ MatcherGenericBase() = default;
+ ~MatcherGenericBase() override; // = default;
+
+ MatcherGenericBase(MatcherGenericBase&) = default;
+ MatcherGenericBase(MatcherGenericBase&&) = default;
+
+ MatcherGenericBase& operator=(MatcherGenericBase const&) = delete;
+ MatcherGenericBase& operator=(MatcherGenericBase&&) = delete;
+ };
+
+
+ namespace Detail {
+ template<std::size_t N, std::size_t M>
+ std::array<void const*, N + M> array_cat(std::array<void const*, N> && lhs, std::array<void const*, M> && rhs) {
+ std::array<void const*, N + M> arr{};
+ std::copy_n(lhs.begin(), N, arr.begin());
+ std::copy_n(rhs.begin(), M, arr.begin() + N);
+ return arr;
+ }
+
+ template<std::size_t N>
+ std::array<void const*, N+1> array_cat(std::array<void const*, N> && lhs, void const* rhs) {
+ std::array<void const*, N+1> arr{};
+ std::copy_n(lhs.begin(), N, arr.begin());
+ arr[N] = rhs;
+ return arr;
+ }
+
+ template<std::size_t N>
+ std::array<void const*, N+1> array_cat(void const* lhs, std::array<void const*, N> && rhs) {
+ std::array<void const*, N + 1> arr{ {lhs} };
+ std::copy_n(rhs.begin(), N, arr.begin() + 1);
+ return arr;
+ }
+
+#if defined( __cpp_lib_logical_traits ) && __cpp_lib_logical_traits >= 201510
+
+ using std::conjunction;
+
+#else // __cpp_lib_logical_traits
+
+ template<typename... Cond>
+ struct conjunction : std::true_type {};
+
+ template<typename Cond, typename... Rest>
+ struct conjunction<Cond, Rest...> : std::integral_constant<bool, Cond::value && conjunction<Rest...>::value> {};
+
+#endif // __cpp_lib_logical_traits
+
+ template<typename T>
+ using is_generic_matcher = std::is_base_of<
+ Catch::Matchers::MatcherGenericBase,
+ std::remove_cv_t<std::remove_reference_t<T>>
+ >;
+
+ template<typename... Ts>
+ using are_generic_matchers = conjunction<is_generic_matcher<Ts>...>;
+
+ template<typename T>
+ using is_matcher = std::is_base_of<
+ Catch::Matchers::MatcherUntypedBase,
+ std::remove_cv_t<std::remove_reference_t<T>>
+ >;
+
+
+ template<std::size_t N, typename Arg>
+ bool match_all_of(Arg&&, std::array<void const*, N> const&, std::index_sequence<>) {
+ return true;
+ }
+
+ template<typename T, typename... MatcherTs, std::size_t N, typename Arg, std::size_t Idx, std::size_t... Indices>
+ bool match_all_of(Arg&& arg, std::array<void const*, N> const& matchers, std::index_sequence<Idx, Indices...>) {
+ return static_cast<T const*>(matchers[Idx])->match(arg) && match_all_of<MatcherTs...>(arg, matchers, std::index_sequence<Indices...>{});
+ }
+
+
+ template<std::size_t N, typename Arg>
+ bool match_any_of(Arg&&, std::array<void const*, N> const&, std::index_sequence<>) {
+ return false;
+ }
+
+ template<typename T, typename... MatcherTs, std::size_t N, typename Arg, std::size_t Idx, std::size_t... Indices>
+ bool match_any_of(Arg&& arg, std::array<void const*, N> const& matchers, std::index_sequence<Idx, Indices...>) {
+ return static_cast<T const*>(matchers[Idx])->match(arg) || match_any_of<MatcherTs...>(arg, matchers, std::index_sequence<Indices...>{});
+ }
+
+ std::string describe_multi_matcher(StringRef combine, std::string const* descriptions_begin, std::string const* descriptions_end);
+
+ template<typename... MatcherTs, std::size_t... Idx>
+ std::string describe_multi_matcher(StringRef combine, std::array<void const*, sizeof...(MatcherTs)> const& matchers, std::index_sequence<Idx...>) {
+ std::array<std::string, sizeof...(MatcherTs)> descriptions {{
+ static_cast<MatcherTs const*>(matchers[Idx])->toString()...
+ }};
+
+ return describe_multi_matcher(combine, descriptions.data(), descriptions.data() + descriptions.size());
+ }
+
+
+ template<typename... MatcherTs>
+ class MatchAllOfGeneric final : public MatcherGenericBase {
+ public:
+ MatchAllOfGeneric(MatchAllOfGeneric const&) = delete;
+ MatchAllOfGeneric& operator=(MatchAllOfGeneric const&) = delete;
+ MatchAllOfGeneric(MatchAllOfGeneric&&) = default;
+ MatchAllOfGeneric& operator=(MatchAllOfGeneric&&) = default;
+
+ MatchAllOfGeneric(MatcherTs const&... matchers) : m_matchers{ {std::addressof(matchers)...} } {}
+ explicit MatchAllOfGeneric(std::array<void const*, sizeof...(MatcherTs)> matchers) : m_matchers{matchers} {}
+
+ template<typename Arg>
+ bool match(Arg&& arg) const {
+ return match_all_of<MatcherTs...>(arg, m_matchers, std::index_sequence_for<MatcherTs...>{});
+ }
+
+ std::string describe() const override {
+ return describe_multi_matcher<MatcherTs...>(" and "_sr, m_matchers, std::index_sequence_for<MatcherTs...>{});
+ }
+
+ // Has to be public to enable the concatenating operators
+ // below, because they are not friend of the RHS, only LHS,
+ // and thus cannot access private fields of RHS
+ std::array<void const*, sizeof...( MatcherTs )> m_matchers;
+
+
+ //! Avoids type nesting for `GenericAllOf && GenericAllOf` case
+ template<typename... MatchersRHS>
+ friend
+ MatchAllOfGeneric<MatcherTs..., MatchersRHS...> operator && (
+ MatchAllOfGeneric<MatcherTs...>&& lhs,
+ MatchAllOfGeneric<MatchersRHS...>&& rhs) {
+ return MatchAllOfGeneric<MatcherTs..., MatchersRHS...>{array_cat(CATCH_MOVE(lhs.m_matchers), CATCH_MOVE(rhs.m_matchers))};
+ }
+
+ //! Avoids type nesting for `GenericAllOf && some matcher` case
+ template<typename MatcherRHS>
+ friend std::enable_if_t<is_matcher<MatcherRHS>::value,
+ MatchAllOfGeneric<MatcherTs..., MatcherRHS>> operator && (
+ MatchAllOfGeneric<MatcherTs...>&& lhs,
+ MatcherRHS const& rhs) {
+ return MatchAllOfGeneric<MatcherTs..., MatcherRHS>{array_cat(CATCH_MOVE(lhs.m_matchers), static_cast<void const*>(&rhs))};
+ }
+
+ //! Avoids type nesting for `some matcher && GenericAllOf` case
+ template<typename MatcherLHS>
+ friend std::enable_if_t<is_matcher<MatcherLHS>::value,
+ MatchAllOfGeneric<MatcherLHS, MatcherTs...>> operator && (
+ MatcherLHS const& lhs,
+ MatchAllOfGeneric<MatcherTs...>&& rhs) {
+ return MatchAllOfGeneric<MatcherLHS, MatcherTs...>{array_cat(static_cast<void const*>(std::addressof(lhs)), CATCH_MOVE(rhs.m_matchers))};
+ }
+ };
+
+
+ template<typename... MatcherTs>
+ class MatchAnyOfGeneric final : public MatcherGenericBase {
+ public:
+ MatchAnyOfGeneric(MatchAnyOfGeneric const&) = delete;
+ MatchAnyOfGeneric& operator=(MatchAnyOfGeneric const&) = delete;
+ MatchAnyOfGeneric(MatchAnyOfGeneric&&) = default;
+ MatchAnyOfGeneric& operator=(MatchAnyOfGeneric&&) = default;
+
+ MatchAnyOfGeneric(MatcherTs const&... matchers) : m_matchers{ {std::addressof(matchers)...} } {}
+ explicit MatchAnyOfGeneric(std::array<void const*, sizeof...(MatcherTs)> matchers) : m_matchers{matchers} {}
+
+ template<typename Arg>
+ bool match(Arg&& arg) const {
+ return match_any_of<MatcherTs...>(arg, m_matchers, std::index_sequence_for<MatcherTs...>{});
+ }
+
+ std::string describe() const override {
+ return describe_multi_matcher<MatcherTs...>(" or "_sr, m_matchers, std::index_sequence_for<MatcherTs...>{});
+ }
+
+
+ // Has to be public to enable the concatenating operators
+ // below, because they are not friend of the RHS, only LHS,
+ // and thus cannot access private fields of RHS
+ std::array<void const*, sizeof...( MatcherTs )> m_matchers;
+
+ //! Avoids type nesting for `GenericAnyOf || GenericAnyOf` case
+ template<typename... MatchersRHS>
+ friend MatchAnyOfGeneric<MatcherTs..., MatchersRHS...> operator || (
+ MatchAnyOfGeneric<MatcherTs...>&& lhs,
+ MatchAnyOfGeneric<MatchersRHS...>&& rhs) {
+ return MatchAnyOfGeneric<MatcherTs..., MatchersRHS...>{array_cat(CATCH_MOVE(lhs.m_matchers), CATCH_MOVE(rhs.m_matchers))};
+ }
+
+ //! Avoids type nesting for `GenericAnyOf || some matcher` case
+ template<typename MatcherRHS>
+ friend std::enable_if_t<is_matcher<MatcherRHS>::value,
+ MatchAnyOfGeneric<MatcherTs..., MatcherRHS>> operator || (
+ MatchAnyOfGeneric<MatcherTs...>&& lhs,
+ MatcherRHS const& rhs) {
+ return MatchAnyOfGeneric<MatcherTs..., MatcherRHS>{array_cat(CATCH_MOVE(lhs.m_matchers), static_cast<void const*>(std::addressof(rhs)))};
+ }
+
+ //! Avoids type nesting for `some matcher || GenericAnyOf` case
+ template<typename MatcherLHS>
+ friend std::enable_if_t<is_matcher<MatcherLHS>::value,
+ MatchAnyOfGeneric<MatcherLHS, MatcherTs...>> operator || (
+ MatcherLHS const& lhs,
+ MatchAnyOfGeneric<MatcherTs...>&& rhs) {
+ return MatchAnyOfGeneric<MatcherLHS, MatcherTs...>{array_cat(static_cast<void const*>(std::addressof(lhs)), CATCH_MOVE(rhs.m_matchers))};
+ }
+ };
+
+
+ template<typename MatcherT>
+ class MatchNotOfGeneric final : public MatcherGenericBase {
+ MatcherT const& m_matcher;
+
+ public:
+ MatchNotOfGeneric(MatchNotOfGeneric const&) = delete;
+ MatchNotOfGeneric& operator=(MatchNotOfGeneric const&) = delete;
+ MatchNotOfGeneric(MatchNotOfGeneric&&) = default;
+ MatchNotOfGeneric& operator=(MatchNotOfGeneric&&) = default;
+
+ explicit MatchNotOfGeneric(MatcherT const& matcher) : m_matcher{matcher} {}
+
+ template<typename Arg>
+ bool match(Arg&& arg) const {
+ return !m_matcher.match(arg);
+ }
+
+ std::string describe() const override {
+ return "not " + m_matcher.toString();
+ }
+
+ //! Negating negation can just unwrap and return underlying matcher
+ friend MatcherT const& operator ! (MatchNotOfGeneric<MatcherT> const& matcher) {
+ return matcher.m_matcher;
+ }
+ };
+ } // namespace Detail
+
+
+ // compose only generic matchers
+ template<typename MatcherLHS, typename MatcherRHS>
+ std::enable_if_t<Detail::are_generic_matchers<MatcherLHS, MatcherRHS>::value, Detail::MatchAllOfGeneric<MatcherLHS, MatcherRHS>>
+ operator && (MatcherLHS const& lhs, MatcherRHS const& rhs) {
+ return { lhs, rhs };
+ }
+
+ template<typename MatcherLHS, typename MatcherRHS>
+ std::enable_if_t<Detail::are_generic_matchers<MatcherLHS, MatcherRHS>::value, Detail::MatchAnyOfGeneric<MatcherLHS, MatcherRHS>>
+ operator || (MatcherLHS const& lhs, MatcherRHS const& rhs) {
+ return { lhs, rhs };
+ }
+
+ //! Wrap provided generic matcher in generic negator
+ template<typename MatcherT>
+ std::enable_if_t<Detail::is_generic_matcher<MatcherT>::value, Detail::MatchNotOfGeneric<MatcherT>>
+ operator ! (MatcherT const& matcher) {
+ return Detail::MatchNotOfGeneric<MatcherT>{matcher};
+ }
+
+
+ // compose mixed generic and non-generic matchers
+ template<typename MatcherLHS, typename ArgRHS>
+ std::enable_if_t<Detail::is_generic_matcher<MatcherLHS>::value, Detail::MatchAllOfGeneric<MatcherLHS, MatcherBase<ArgRHS>>>
+ operator && (MatcherLHS const& lhs, MatcherBase<ArgRHS> const& rhs) {
+ return { lhs, rhs };
+ }
+
+ template<typename ArgLHS, typename MatcherRHS>
+ std::enable_if_t<Detail::is_generic_matcher<MatcherRHS>::value, Detail::MatchAllOfGeneric<MatcherBase<ArgLHS>, MatcherRHS>>
+ operator && (MatcherBase<ArgLHS> const& lhs, MatcherRHS const& rhs) {
+ return { lhs, rhs };
+ }
+
+ template<typename MatcherLHS, typename ArgRHS>
+ std::enable_if_t<Detail::is_generic_matcher<MatcherLHS>::value, Detail::MatchAnyOfGeneric<MatcherLHS, MatcherBase<ArgRHS>>>
+ operator || (MatcherLHS const& lhs, MatcherBase<ArgRHS> const& rhs) {
+ return { lhs, rhs };
+ }
+
+ template<typename ArgLHS, typename MatcherRHS>
+ std::enable_if_t<Detail::is_generic_matcher<MatcherRHS>::value, Detail::MatchAnyOfGeneric<MatcherBase<ArgLHS>, MatcherRHS>>
+ operator || (MatcherBase<ArgLHS> const& lhs, MatcherRHS const& rhs) {
+ return { lhs, rhs };
+ }
+
+} // namespace Matchers
+} // namespace Catch
+
+#endif // CATCH_MATCHERS_TEMPLATED_HPP_INCLUDED
+
+namespace Catch {
+ namespace Matchers {
+
+ class IsEmptyMatcher final : public MatcherGenericBase {
+ public:
+ template <typename RangeLike>
+ bool match(RangeLike&& rng) const {
+#if defined(CATCH_CONFIG_POLYFILL_NONMEMBER_CONTAINER_ACCESS)
+ using Catch::Detail::empty;
+#else
+ using std::empty;
+#endif
+ return empty(rng);
+ }
+
+ std::string describe() const override;
+ };
+
+ class HasSizeMatcher final : public MatcherGenericBase {
+ std::size_t m_target_size;
+ public:
+ explicit HasSizeMatcher(std::size_t target_size):
+ m_target_size(target_size)
+ {}
+
+ template <typename RangeLike>
+ bool match(RangeLike&& rng) const {
+#if defined(CATCH_CONFIG_POLYFILL_NONMEMBER_CONTAINER_ACCESS)
+ using Catch::Detail::size;
+#else
+ using std::size;
+#endif
+ return size(rng) == m_target_size;
+ }
+
+ std::string describe() const override;
+ };
+
+ template <typename Matcher>
+ class SizeMatchesMatcher final : public MatcherGenericBase {
+ Matcher m_matcher;
+ public:
+ explicit SizeMatchesMatcher(Matcher m):
+ m_matcher(CATCH_MOVE(m))
+ {}
+
+ template <typename RangeLike>
+ bool match(RangeLike&& rng) const {
+#if defined(CATCH_CONFIG_POLYFILL_NONMEMBER_CONTAINER_ACCESS)
+ using Catch::Detail::size;
+#else
+ using std::size;
+#endif
+ return m_matcher.match(size(rng));
+ }
+
+ std::string describe() const override {
+ return "size matches " + m_matcher.describe();
+ }
+ };
+
+
+ //! Creates a matcher that accepts empty ranges/containers
+ IsEmptyMatcher IsEmpty();
+ //! Creates a matcher that accepts ranges/containers with specific size
+ HasSizeMatcher SizeIs(std::size_t sz);
+ template <typename Matcher>
+ std::enable_if_t<Detail::is_matcher<Matcher>::value,
+ SizeMatchesMatcher<Matcher>> SizeIs(Matcher&& m) {
+ return SizeMatchesMatcher<Matcher>{CATCH_FORWARD(m)};
+ }
+
+ } // end namespace Matchers
+} // end namespace Catch
+
+#endif // CATCH_MATCHERS_CONTAINER_PROPERTIES_HPP_INCLUDED
+
+
+#ifndef CATCH_MATCHERS_CONTAINS_HPP_INCLUDED
+#define CATCH_MATCHERS_CONTAINS_HPP_INCLUDED
+
+
+#include <algorithm>
+#include <functional>
+
+namespace Catch {
+ namespace Matchers {
+ //! Matcher for checking that an element in range is equal to specific element
+ template <typename T, typename Equality>
+ class ContainsElementMatcher final : public MatcherGenericBase {
+ T m_desired;
+ Equality m_eq;
+ public:
+ template <typename T2, typename Equality2>
+ ContainsElementMatcher(T2&& target, Equality2&& predicate):
+ m_desired(CATCH_FORWARD(target)),
+ m_eq(CATCH_FORWARD(predicate))
+ {}
+
+ std::string describe() const override {
+ return "contains element " + Catch::Detail::stringify(m_desired);
+ }
+
+ template <typename RangeLike>
+ bool match(RangeLike&& rng) const {
+ using std::begin; using std::end;
+
+ return end(rng) != std::find_if(begin(rng), end(rng),
+ [&](auto const& elem) {
+ return m_eq(elem, m_desired);
+ });
+ }
+ };
+
+ //! Meta-matcher for checking that an element in a range matches a specific matcher
+ template <typename Matcher>
+ class ContainsMatcherMatcher final : public MatcherGenericBase {
+ Matcher m_matcher;
+ public:
+ // Note that we do a copy+move to avoid having to SFINAE this
+ // constructor (and also avoid some perfect forwarding failure
+ // cases)
+ ContainsMatcherMatcher(Matcher matcher):
+ m_matcher(CATCH_MOVE(matcher))
+ {}
+
+ template <typename RangeLike>
+ bool match(RangeLike&& rng) const {
+ for (auto&& elem : rng) {
+ if (m_matcher.match(elem)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ std::string describe() const override {
+ return "contains element matching " + m_matcher.describe();
+ }
+ };
+
+ /**
+ * Creates a matcher that checks whether a range contains a specific element.
+ *
+ * Uses `std::equal_to` to do the comparison
+ */
+ template <typename T>
+ std::enable_if_t<!Detail::is_matcher<T>::value,
+ ContainsElementMatcher<T, std::equal_to<>>> Contains(T&& elem) {
+ return { CATCH_FORWARD(elem), std::equal_to<>{} };
+ }
+
+ //! Creates a matcher that checks whether a range contains element matching a matcher
+ template <typename Matcher>
+ std::enable_if_t<Detail::is_matcher<Matcher>::value,
+ ContainsMatcherMatcher<Matcher>> Contains(Matcher&& matcher) {
+ return { CATCH_FORWARD(matcher) };
+ }
+
+ /**
+ * Creates a matcher that checks whether a range contains a specific element.
+ *
+ * Uses `eq` to do the comparisons
+ */
+ template <typename T, typename Equality>
+ ContainsElementMatcher<T, Equality> Contains(T&& elem, Equality&& eq) {
+ return { CATCH_FORWARD(elem), CATCH_FORWARD(eq) };
+ }
+
+ }
+}
+
+#endif // CATCH_MATCHERS_CONTAINS_HPP_INCLUDED
+
+
+#ifndef CATCH_MATCHERS_EXCEPTION_HPP_INCLUDED
+#define CATCH_MATCHERS_EXCEPTION_HPP_INCLUDED
+
+
+namespace Catch {
+namespace Matchers {
+
+class ExceptionMessageMatcher final : public MatcherBase<std::exception> {
+ std::string m_message;
+public:
+
+ ExceptionMessageMatcher(std::string const& message):
+ m_message(message)
+ {}
+
+ bool match(std::exception const& ex) const override;
+
+ std::string describe() const override;
+};
+
+//! Creates a matcher that checks whether a std derived exception has the provided message
+ExceptionMessageMatcher Message(std::string const& message);
+
+} // namespace Matchers
+} // namespace Catch
+
+#endif // CATCH_MATCHERS_EXCEPTION_HPP_INCLUDED
+
+
+#ifndef CATCH_MATCHERS_FLOATING_POINT_HPP_INCLUDED
+#define CATCH_MATCHERS_FLOATING_POINT_HPP_INCLUDED
+
+
+namespace Catch {
+namespace Matchers {
+
+ namespace Detail {
+ enum class FloatingPointKind : uint8_t;
+ }
+
+ class WithinAbsMatcher final : public MatcherBase<double> {
+ public:
+ WithinAbsMatcher(double target, double margin);
+ bool match(double const& matchee) const override;
+ std::string describe() const override;
+ private:
+ double m_target;
+ double m_margin;
+ };
+
+ class WithinUlpsMatcher final : public MatcherBase<double> {
+ public:
+ WithinUlpsMatcher( double target,
+ uint64_t ulps,
+ Detail::FloatingPointKind baseType );
+ bool match(double const& matchee) const override;
+ std::string describe() const override;
+ private:
+ double m_target;
+ uint64_t m_ulps;
+ Detail::FloatingPointKind m_type;
+ };
+
+ // Given IEEE-754 format for floats and doubles, we can assume
+ // that float -> double promotion is lossless. Given this, we can
+ // assume that if we do the standard relative comparison of
+ // |lhs - rhs| <= epsilon * max(fabs(lhs), fabs(rhs)), then we get
+ // the same result if we do this for floats, as if we do this for
+ // doubles that were promoted from floats.
+ class WithinRelMatcher final : public MatcherBase<double> {
+ public:
+ WithinRelMatcher( double target, double epsilon );
+ bool match(double const& matchee) const override;
+ std::string describe() const override;
+ private:
+ double m_target;
+ double m_epsilon;
+ };
+
+ //! Creates a matcher that accepts doubles within certain ULP range of target
+ WithinUlpsMatcher WithinULP(double target, uint64_t maxUlpDiff);
+ //! Creates a matcher that accepts floats within certain ULP range of target
+ WithinUlpsMatcher WithinULP(float target, uint64_t maxUlpDiff);
+ //! Creates a matcher that accepts numbers within certain range of target
+ WithinAbsMatcher WithinAbs(double target, double margin);
+
+ //! Creates a matcher that accepts doubles within certain relative range of target
+ WithinRelMatcher WithinRel(double target, double eps);
+ //! Creates a matcher that accepts doubles within 100*DBL_EPS relative range of target
+ WithinRelMatcher WithinRel(double target);
+ //! Creates a matcher that accepts doubles within certain relative range of target
+ WithinRelMatcher WithinRel(float target, float eps);
+ //! Creates a matcher that accepts floats within 100*FLT_EPS relative range of target
+ WithinRelMatcher WithinRel(float target);
+
+} // namespace Matchers
+} // namespace Catch
+
+#endif // CATCH_MATCHERS_FLOATING_POINT_HPP_INCLUDED
+
+
+#ifndef CATCH_MATCHERS_PREDICATE_HPP_INCLUDED
+#define CATCH_MATCHERS_PREDICATE_HPP_INCLUDED
+
+
+#include <string>
+
+namespace Catch {
+namespace Matchers {
+
+namespace Detail {
+ std::string finalizeDescription(const std::string& desc);
+} // namespace Detail
+
+template <typename T, typename Predicate>
+class PredicateMatcher final : public MatcherBase<T> {
+ Predicate m_predicate;
+ std::string m_description;
+public:
+
+ PredicateMatcher(Predicate&& elem, std::string const& descr)
+ :m_predicate(CATCH_FORWARD(elem)),
+ m_description(Detail::finalizeDescription(descr))
+ {}
+
+ bool match( T const& item ) const override {
+ return m_predicate(item);
+ }
+
+ std::string describe() const override {
+ return m_description;
+ }
+};
+
+ /**
+ * Creates a matcher that calls delegates `match` to the provided predicate.
+ *
+ * The user has to explicitly specify the argument type to the matcher
+ */
+ template<typename T, typename Pred>
+ PredicateMatcher<T, Pred> Predicate(Pred&& predicate, std::string const& description = "") {
+ static_assert(is_callable<Pred(T)>::value, "Predicate not callable with argument T");
+ static_assert(std::is_same<bool, FunctionReturnType<Pred, T>>::value, "Predicate does not return bool");
+ return PredicateMatcher<T, Pred>(CATCH_FORWARD(predicate), description);
+ }
+
+} // namespace Matchers
+} // namespace Catch
+
+#endif // CATCH_MATCHERS_PREDICATE_HPP_INCLUDED
+
+
+#ifndef CATCH_MATCHERS_QUANTIFIERS_HPP_INCLUDED
+#define CATCH_MATCHERS_QUANTIFIERS_HPP_INCLUDED
+
+
+namespace Catch {
+ namespace Matchers {
+ // Matcher for checking that all elements in range matches a given matcher.
+ template <typename Matcher>
+ class AllMatchMatcher final : public MatcherGenericBase {
+ Matcher m_matcher;
+ public:
+ AllMatchMatcher(Matcher matcher):
+ m_matcher(CATCH_MOVE(matcher))
+ {}
+
+ std::string describe() const override {
+ return "all match " + m_matcher.describe();
+ }
+
+ template <typename RangeLike>
+ bool match(RangeLike&& rng) const {
+ for (auto&& elem : rng) {
+ if (!m_matcher.match(elem)) {
+ return false;
+ }
+ }
+ return true;
+ }
+ };
+
+ // Matcher for checking that no element in range matches a given matcher.
+ template <typename Matcher>
+ class NoneMatchMatcher final : public MatcherGenericBase {
+ Matcher m_matcher;
+ public:
+ NoneMatchMatcher(Matcher matcher):
+ m_matcher(CATCH_MOVE(matcher))
+ {}
+
+ std::string describe() const override {
+ return "none match " + m_matcher.describe();
+ }
+
+ template <typename RangeLike>
+ bool match(RangeLike&& rng) const {
+ for (auto&& elem : rng) {
+ if (m_matcher.match(elem)) {
+ return false;
+ }
+ }
+ return true;
+ }
+ };
+
+ // Matcher for checking that at least one element in range matches a given matcher.
+ template <typename Matcher>
+ class AnyMatchMatcher final : public MatcherGenericBase {
+ Matcher m_matcher;
+ public:
+ AnyMatchMatcher(Matcher matcher):
+ m_matcher(CATCH_MOVE(matcher))
+ {}
+
+ std::string describe() const override {
+ return "any match " + m_matcher.describe();
+ }
+
+ template <typename RangeLike>
+ bool match(RangeLike&& rng) const {
+ for (auto&& elem : rng) {
+ if (m_matcher.match(elem)) {
+ return true;
+ }
+ }
+ return false;
+ }
+ };
+
+ // Matcher for checking that all elements in range are true.
+ class AllTrueMatcher final : public MatcherGenericBase {
+ public:
+ std::string describe() const override;
+
+ template <typename RangeLike>
+ bool match(RangeLike&& rng) const {
+ for (auto&& elem : rng) {
+ if (!elem) {
+ return false;
+ }
+ }
+ return true;
+ }
+ };
+
+ // Matcher for checking that no element in range is true.
+ class NoneTrueMatcher final : public MatcherGenericBase {
+ public:
+ std::string describe() const override;
+
+ template <typename RangeLike>
+ bool match(RangeLike&& rng) const {
+ for (auto&& elem : rng) {
+ if (elem) {
+ return false;
+ }
+ }
+ return true;
+ }
+ };
+
+ // Matcher for checking that any element in range is true.
+ class AnyTrueMatcher final : public MatcherGenericBase {
+ public:
+ std::string describe() const override;
+
+ template <typename RangeLike>
+ bool match(RangeLike&& rng) const {
+ for (auto&& elem : rng) {
+ if (elem) {
+ return true;
+ }
+ }
+ return false;
+ }
+ };
+
+ // Creates a matcher that checks whether all elements in a range match a matcher
+ template <typename Matcher>
+ AllMatchMatcher<Matcher> AllMatch(Matcher&& matcher) {
+ return { CATCH_FORWARD(matcher) };
+ }
+
+ // Creates a matcher that checks whether no element in a range matches a matcher.
+ template <typename Matcher>
+ NoneMatchMatcher<Matcher> NoneMatch(Matcher&& matcher) {
+ return { CATCH_FORWARD(matcher) };
+ }
+
+ // Creates a matcher that checks whether any element in a range matches a matcher.
+ template <typename Matcher>
+ AnyMatchMatcher<Matcher> AnyMatch(Matcher&& matcher) {
+ return { CATCH_FORWARD(matcher) };
+ }
+
+ // Creates a matcher that checks whether all elements in a range are true
+ AllTrueMatcher AllTrue();
+
+ // Creates a matcher that checks whether no element in a range is true
+ NoneTrueMatcher NoneTrue();
+
+ // Creates a matcher that checks whether any element in a range is true
+ AnyTrueMatcher AnyTrue();
+ }
+}
+
+#endif // CATCH_MATCHERS_QUANTIFIERS_HPP_INCLUDED
+
+
+#ifndef CATCH_MATCHERS_STRING_HPP_INCLUDED
+#define CATCH_MATCHERS_STRING_HPP_INCLUDED
+
+
+#include <string>
+
+namespace Catch {
+namespace Matchers {
+
+ struct CasedString {
+ CasedString( std::string const& str, CaseSensitive caseSensitivity );
+ std::string adjustString( std::string const& str ) const;
+ StringRef caseSensitivitySuffix() const;
+
+ CaseSensitive m_caseSensitivity;
+ std::string m_str;
+ };
+
+ class StringMatcherBase : public MatcherBase<std::string> {
+ protected:
+ CasedString m_comparator;
+ StringRef m_operation;
+
+ public:
+ StringMatcherBase( StringRef operation,
+ CasedString const& comparator );
+ std::string describe() const override;
+ };
+
+ class StringEqualsMatcher final : public StringMatcherBase {
+ public:
+ StringEqualsMatcher( CasedString const& comparator );
+ bool match( std::string const& source ) const override;
+ };
+ class StringContainsMatcher final : public StringMatcherBase {
+ public:
+ StringContainsMatcher( CasedString const& comparator );
+ bool match( std::string const& source ) const override;
+ };
+ class StartsWithMatcher final : public StringMatcherBase {
+ public:
+ StartsWithMatcher( CasedString const& comparator );
+ bool match( std::string const& source ) const override;
+ };
+ class EndsWithMatcher final : public StringMatcherBase {
+ public:
+ EndsWithMatcher( CasedString const& comparator );
+ bool match( std::string const& source ) const override;
+ };
+
+ class RegexMatcher final : public MatcherBase<std::string> {
+ std::string m_regex;
+ CaseSensitive m_caseSensitivity;
+
+ public:
+ RegexMatcher( std::string regex, CaseSensitive caseSensitivity );
+ bool match( std::string const& matchee ) const override;
+ std::string describe() const override;
+ };
+
+ //! Creates matcher that accepts strings that are exactly equal to `str`
+ StringEqualsMatcher Equals( std::string const& str, CaseSensitive caseSensitivity = CaseSensitive::Yes );
+ //! Creates matcher that accepts strings that contain `str`
+ StringContainsMatcher ContainsSubstring( std::string const& str, CaseSensitive caseSensitivity = CaseSensitive::Yes );
+ //! Creates matcher that accepts strings that _end_ with `str`
+ EndsWithMatcher EndsWith( std::string const& str, CaseSensitive caseSensitivity = CaseSensitive::Yes );
+ //! Creates matcher that accepts strings that _start_ with `str`
+ StartsWithMatcher StartsWith( std::string const& str, CaseSensitive caseSensitivity = CaseSensitive::Yes );
+ //! Creates matcher that accepts strings matching `regex`
+ RegexMatcher Matches( std::string const& regex, CaseSensitive caseSensitivity = CaseSensitive::Yes );
+
+} // namespace Matchers
+} // namespace Catch
+
+#endif // CATCH_MATCHERS_STRING_HPP_INCLUDED
+
+
+#ifndef CATCH_MATCHERS_VECTOR_HPP_INCLUDED
+#define CATCH_MATCHERS_VECTOR_HPP_INCLUDED
+
+
+#include <algorithm>
+
+namespace Catch {
+namespace Matchers {
+
+ template<typename T, typename Alloc>
+ class VectorContainsElementMatcher final : public MatcherBase<std::vector<T, Alloc>> {
+ T const& m_comparator;
+
+ public:
+ VectorContainsElementMatcher(T const& comparator):
+ m_comparator(comparator)
+ {}
+
+ bool match(std::vector<T, Alloc> const& v) const override {
+ for (auto const& el : v) {
+ if (el == m_comparator) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ std::string describe() const override {
+ return "Contains: " + ::Catch::Detail::stringify( m_comparator );
+ }
+ };
+
+ template<typename T, typename AllocComp, typename AllocMatch>
+ class ContainsMatcher final : public MatcherBase<std::vector<T, AllocMatch>> {
+ std::vector<T, AllocComp> const& m_comparator;
+
+ public:
+ ContainsMatcher(std::vector<T, AllocComp> const& comparator):
+ m_comparator( comparator )
+ {}
+
+ bool match(std::vector<T, AllocMatch> const& v) const override {
+ // !TBD: see note in EqualsMatcher
+ if (m_comparator.size() > v.size())
+ return false;
+ for (auto const& comparator : m_comparator) {
+ auto present = false;
+ for (const auto& el : v) {
+ if (el == comparator) {
+ present = true;
+ break;
+ }
+ }
+ if (!present) {
+ return false;
+ }
+ }
+ return true;
+ }
+ std::string describe() const override {
+ return "Contains: " + ::Catch::Detail::stringify( m_comparator );
+ }
+ };
+
+ template<typename T, typename AllocComp, typename AllocMatch>
+ class EqualsMatcher final : public MatcherBase<std::vector<T, AllocMatch>> {
+ std::vector<T, AllocComp> const& m_comparator;
+
+ public:
+ EqualsMatcher(std::vector<T, AllocComp> const& comparator):
+ m_comparator( comparator )
+ {}
+
+ bool match(std::vector<T, AllocMatch> const& v) const override {
+ // !TBD: This currently works if all elements can be compared using !=
+ // - a more general approach would be via a compare template that defaults
+ // to using !=. but could be specialised for, e.g. std::vector<T> etc
+ // - then just call that directly
+ if (m_comparator.size() != v.size())
+ return false;
+ for (std::size_t i = 0; i < v.size(); ++i)
+ if (m_comparator[i] != v[i])
+ return false;
+ return true;
+ }
+ std::string describe() const override {
+ return "Equals: " + ::Catch::Detail::stringify( m_comparator );
+ }
+ };
+
+ template<typename T, typename AllocComp, typename AllocMatch>
+ class ApproxMatcher final : public MatcherBase<std::vector<T, AllocMatch>> {
+ std::vector<T, AllocComp> const& m_comparator;
+ mutable Catch::Approx approx = Catch::Approx::custom();
+
+ public:
+ ApproxMatcher(std::vector<T, AllocComp> const& comparator):
+ m_comparator( comparator )
+ {}
+
+ bool match(std::vector<T, AllocMatch> const& v) const override {
+ if (m_comparator.size() != v.size())
+ return false;
+ for (std::size_t i = 0; i < v.size(); ++i)
+ if (m_comparator[i] != approx(v[i]))
+ return false;
+ return true;
+ }
+ std::string describe() const override {
+ return "is approx: " + ::Catch::Detail::stringify( m_comparator );
+ }
+ template <typename = std::enable_if_t<std::is_constructible<double, T>::value>>
+ ApproxMatcher& epsilon( T const& newEpsilon ) {
+ approx.epsilon(static_cast<double>(newEpsilon));
+ return *this;
+ }
+ template <typename = std::enable_if_t<std::is_constructible<double, T>::value>>
+ ApproxMatcher& margin( T const& newMargin ) {
+ approx.margin(static_cast<double>(newMargin));
+ return *this;
+ }
+ template <typename = std::enable_if_t<std::is_constructible<double, T>::value>>
+ ApproxMatcher& scale( T const& newScale ) {
+ approx.scale(static_cast<double>(newScale));
+ return *this;
+ }
+ };
+
+ template<typename T, typename AllocComp, typename AllocMatch>
+ class UnorderedEqualsMatcher final : public MatcherBase<std::vector<T, AllocMatch>> {
+ std::vector<T, AllocComp> const& m_target;
+
+ public:
+ UnorderedEqualsMatcher(std::vector<T, AllocComp> const& target):
+ m_target(target)
+ {}
+ bool match(std::vector<T, AllocMatch> const& vec) const override {
+ if (m_target.size() != vec.size()) {
+ return false;
+ }
+ return std::is_permutation(m_target.begin(), m_target.end(), vec.begin());
+ }
+
+ std::string describe() const override {
+ return "UnorderedEquals: " + ::Catch::Detail::stringify(m_target);
+ }
+ };
+
+
+ // The following functions create the actual matcher objects.
+ // This allows the types to be inferred
+
+ //! Creates a matcher that matches vectors that contain all elements in `comparator`
+ template<typename T, typename AllocComp = std::allocator<T>, typename AllocMatch = AllocComp>
+ ContainsMatcher<T, AllocComp, AllocMatch> Contains( std::vector<T, AllocComp> const& comparator ) {
+ return ContainsMatcher<T, AllocComp, AllocMatch>(comparator);
+ }
+
+ //! Creates a matcher that matches vectors that contain `comparator` as an element
+ template<typename T, typename Alloc = std::allocator<T>>
+ VectorContainsElementMatcher<T, Alloc> VectorContains( T const& comparator ) {
+ return VectorContainsElementMatcher<T, Alloc>(comparator);
+ }
+
+ //! Creates a matcher that matches vectors that are exactly equal to `comparator`
+ template<typename T, typename AllocComp = std::allocator<T>, typename AllocMatch = AllocComp>
+ EqualsMatcher<T, AllocComp, AllocMatch> Equals( std::vector<T, AllocComp> const& comparator ) {
+ return EqualsMatcher<T, AllocComp, AllocMatch>(comparator);
+ }
+
+ //! Creates a matcher that matches vectors that `comparator` as an element
+ template<typename T, typename AllocComp = std::allocator<T>, typename AllocMatch = AllocComp>
+ ApproxMatcher<T, AllocComp, AllocMatch> Approx( std::vector<T, AllocComp> const& comparator ) {
+ return ApproxMatcher<T, AllocComp, AllocMatch>(comparator);
+ }
+
+ //! Creates a matcher that matches vectors that is equal to `target` modulo permutation
+ template<typename T, typename AllocComp = std::allocator<T>, typename AllocMatch = AllocComp>
+ UnorderedEqualsMatcher<T, AllocComp, AllocMatch> UnorderedEquals(std::vector<T, AllocComp> const& target) {
+ return UnorderedEqualsMatcher<T, AllocComp, AllocMatch>(target);
+ }
+
+} // namespace Matchers
+} // namespace Catch
+
+#endif // CATCH_MATCHERS_VECTOR_HPP_INCLUDED
+
+#endif // CATCH_MATCHERS_ALL_HPP_INCLUDED
+
+
+/** \file
+ * This is a convenience header for Catch2's Reporter support. It includes
+ * **all** of Catch2 headers related to reporters, including all reporters.
+ *
+ * Generally the Catch2 users should use specific includes they need,
+ * but this header can be used instead for ease-of-experimentation, or
+ * just plain convenience, at the cost of (significantly) increased
+ * compilation times.
+ *
+ * When a new header (reporter) is added to either the `reporter` folder,
+ * or to the corresponding internal subfolder, it should be added here.
+ */
+
+#ifndef CATCH_REPORTERS_ALL_HPP_INCLUDED
+#define CATCH_REPORTERS_ALL_HPP_INCLUDED
+
+
+
+#ifndef CATCH_REPORTER_AUTOMAKE_HPP_INCLUDED
+#define CATCH_REPORTER_AUTOMAKE_HPP_INCLUDED
+
+
+
+#ifndef CATCH_REPORTER_STREAMING_BASE_HPP_INCLUDED
+#define CATCH_REPORTER_STREAMING_BASE_HPP_INCLUDED
+
+
+
+#ifndef CATCH_REPORTER_COMMON_BASE_HPP_INCLUDED
+#define CATCH_REPORTER_COMMON_BASE_HPP_INCLUDED
+
+
+#include <map>
+#include <string>
+
+namespace Catch {
+ class ColourImpl;
+
+ /**
+ * This is the base class for all reporters.
+ *
+ * If are writing a reporter, you must derive from this type, or one
+ * of the helper reporter bases that are derived from this type.
+ *
+ * ReporterBase centralizes handling of various common tasks in reporters,
+ * like storing the right stream for the reporters to write to, and
+ * providing the default implementation of the different listing events.
+ */
+ class ReporterBase : public IEventListener {
+ protected:
+ //! The stream wrapper as passed to us by outside code
+ Detail::unique_ptr<IStream> m_wrapped_stream;
+ //! Cached output stream from `m_wrapped_stream` to reduce
+ //! number of indirect calls needed to write output.
+ std::ostream& m_stream;
+ //! Colour implementation this reporter was configured for
+ Detail::unique_ptr<ColourImpl> m_colour;
+ //! The custom reporter options user passed down to the reporter
+ std::map<std::string, std::string> m_customOptions;
+
+ public:
+ ReporterBase( ReporterConfig&& config );
+ ~ReporterBase() override; // = default;
+
+ /**
+ * Provides a simple default listing of reporters.
+ *
+ * Should look roughly like the reporter listing in v2 and earlier
+ * versions of Catch2.
+ */
+ void listReporters(
+ std::vector<ReporterDescription> const& descriptions ) override;
+ /**
+ * Provides a simple default listing of listeners
+ *
+ * Looks similarly to listing of reporters, but with listener type
+ * instead of reporter name.
+ */
+ void listListeners(
+ std::vector<ListenerDescription> const& descriptions ) override;
+ /**
+ * Provides a simple default listing of tests.
+ *
+ * Should look roughly like the test listing in v2 and earlier versions
+ * of Catch2. Especially supports low-verbosity listing that mimics the
+ * old `--list-test-names-only` output.
+ */
+ void listTests( std::vector<TestCaseHandle> const& tests ) override;
+ /**
+ * Provides a simple default listing of tags.
+ *
+ * Should look roughly like the tag listing in v2 and earlier versions
+ * of Catch2.
+ */
+ void listTags( std::vector<TagInfo> const& tags ) override;
+ };
+} // namespace Catch
+
+#endif // CATCH_REPORTER_COMMON_BASE_HPP_INCLUDED
+
+#include <vector>
+
+namespace Catch {
+
+ class StreamingReporterBase : public ReporterBase {
+ public:
+ // GCC5 compat: we cannot use inherited constructor, because it
+ // doesn't implement backport of P0136
+ StreamingReporterBase(ReporterConfig&& _config):
+ ReporterBase(CATCH_MOVE(_config))
+ {}
+ ~StreamingReporterBase() override;
+
+ void benchmarkPreparing( StringRef ) override {}
+ void benchmarkStarting( BenchmarkInfo const& ) override {}
+ void benchmarkEnded( BenchmarkStats<> const& ) override {}
+ void benchmarkFailed( StringRef ) override {}
+
+ void fatalErrorEncountered( StringRef /*error*/ ) override {}
+ void noMatchingTestCases( StringRef /*unmatchedSpec*/ ) override {}
+ void reportInvalidTestSpec( StringRef /*invalidArgument*/ ) override {}
+
+ void testRunStarting( TestRunInfo const& _testRunInfo ) override;
+
+ void testCaseStarting(TestCaseInfo const& _testInfo) override {
+ currentTestCaseInfo = &_testInfo;
+ }
+ void testCasePartialStarting( TestCaseInfo const&, uint64_t ) override {}
+ void sectionStarting(SectionInfo const& _sectionInfo) override {
+ m_sectionStack.push_back(_sectionInfo);
+ }
+
+ void assertionStarting( AssertionInfo const& ) override {}
+ void assertionEnded( AssertionStats const& ) override {}
+
+ void sectionEnded(SectionStats const& /* _sectionStats */) override {
+ m_sectionStack.pop_back();
+ }
+ void testCasePartialEnded( TestCaseStats const&, uint64_t ) override {}
+ void testCaseEnded(TestCaseStats const& /* _testCaseStats */) override {
+ currentTestCaseInfo = nullptr;
+ }
+ void testRunEnded( TestRunStats const& /* _testRunStats */ ) override;
+
+ void skipTest(TestCaseInfo const&) override {
+ // Don't do anything with this by default.
+ // It can optionally be overridden in the derived class.
+ }
+
+ protected:
+ TestRunInfo currentTestRunInfo{ "test run has not started yet"_sr };
+ TestCaseInfo const* currentTestCaseInfo = nullptr;
+
+ //! Stack of all _active_ sections in the _current_ test case
+ std::vector<SectionInfo> m_sectionStack;
+ };
+
+} // end namespace Catch
+
+#endif // CATCH_REPORTER_STREAMING_BASE_HPP_INCLUDED
+
+#include <string>
+
+namespace Catch {
+
+ class AutomakeReporter final : public StreamingReporterBase {
+ public:
+ // GCC5 compat: we cannot use inherited constructor, because it
+ // doesn't implement backport of P0136
+ AutomakeReporter(ReporterConfig&& _config):
+ StreamingReporterBase(CATCH_MOVE(_config))
+ {}
+ ~AutomakeReporter() override;
+
+ static std::string getDescription() {
+ using namespace std::string_literals;
+ return "Reports test results in the format of Automake .trs files"s;
+ }
+
+ void testCaseEnded(TestCaseStats const& _testCaseStats) override;
+ void skipTest(TestCaseInfo const& testInfo) override;
+ };
+
+} // end namespace Catch
+
+#endif // CATCH_REPORTER_AUTOMAKE_HPP_INCLUDED
+
+
+#ifndef CATCH_REPORTER_COMPACT_HPP_INCLUDED
+#define CATCH_REPORTER_COMPACT_HPP_INCLUDED
+
+
+
+
+namespace Catch {
+
+ class CompactReporter final : public StreamingReporterBase {
+ public:
+ using StreamingReporterBase::StreamingReporterBase;
+
+ ~CompactReporter() override;
+
+ static std::string getDescription();
+
+ void noMatchingTestCases( StringRef unmatchedSpec ) override;
+
+ void testRunStarting( TestRunInfo const& _testInfo ) override;
+
+ void assertionEnded(AssertionStats const& _assertionStats) override;
+
+ void sectionEnded(SectionStats const& _sectionStats) override;
+
+ void testRunEnded(TestRunStats const& _testRunStats) override;
+
+ };
+
+} // end namespace Catch
+
+#endif // CATCH_REPORTER_COMPACT_HPP_INCLUDED
+
+
+#ifndef CATCH_REPORTER_CONSOLE_HPP_INCLUDED
+#define CATCH_REPORTER_CONSOLE_HPP_INCLUDED
+
+
+namespace Catch {
+ // Fwd decls
+ struct SummaryColumn;
+ class TablePrinter;
+
+ class ConsoleReporter final : public StreamingReporterBase {
+ Detail::unique_ptr<TablePrinter> m_tablePrinter;
+
+ public:
+ ConsoleReporter(ReporterConfig&& config);
+ ~ConsoleReporter() override;
+ static std::string getDescription();
+
+ void noMatchingTestCases( StringRef unmatchedSpec ) override;
+ void reportInvalidTestSpec( StringRef arg ) override;
+
+ void assertionStarting(AssertionInfo const&) override;
+
+ void assertionEnded(AssertionStats const& _assertionStats) override;
+
+ void sectionStarting(SectionInfo const& _sectionInfo) override;
+ void sectionEnded(SectionStats const& _sectionStats) override;
+
+ void benchmarkPreparing( StringRef name ) override;
+ void benchmarkStarting(BenchmarkInfo const& info) override;
+ void benchmarkEnded(BenchmarkStats<> const& stats) override;
+ void benchmarkFailed( StringRef error ) override;
+
+ void testCaseEnded(TestCaseStats const& _testCaseStats) override;
+ void testRunEnded(TestRunStats const& _testRunStats) override;
+ void testRunStarting(TestRunInfo const& _testRunInfo) override;
+
+ private:
+ void lazyPrint();
+
+ void lazyPrintWithoutClosingBenchmarkTable();
+ void lazyPrintRunInfo();
+ void printTestCaseAndSectionHeader();
+
+ void printClosedHeader(std::string const& _name);
+ void printOpenHeader(std::string const& _name);
+
+ // if string has a : in first line will set indent to follow it on
+ // subsequent lines
+ void printHeaderString(std::string const& _string, std::size_t indent = 0);
+
+
+ void printTotals(Totals const& totals);
+ void printSummaryRow(StringRef label, std::vector<SummaryColumn> const& cols, std::size_t row);
+
+ void printTotalsDivider(Totals const& totals);
+ void printSummaryDivider();
+
+ bool m_headerPrinted = false;
+ bool m_testRunInfoPrinted = false;
+ };
+
+} // end namespace Catch
+
+#endif // CATCH_REPORTER_CONSOLE_HPP_INCLUDED
+
+
+#ifndef CATCH_REPORTER_CUMULATIVE_BASE_HPP_INCLUDED
+#define CATCH_REPORTER_CUMULATIVE_BASE_HPP_INCLUDED
+
+
+#include <string>
+#include <vector>
+
+namespace Catch {
+
+ namespace Detail {
+
+ //! Represents either an assertion or a benchmark result to be handled by cumulative reporter later
+ class AssertionOrBenchmarkResult {
+ // This should really be a variant, but this is much faster
+ // to write and the data layout here is already terrible
+ // enough that we do not have to care about the object size.
+ Optional<AssertionStats> m_assertion;
+ Optional<BenchmarkStats<>> m_benchmark;
+ public:
+ AssertionOrBenchmarkResult(AssertionStats const& assertion);
+ AssertionOrBenchmarkResult(BenchmarkStats<> const& benchmark);
+
+ bool isAssertion() const;
+ bool isBenchmark() const;
+
+ AssertionStats const& asAssertion() const;
+ BenchmarkStats<> const& asBenchmark() const;
+ };
+ }
+
+ /**
+ * Utility base for reporters that need to handle all results at once
+ *
+ * It stores tree of all test cases, sections and assertions, and after the
+ * test run is finished, calls into `testRunEndedCumulative` to pass the
+ * control to the deriving class.
+ *
+ * If you are deriving from this class and override any testing related
+ * member functions, you should first call into the base's implementation to
+ * avoid breaking the tree construction.
+ *
+ * Due to the way this base functions, it has to expand assertions up-front,
+ * even if they are later unused (e.g. because the deriving reporter does
+ * not report successful assertions, or because the deriving reporter does
+ * not use assertion expansion at all). Derived classes can use two
+ * customization points, `m_shouldStoreSuccesfulAssertions` and
+ * `m_shouldStoreFailedAssertions`, to disable the expansion and gain extra
+ * performance. **Accessing the assertion expansions if it wasn't stored is
+ * UB.**
+ */
+ class CumulativeReporterBase : public ReporterBase {
+ public:
+ template<typename T, typename ChildNodeT>
+ struct Node {
+ explicit Node( T const& _value ) : value( _value ) {}
+
+ using ChildNodes = std::vector<Detail::unique_ptr<ChildNodeT>>;
+ T value;
+ ChildNodes children;
+ };
+ struct SectionNode {
+ explicit SectionNode(SectionStats const& _stats) : stats(_stats) {}
+
+ bool operator == (SectionNode const& other) const {
+ return stats.sectionInfo.lineInfo == other.stats.sectionInfo.lineInfo;
+ }
+
+ bool hasAnyAssertions() const;
+
+ SectionStats stats;
+ std::vector<Detail::unique_ptr<SectionNode>> childSections;
+ std::vector<Detail::AssertionOrBenchmarkResult> assertionsAndBenchmarks;
+ std::string stdOut;
+ std::string stdErr;
+ };
+
+
+ using TestCaseNode = Node<TestCaseStats, SectionNode>;
+ using TestRunNode = Node<TestRunStats, TestCaseNode>;
+
+ // GCC5 compat: we cannot use inherited constructor, because it
+ // doesn't implement backport of P0136
+ CumulativeReporterBase(ReporterConfig&& _config):
+ ReporterBase(CATCH_MOVE(_config))
+ {}
+ ~CumulativeReporterBase() override;
+
+ void benchmarkPreparing( StringRef ) override {}
+ void benchmarkStarting( BenchmarkInfo const& ) override {}
+ void benchmarkEnded( BenchmarkStats<> const& benchmarkStats ) override;
+ void benchmarkFailed( StringRef ) override {}
+
+ void noMatchingTestCases( StringRef ) override {}
+ void reportInvalidTestSpec( StringRef ) override {}
+ void fatalErrorEncountered( StringRef /*error*/ ) override {}
+
+ void testRunStarting( TestRunInfo const& ) override {}
+
+ void testCaseStarting( TestCaseInfo const& ) override {}
+ void testCasePartialStarting( TestCaseInfo const&, uint64_t ) override {}
+ void sectionStarting( SectionInfo const& sectionInfo ) override;
+
+ void assertionStarting( AssertionInfo const& ) override {}
+
+ void assertionEnded( AssertionStats const& assertionStats ) override;
+ void sectionEnded( SectionStats const& sectionStats ) override;
+ void testCasePartialEnded( TestCaseStats const&, uint64_t ) override {}
+ void testCaseEnded( TestCaseStats const& testCaseStats ) override;
+ void testRunEnded( TestRunStats const& testRunStats ) override;
+ //! Customization point: called after last test finishes (testRunEnded has been handled)
+ virtual void testRunEndedCumulative() = 0;
+
+ void skipTest(TestCaseInfo const&) override {}
+
+ protected:
+ //! Should the cumulative base store the assertion expansion for succesful assertions?
+ bool m_shouldStoreSuccesfulAssertions = true;
+ //! Should the cumulative base store the assertion expansion for failed assertions?
+ bool m_shouldStoreFailedAssertions = true;
+
+ // We need lazy construction here. We should probably refactor it
+ // later, after the events are redone.
+ //! The root node of the test run tree.
+ Detail::unique_ptr<TestRunNode> m_testRun;
+
+ private:
+ // Note: We rely on pointer identity being stable, which is why
+ // we store pointers to the nodes rather than the values.
+ std::vector<Detail::unique_ptr<TestCaseNode>> m_testCases;
+ // Root section of the _current_ test case
+ Detail::unique_ptr<SectionNode> m_rootSection;
+ // Deepest section of the _current_ test case
+ SectionNode* m_deepestSection = nullptr;
+ // Stack of _active_ sections in the _current_ test case
+ std::vector<SectionNode*> m_sectionStack;
+ };
+
+} // end namespace Catch
+
+#endif // CATCH_REPORTER_CUMULATIVE_BASE_HPP_INCLUDED
+
+
+#ifndef CATCH_REPORTER_EVENT_LISTENER_HPP_INCLUDED
+#define CATCH_REPORTER_EVENT_LISTENER_HPP_INCLUDED
+
+
+namespace Catch {
+
+ /**
+ * Base class to simplify implementing listeners.
+ *
+ * Provides empty default implementation for all IEventListener member
+ * functions, so that a listener implementation can pick which
+ * member functions it actually cares about.
+ */
+ class EventListenerBase : public IEventListener {
+ public:
+ using IEventListener::IEventListener;
+
+ void reportInvalidTestSpec( StringRef unmatchedSpec ) override;
+ void fatalErrorEncountered( StringRef error ) override;
+
+ void benchmarkPreparing( StringRef name ) override;
+ void benchmarkStarting( BenchmarkInfo const& benchmarkInfo ) override;
+ void benchmarkEnded( BenchmarkStats<> const& benchmarkStats ) override;
+ void benchmarkFailed( StringRef error ) override;
+
+ void assertionStarting( AssertionInfo const& assertionInfo ) override;
+ void assertionEnded( AssertionStats const& assertionStats ) override;
+
+ void listReporters(
+ std::vector<ReporterDescription> const& descriptions ) override;
+ void listListeners(
+ std::vector<ListenerDescription> const& descriptions ) override;
+ void listTests( std::vector<TestCaseHandle> const& tests ) override;
+ void listTags( std::vector<TagInfo> const& tagInfos ) override;
+
+ void noMatchingTestCases( StringRef unmatchedSpec ) override;
+ void testRunStarting( TestRunInfo const& testRunInfo ) override;
+ void testCaseStarting( TestCaseInfo const& testInfo ) override;
+ void testCasePartialStarting( TestCaseInfo const& testInfo,
+ uint64_t partNumber ) override;
+ void sectionStarting( SectionInfo const& sectionInfo ) override;
+ void sectionEnded( SectionStats const& sectionStats ) override;
+ void testCasePartialEnded( TestCaseStats const& testCaseStats,
+ uint64_t partNumber ) override;
+ void testCaseEnded( TestCaseStats const& testCaseStats ) override;
+ void testRunEnded( TestRunStats const& testRunStats ) override;
+ void skipTest( TestCaseInfo const& testInfo ) override;
+ };
+
+} // end namespace Catch
+
+#endif // CATCH_REPORTER_EVENT_LISTENER_HPP_INCLUDED
+
+
+#ifndef CATCH_REPORTER_HELPERS_HPP_INCLUDED
+#define CATCH_REPORTER_HELPERS_HPP_INCLUDED
+
+#include <iosfwd>
+#include <string>
+#include <vector>
+
+
+namespace Catch {
+
+ class IConfig;
+ class TestCaseHandle;
+ class ColourImpl;
+
+ // Returns double formatted as %.3f (format expected on output)
+ std::string getFormattedDuration( double duration );
+
+ //! Should the reporter show duration of test given current configuration?
+ bool shouldShowDuration( IConfig const& config, double duration );
+
+ std::string serializeFilters( std::vector<std::string> const& filters );
+
+ struct lineOfChars {
+ char c;
+ constexpr lineOfChars( char c_ ): c( c_ ) {}
+
+ friend std::ostream& operator<<( std::ostream& out, lineOfChars value );
+ };
+
+ /**
+ * Lists reporter descriptions to the provided stream in user-friendly
+ * format
+ *
+ * Used as the default listing implementation by the first party reporter
+ * bases. The output should be backwards compatible with the output of
+ * Catch2 v2 binaries.
+ */
+ void
+ defaultListReporters( std::ostream& out,
+ std::vector<ReporterDescription> const& descriptions,
+ Verbosity verbosity );
+
+ /**
+ * Lists listeners descriptions to the provided stream in user-friendly
+ * format
+ */
+ void defaultListListeners( std::ostream& out,
+ std::vector<ListenerDescription> const& descriptions );
+
+ /**
+ * Lists tag information to the provided stream in user-friendly format
+ *
+ * Used as the default listing implementation by the first party reporter
+ * bases. The output should be backwards compatible with the output of
+ * Catch2 v2 binaries.
+ */
+ void defaultListTags( std::ostream& out, std::vector<TagInfo> const& tags, bool isFiltered );
+
+ /**
+ * Lists test case information to the provided stream in user-friendly
+ * format
+ *
+ * Used as the default listing implementation by the first party reporter
+ * bases. The output is backwards compatible with the output of Catch2
+ * v2 binaries, and also supports the format specific to the old
+ * `--list-test-names-only` option, for people who used it in integrations.
+ */
+ void defaultListTests( std::ostream& out,
+ ColourImpl* streamColour,
+ std::vector<TestCaseHandle> const& tests,
+ bool isFiltered,
+ Verbosity verbosity );
+
+} // end namespace Catch
+
+#endif // CATCH_REPORTER_HELPERS_HPP_INCLUDED
+
+
+#ifndef CATCH_REPORTER_JUNIT_HPP_INCLUDED
+#define CATCH_REPORTER_JUNIT_HPP_INCLUDED
+
+
+
+namespace Catch {
+
+ class JunitReporter final : public CumulativeReporterBase {
+ public:
+ JunitReporter(ReporterConfig&& _config);
+
+ ~JunitReporter() override = default;
+
+ static std::string getDescription();
+
+ void testRunStarting(TestRunInfo const& runInfo) override;
+
+ void testCaseStarting(TestCaseInfo const& testCaseInfo) override;
+ void assertionEnded(AssertionStats const& assertionStats) override;
+
+ void testCaseEnded(TestCaseStats const& testCaseStats) override;
+
+ void testRunEndedCumulative() override;
+
+ private:
+ void writeRun(TestRunNode const& testRunNode, double suiteTime);
+
+ void writeTestCase(TestCaseNode const& testCaseNode);
+
+ void writeSection( std::string const& className,
+ std::string const& rootName,
+ SectionNode const& sectionNode,
+ bool testOkToFail );
+
+ void writeAssertions(SectionNode const& sectionNode);
+ void writeAssertion(AssertionStats const& stats);
+
+ XmlWriter xml;
+ Timer suiteTimer;
+ std::string stdOutForSuite;
+ std::string stdErrForSuite;
+ unsigned int unexpectedExceptions = 0;
+ bool m_okToFail = false;
+ };
+
+} // end namespace Catch
+
+#endif // CATCH_REPORTER_JUNIT_HPP_INCLUDED
+
+
+#ifndef CATCH_REPORTER_MULTI_HPP_INCLUDED
+#define CATCH_REPORTER_MULTI_HPP_INCLUDED
+
+
+namespace Catch {
+
+ class MultiReporter final : public IEventListener {
+ /*
+ * Stores all added reporters and listeners
+ *
+ * All Listeners are stored before all reporters, and individual
+ * listeners/reporters are stored in order of insertion.
+ */
+ std::vector<IEventListenerPtr> m_reporterLikes;
+ bool m_haveNoncapturingReporters = false;
+
+ // Keep track of how many listeners we have already inserted,
+ // so that we can insert them into the main vector at the right place
+ size_t m_insertedListeners = 0;
+
+ void updatePreferences(IEventListener const& reporterish);
+
+ public:
+ using IEventListener::IEventListener;
+
+ void addListener( IEventListenerPtr&& listener );
+ void addReporter( IEventListenerPtr&& reporter );
+
+ public: // IEventListener
+
+ void noMatchingTestCases( StringRef unmatchedSpec ) override;
+ void fatalErrorEncountered( StringRef error ) override;
+ void reportInvalidTestSpec( StringRef arg ) override;
+
+ void benchmarkPreparing( StringRef name ) override;
+ void benchmarkStarting( BenchmarkInfo const& benchmarkInfo ) override;
+ void benchmarkEnded( BenchmarkStats<> const& benchmarkStats ) override;
+ void benchmarkFailed( StringRef error ) override;
+
+ void testRunStarting( TestRunInfo const& testRunInfo ) override;
+ void testCaseStarting( TestCaseInfo const& testInfo ) override;
+ void testCasePartialStarting(TestCaseInfo const& testInfo, uint64_t partNumber) override;
+ void sectionStarting( SectionInfo const& sectionInfo ) override;
+ void assertionStarting( AssertionInfo const& assertionInfo ) override;
+
+ void assertionEnded( AssertionStats const& assertionStats ) override;
+ void sectionEnded( SectionStats const& sectionStats ) override;
+ void testCasePartialEnded(TestCaseStats const& testInfo, uint64_t partNumber) override;
+ void testCaseEnded( TestCaseStats const& testCaseStats ) override;
+ void testRunEnded( TestRunStats const& testRunStats ) override;
+
+ void skipTest( TestCaseInfo const& testInfo ) override;
+
+ void listReporters(std::vector<ReporterDescription> const& descriptions) override;
+ void listListeners(std::vector<ListenerDescription> const& descriptions) override;
+ void listTests(std::vector<TestCaseHandle> const& tests) override;
+ void listTags(std::vector<TagInfo> const& tags) override;
+
+
+ };
+
+} // end namespace Catch
+
+#endif // CATCH_REPORTER_MULTI_HPP_INCLUDED
+
+
+#ifndef CATCH_REPORTER_REGISTRARS_HPP_INCLUDED
+#define CATCH_REPORTER_REGISTRARS_HPP_INCLUDED
+
+
+#include <type_traits>
+
+namespace Catch {
+
+ namespace Detail {
+
+ template <typename T, typename = void>
+ struct has_description : std::false_type {};
+
+ template <typename T>
+ struct has_description<
+ T,
+ void_t<decltype( T::getDescription() )>>
+ : std::true_type {};
+
+ //! Indirection for reporter registration, so that the error handling is
+ //! independent on the reporter's concrete type
+ void registerReporterImpl( std::string const& name,
+ IReporterFactoryPtr reporterPtr );
+
+ } // namespace Detail
+
+ class IEventListener;
+ using IEventListenerPtr = Detail::unique_ptr<IEventListener>;
+
+ template <typename T>
+ class ReporterFactory : public IReporterFactory {
+
+ IEventListenerPtr create( ReporterConfig&& config ) const override {
+ return Detail::make_unique<T>( CATCH_MOVE(config) );
+ }
+
+ std::string getDescription() const override {
+ return T::getDescription();
+ }
+ };
+
+
+ template<typename T>
+ class ReporterRegistrar {
+ public:
+ explicit ReporterRegistrar( std::string const& name ) {
+ registerReporterImpl( name,
+ Detail::make_unique<ReporterFactory<T>>() );
+ }
+ };
+
+ template<typename T>
+ class ListenerRegistrar {
+
+ class TypedListenerFactory : public EventListenerFactory {
+ StringRef m_listenerName;
+
+ std::string getDescriptionImpl( std::true_type ) const {
+ return T::getDescription();
+ }
+
+ std::string getDescriptionImpl( std::false_type ) const {
+ return "(No description provided)";
+ }
+
+ public:
+ TypedListenerFactory( StringRef listenerName ):
+ m_listenerName( listenerName ) {}
+
+ IEventListenerPtr create( IConfig const* config ) const override {
+ return Detail::make_unique<T>( config );
+ }
+
+ StringRef getName() const override {
+ return m_listenerName;
+ }
+
+ std::string getDescription() const override {
+ return getDescriptionImpl( Detail::has_description<T>{} );
+ }
+ };
+
+ public:
+ ListenerRegistrar(StringRef listenerName) {
+ getMutableRegistryHub().registerListener( Detail::make_unique<TypedListenerFactory>(listenerName) );
+ }
+ };
+}
+
+#if !defined(CATCH_CONFIG_DISABLE)
+
+# define CATCH_REGISTER_REPORTER( name, reporterType ) \
+ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
+ CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
+ namespace { \
+ Catch::ReporterRegistrar<reporterType> INTERNAL_CATCH_UNIQUE_NAME( \
+ catch_internal_RegistrarFor )( name ); \
+ } \
+ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
+
+# define CATCH_REGISTER_LISTENER( listenerType ) \
+ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
+ CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
+ namespace { \
+ Catch::ListenerRegistrar<listenerType> INTERNAL_CATCH_UNIQUE_NAME( \
+ catch_internal_RegistrarFor )( #listenerType ); \
+ } \
+ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
+
+#else // CATCH_CONFIG_DISABLE
+
+#define CATCH_REGISTER_REPORTER(name, reporterType)
+#define CATCH_REGISTER_LISTENER(listenerType)
+
+#endif // CATCH_CONFIG_DISABLE
+
+#endif // CATCH_REPORTER_REGISTRARS_HPP_INCLUDED
+
+
+#ifndef CATCH_REPORTER_SONARQUBE_HPP_INCLUDED
+#define CATCH_REPORTER_SONARQUBE_HPP_INCLUDED
+
+
+
+namespace Catch {
+
+ class SonarQubeReporter final : public CumulativeReporterBase {
+ public:
+ SonarQubeReporter(ReporterConfig&& config)
+ : CumulativeReporterBase(CATCH_MOVE(config))
+ , xml(m_stream) {
+ m_preferences.shouldRedirectStdOut = true;
+ m_preferences.shouldReportAllAssertions = true;
+ m_shouldStoreSuccesfulAssertions = false;
+ }
+
+ ~SonarQubeReporter() override = default;
+
+ static std::string getDescription() {
+ using namespace std::string_literals;
+ return "Reports test results in the Generic Test Data SonarQube XML format"s;
+ }
+
+ void testRunStarting( TestRunInfo const& testRunInfo ) override;
+
+ void testRunEndedCumulative() override {
+ writeRun( *m_testRun );
+ xml.endElement();
+ }
+
+ void writeRun( TestRunNode const& groupNode );
+
+ void writeTestFile(std::string const& filename, std::vector<TestCaseNode const*> const& testCaseNodes);
+
+ void writeTestCase(TestCaseNode const& testCaseNode);
+
+ void writeSection(std::string const& rootName, SectionNode const& sectionNode, bool okToFail);
+
+ void writeAssertions(SectionNode const& sectionNode, bool okToFail);
+
+ void writeAssertion(AssertionStats const& stats, bool okToFail);
+
+ private:
+ XmlWriter xml;
+ };
+
+
+} // end namespace Catch
+
+#endif // CATCH_REPORTER_SONARQUBE_HPP_INCLUDED
+
+
+#ifndef CATCH_REPORTER_TAP_HPP_INCLUDED
+#define CATCH_REPORTER_TAP_HPP_INCLUDED
+
+
+namespace Catch {
+
+ class TAPReporter final : public StreamingReporterBase {
+ public:
+ TAPReporter( ReporterConfig&& config ):
+ StreamingReporterBase( CATCH_MOVE(config) ) {
+ m_preferences.shouldReportAllAssertions = true;
+ }
+ ~TAPReporter() override = default;
+
+ static std::string getDescription() {
+ using namespace std::string_literals;
+ return "Reports test results in TAP format, suitable for test harnesses"s;
+ }
+
+ void testRunStarting( TestRunInfo const& testInfo ) override;
+
+ void noMatchingTestCases( StringRef unmatchedSpec ) override;
+
+ void assertionEnded(AssertionStats const& _assertionStats) override;
+
+ void testRunEnded(TestRunStats const& _testRunStats) override;
+
+ private:
+ std::size_t counter = 0;
+ };
+
+} // end namespace Catch
+
+#endif // CATCH_REPORTER_TAP_HPP_INCLUDED
+
+
+#ifndef CATCH_REPORTER_TEAMCITY_HPP_INCLUDED
+#define CATCH_REPORTER_TEAMCITY_HPP_INCLUDED
+
+
+#include <cstring>
+
+#ifdef __clang__
+# pragma clang diagnostic push
+# pragma clang diagnostic ignored "-Wpadded"
+#endif
+
+namespace Catch {
+
+ class TeamCityReporter final : public StreamingReporterBase {
+ public:
+ TeamCityReporter( ReporterConfig&& _config )
+ : StreamingReporterBase( CATCH_MOVE(_config) )
+ {
+ m_preferences.shouldRedirectStdOut = true;
+ }
+
+ ~TeamCityReporter() override;
+
+ static std::string getDescription() {
+ using namespace std::string_literals;
+ return "Reports test results as TeamCity service messages"s;
+ }
+
+ void testRunStarting( TestRunInfo const& groupInfo ) override;
+ void testRunEnded( TestRunStats const& testGroupStats ) override;
+
+
+ void assertionEnded(AssertionStats const& assertionStats) override;
+
+ void sectionStarting(SectionInfo const& sectionInfo) override {
+ m_headerPrintedForThisSection = false;
+ StreamingReporterBase::sectionStarting( sectionInfo );
+ }
+
+ void testCaseStarting(TestCaseInfo const& testInfo) override;
+
+ void testCaseEnded(TestCaseStats const& testCaseStats) override;
+
+ private:
+ void printSectionHeader(std::ostream& os);
+
+ bool m_headerPrintedForThisSection = false;
+ Timer m_testTimer;
+ };
+
+} // end namespace Catch
+
+#ifdef __clang__
+# pragma clang diagnostic pop
+#endif
+
+#endif // CATCH_REPORTER_TEAMCITY_HPP_INCLUDED
+
+
+#ifndef CATCH_REPORTER_XML_HPP_INCLUDED
+#define CATCH_REPORTER_XML_HPP_INCLUDED
+
+
+
+
+namespace Catch {
+ class XmlReporter : public StreamingReporterBase {
+ public:
+ XmlReporter(ReporterConfig&& _config);
+
+ ~XmlReporter() override;
+
+ static std::string getDescription();
+
+ virtual std::string getStylesheetRef() const;
+
+ void writeSourceInfo(SourceLineInfo const& sourceInfo);
+
+ public: // StreamingReporterBase
+
+ void testRunStarting(TestRunInfo const& testInfo) override;
+
+ void testCaseStarting(TestCaseInfo const& testInfo) override;
+
+ void sectionStarting(SectionInfo const& sectionInfo) override;
+
+ void assertionStarting(AssertionInfo const&) override;
+
+ void assertionEnded(AssertionStats const& assertionStats) override;
+
+ void sectionEnded(SectionStats const& sectionStats) override;
+
+ void testCaseEnded(TestCaseStats const& testCaseStats) override;
+
+ void testRunEnded(TestRunStats const& testRunStats) override;
+
+ void benchmarkPreparing( StringRef name ) override;
+ void benchmarkStarting(BenchmarkInfo const&) override;
+ void benchmarkEnded(BenchmarkStats<> const&) override;
+ void benchmarkFailed( StringRef error ) override;
+
+ void listReporters(std::vector<ReporterDescription> const& descriptions) override;
+ void listListeners(std::vector<ListenerDescription> const& descriptions) override;
+ void listTests(std::vector<TestCaseHandle> const& tests) override;
+ void listTags(std::vector<TagInfo> const& tags) override;
+
+ private:
+ Timer m_testCaseTimer;
+ XmlWriter m_xml;
+ int m_sectionDepth = 0;
+ };
+
+} // end namespace Catch
+
+#endif // CATCH_REPORTER_XML_HPP_INCLUDED
+
+#endif // CATCH_REPORTERS_ALL_HPP_INCLUDED
+
+#endif // CATCH_ALL_HPP_INCLUDED
+#endif // CATCH_AMALGAMATED_HPP_INCLUDED
diff --git a/3rdparty/bx/LICENSE b/3rdparty/bx/LICENSE
index 3df43e30a2a..e21e5d5f338 100644
--- a/3rdparty/bx/LICENSE
+++ b/3rdparty/bx/LICENSE
@@ -1,4 +1,4 @@
-Copyright 2010-2018 Branimir Karadzic. All rights reserved.
+Copyright 2010-2022 Branimir Karadzic
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
@@ -10,13 +10,13 @@ are permitted provided that the following conditions are met:
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
-THIS SOFTWARE IS PROVIDED BY COPYRIGHT HOLDER ``AS IS'' AND ANY EXPRESS OR
-IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
-SHALL COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
-INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
-PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
-WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/3rdparty/bx/README.md b/3rdparty/bx/README.md
index 1d987c34f7f..849b7ee1c74 100644
--- a/3rdparty/bx/README.md
+++ b/3rdparty/bx/README.md
@@ -3,10 +3,9 @@ bx
Base library.
-[![Build Status](https://travis-ci.org/bkaradzic/bx.svg?branch=master)](https://travis-ci.org/bkaradzic/bx)
[![Build status](https://ci.appveyor.com/api/projects/status/edras3mltmoy31g5?svg=true)](https://ci.appveyor.com/project/bkaradzic/bx)
[![License](https://img.shields.io/badge/license-BSD--2%20clause-blue.svg)](https://bkaradzic.github.io/bgfx/license.html)
-[![Join the chat at https://gitter.im/bkaradzic/bgfx](https://badges.gitter.im/bkaradzic/bgfx.svg)](https://gitter.im/bkaradzic/bgfx)
+[![Join the chat at https://discord.gg/9eMbv7J](https://img.shields.io/discord/712512073522872352?color=%237289DA&label=bx&logo=discord&logoColor=white)](https://discord.gg/9eMbv7J)
Contact
-------
@@ -23,27 +22,25 @@ https://github.com/bkaradzic/bx
<img align="right" src="http://opensource.org/trademarks/opensource/OSI-Approved-License-100x137.png">
</a>
- Copyright 2010-2018 Branimir Karadzic. All rights reserved.
+ Copyright 2010-2022 Branimir Karadzic
- https://github.com/bkaradzic/bx
+ Redistribution and use in source and binary forms, with or without modification,
+ are permitted provided that the following conditions are met:
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions are met:
-
- 1. Redistributions of source code must retain the above copyright notice,
- this list of conditions and the following disclaimer.
+ 1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
- THIS SOFTWARE IS PROVIDED BY COPYRIGHT HOLDER ``AS IS'' AND ANY EXPRESS OR
- IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
- EVENT SHALL COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
- OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/3rdparty/bx/include/bx/allocator.h b/3rdparty/bx/include/bx/allocator.h
index cfd1475ab52..925441ee5ec 100644
--- a/3rdparty/bx/include/bx/allocator.h
+++ b/3rdparty/bx/include/bx/allocator.h
@@ -1,12 +1,13 @@
/*
- * Copyright 2010-2018 Branimir Karadzic. All rights reserved.
- * License: https://github.com/bkaradzic/bx#license-bsd-2-clause
+ * Copyright 2010-2022 Branimir Karadzic. All rights reserved.
+ * License: https://github.com/bkaradzic/bx/blob/master/LICENSE
*/
#ifndef BX_ALLOCATOR_H_HEADER_GUARD
#define BX_ALLOCATOR_H_HEADER_GUARD
#include "bx.h"
+#include "uint32_t.h"
#if BX_CONFIG_ALLOCATOR_DEBUG
# define BX_ALLOC(_allocator, _size) bx::alloc(_allocator, _size, 0, __FILE__, __LINE__)
@@ -30,9 +31,14 @@
#define BX_NEW(_allocator, _type) BX_PLACEMENT_NEW(BX_ALLOC(_allocator, sizeof(_type) ), _type)
#define BX_ALIGNED_NEW(_allocator, _type, _align) BX_PLACEMENT_NEW(BX_ALIGNED_ALLOC(_allocator, sizeof(_type), _align), _type)
-#define BX_PLACEMENT_NEW(_ptr, _type) ::new(bx::PlacementNewTag(), _ptr) _type
+#define BX_PLACEMENT_NEW(_ptr, _type) ::new(bx::PlacementNew, _ptr) _type
-namespace bx { struct PlacementNewTag {}; }
+namespace bx
+{
+ struct PlacementNewTag {};
+ constexpr PlacementNewTag PlacementNew;
+
+} // namespace bx
void* operator new(size_t, bx::PlacementNewTag, void* _ptr);
void operator delete(void*, bx::PlacementNewTag, void*) throw();
@@ -46,13 +52,20 @@ namespace bx
///
virtual ~AllocatorI() = 0;
- /// Allocates, resizes memory block, or frees memory.
+ /// Allocates, resizes, or frees memory block.
///
- /// @param[in] _ptr If _ptr is NULL new block will be allocated.
+ /// @remark
+ /// - Allocate memory block: _ptr == NULL && size > 0
+ /// - Resize memory block: _ptr != NULL && size > 0
+ /// - Free memory block: _ptr != NULL && size == 0
+ ///
+ /// @param[in] _ptr If _ptr is NULL new block will be allocated. If _ptr is not-NULL, and
+ /// _size is not 0, memory block will be resized.
/// @param[in] _size If _ptr is set, and _size is 0, memory will be freed.
/// @param[in] _align Alignment.
/// @param[in] _file Debug file path info.
/// @param[in] _line Debug file line info.
+ ///
virtual void* realloc(
void* _ptr
, size_t _size
@@ -82,9 +95,6 @@ namespace bx
) override;
};
- /// Check if pointer is aligned. _align must be power of two.
- bool isAligned(const void* _ptr, size_t _align);
-
/// Aligns pointer to nearest next aligned address. _align must be power of two.
void* alignPtr(
void* _ptr
diff --git a/3rdparty/bx/include/bx/bounds.h b/3rdparty/bx/include/bx/bounds.h
new file mode 100644
index 00000000000..12201b45f92
--- /dev/null
+++ b/3rdparty/bx/include/bx/bounds.h
@@ -0,0 +1,526 @@
+/*
+ * Copyright 2011-2022 Branimir Karadzic. All rights reserved.
+ * License: https://github.com/bkaradzic/bgfx#license-bsd-2-clause
+ */
+
+#ifndef BX_BOUNDS_H_HEADER_GUARD
+#define BX_BOUNDS_H_HEADER_GUARD
+
+#include <bx/math.h>
+
+namespace bx
+{
+ ///
+ struct Line
+ {
+ Vec3 pos = init::None;
+ Vec3 dir = init::None;
+ };
+
+ ///
+ struct LineSegment
+ {
+ Vec3 pos = init::None;
+ Vec3 end = init::None;
+ };
+
+ ///
+ struct Aabb
+ {
+ Vec3 min = init::None;
+ Vec3 max = init::None;
+ };
+
+ ///
+ struct Capsule
+ {
+ Vec3 pos = init::None;
+ Vec3 end = init::None;
+ float radius;
+ };
+
+ ///
+ struct Cone
+ {
+ Vec3 pos = init::None;
+ Vec3 end = init::None;
+ float radius;
+ };
+
+ ///
+ struct Cylinder
+ {
+ Vec3 pos = init::None;
+ Vec3 end = init::None;
+ float radius;
+ };
+
+ ///
+ struct Disk
+ {
+ Vec3 center = init::None;
+ Vec3 normal = init::None;
+ float radius;
+ };
+
+ ///
+ struct Obb
+ {
+ float mtx[16];
+ };
+
+ ///
+ struct Sphere
+ {
+ Vec3 center = init::None;
+ float radius;
+ };
+
+ ///
+ struct Triangle
+ {
+ Vec3 v0 = init::None;
+ Vec3 v1 = init::None;
+ Vec3 v2 = init::None;
+ };
+
+ ///
+ struct Ray
+ {
+ Vec3 pos = init::None;
+ Vec3 dir = init::None;
+ };
+
+ ///
+ struct Hit
+ {
+ Vec3 pos = init::None;
+ Plane plane = init::None;
+ };
+
+ ///
+ struct Interval
+ {
+ ///
+ Interval(float _val);
+
+ ///
+ Interval(float _min, float _max);
+
+ ///
+ void set(float _val);
+
+ ///
+ void setCenter(float _val);
+
+ ///
+ void expand(float _val);
+
+ float min;
+ float max;
+ };
+
+ ///
+ Vec3 getPointAt(const Ray& _ray, float _t);
+
+ ///
+ Vec3 getPointAt(const Line& _line, float _t);
+
+ ///
+ Vec3 getPointAt(const LineSegment& _line, float _t);
+
+ ///
+ Vec3 getCenter(const Aabb& _aabb);
+
+ ///
+ Vec3 getExtents(const Aabb& _aabb);
+
+ ///
+ Vec3 getCenter(const Triangle& _triangle);
+
+ ///
+ void toAabb(Aabb& _outAabb, const Vec3& _extents);
+
+ ///
+ void toAabb(Aabb& _outAabb, const Vec3& _center, const Vec3& _extents);
+
+ /// Convert cylinder to axis aligned bounding box.
+ void toAabb(Aabb& _outAabb, const Cylinder& _cylinder);
+
+ /// Convert disk to axis aligned bounding box.
+ void toAabb(Aabb& _outAabb, const Disk& _disk);
+
+ /// Convert oriented bounding box to axis aligned bounding box.
+ void toAabb(Aabb& _outAabb, const Obb& _obb);
+
+ /// Convert sphere to axis aligned bounding box.
+ void toAabb(Aabb& _outAabb, const Sphere& _sphere);
+
+ /// Convert triangle to axis aligned bounding box.
+ void toAabb(Aabb& _outAabb, const Triangle& _triangle);
+
+ /// Calculate axis aligned bounding box.
+ void toAabb(Aabb& _outAabb, const void* _vertices, uint32_t _numVertices, uint32_t _stride);
+
+ /// Transform vertices and calculate axis aligned bounding box.
+ void toAabb(Aabb& _outAabb, const float* _mtx, const void* _vertices, uint32_t _numVertices, uint32_t _stride);
+
+ /// Expand AABB.
+ void aabbExpand(Aabb& _outAabb, float _factor);
+
+ /// Expand AABB with xyz.
+ void aabbExpand(Aabb& _outAabb, const Vec3& _pos);
+
+ /// Calculate surface area of axis aligned bounding box.
+ float calcAreaAabb(const Aabb& _aabb);
+
+ /// Convert axis aligned bounding box to oriented bounding box.
+ void toObb(Obb& _outObb, const Aabb& _aabb);
+
+ /// Calculate oriented bounding box.
+ void calcObb(Obb& _outObb, const void* _vertices, uint32_t _numVertices, uint32_t _stride, uint32_t _steps = 17);
+
+ /// Calculate maximum bounding sphere.
+ void calcMaxBoundingSphere(Sphere& _outSphere, const void* _vertices, uint32_t _numVertices, uint32_t _stride);
+
+ /// Calculate minimum bounding sphere.
+ void calcMinBoundingSphere(Sphere& _outSphere, const void* _vertices, uint32_t _numVertices, uint32_t _stride, float _step = 0.01f);
+
+ /// Returns 6 (near, far, left, right, top, bottom) planes representing frustum planes.
+ void buildFrustumPlanes(Plane* _outPlanes, const float* _viewProj);
+
+ /// Returns point from 3 intersecting planes.
+ Vec3 intersectPlanes(const Plane& _pa, const Plane& _pb, const Plane& _pc);
+
+ /// Make screen space ray from x, y coordinate and inverse view-projection matrix.
+ Ray makeRay(float _x, float _y, const float* _invVp);
+
+ /// Intersect ray / AABB.
+ bool intersect(const Ray& _ray, const Aabb& _aabb, Hit* _hit = NULL);
+
+ /// Intersect ray / OBB.
+ bool intersect(const Ray& _ray, const Obb& _obb, Hit* _hit = NULL);
+
+ /// Intersect ray / cylinder.
+ bool intersect(const Ray& _ray, const Cylinder& _cylinder, Hit* _hit = NULL);
+
+ /// Intersect ray / capsule.
+ bool intersect(const Ray& _ray, const Capsule& _capsule, Hit* _hit = NULL);
+
+ /// Intersect ray / cone.
+ bool intersect(const Ray& _ray, const Cone& _cone, Hit* _hit = NULL);
+
+ /// Intersect ray / disk.
+ bool intersect(const Ray& _ray, const Disk& _disk, Hit* _hit = NULL);
+
+ /// Intersect ray / plane.
+ bool intersect(const Ray& _ray, const Plane& _plane, Hit* _hit = NULL);
+
+ /// Intersect ray / plane.
+ bool intersect(const Ray& _ray, const Plane& _plane, bool _doublesided, Hit* _hit = NULL);
+
+ /// Intersect ray / sphere.
+ bool intersect(const Ray& _ray, const Sphere& _sphere, Hit* _hit = NULL);
+
+ /// Intersect ray / triangle.
+ bool intersect(const Ray& _ray, const Triangle& _triangle, Hit* _hit = NULL);
+
+ ///
+ Vec3 closestPoint(const Line& _line, const Vec3& _point);
+
+ ///
+ Vec3 closestPoint(const LineSegment& _line, const Vec3& _point);
+
+ ///
+ Vec3 closestPoint(const Plane& _plane, const Vec3& _point);
+
+ ///
+ Vec3 closestPoint(const Aabb& _aabb, const Vec3& _point);
+
+ ///
+ Vec3 closestPoint(const Obb& _obb, const Vec3& _point);
+
+ ///
+ Vec3 closestPoint(const Triangle& _triangle, const Vec3& _point);
+
+ ///
+ bool overlap(const Interval& _interval, float _pos);
+
+ ///
+ bool overlap(const Interval& _intervalA, const Interval& _intervalB);
+
+ ///
+ bool overlap(const Aabb& _aabb, const Vec3& _pos);
+
+ ///
+ bool overlap(const Aabb& _aabb, const Sphere& _sphere);
+
+ ///
+ bool overlap(const Aabb& _aabbA, const Aabb& _aabbB);
+
+ ///
+ bool overlap(const Aabb& _aabb, const Plane& _plane);
+
+ ///
+ bool overlap(const Aabb& _aabb, const Triangle& _triangle);
+
+ ///
+ bool overlap(const Aabb& _aabb, const Cylinder& _cylinder);
+
+ ///
+ bool overlap(const Aabb& _aabb, const Capsule& _capsule);
+
+ ///
+ bool overlap(const Aabb& _aabb, const Cone& _cone);
+
+ ///
+ bool overlap(const Aabb& _aabb, const Disk& _disk);
+
+ ///
+ bool overlap(const Aabb& _aabb, const Obb& _obb);
+
+ ///
+ bool overlap(const Capsule& _capsule, const Vec3& _pos);
+
+ ///
+ bool overlap(const Capsule& _capsule, const Sphere& _sphere);
+
+ ///
+ bool overlap(const Capsule& _capsule, const Aabb& _aabb);
+
+ ///
+ bool overlap(const Capsule& _capsule, const Plane& _plane);
+
+ ///
+ bool overlap(const Capsule& _capsule, const Triangle& _triangle);
+
+ ///
+ bool overlap(const Capsule& _capsule, const Cylinder& _cylinder);
+
+ ///
+ bool overlap(const Capsule& _capsuleA, const Capsule& _capsuleB);
+
+ ///
+ bool overlap(const Capsule& _capsule, const Cone& _cone);
+
+ ///
+ bool overlap(const Capsule& _capsule, const Disk& _disk);
+
+ ///
+ bool overlap(const Capsule& _capsule, const Obb& _obb);
+
+ ///
+ bool overlap(const Cone& _cone, const Vec3& _pos);
+
+ ///
+ bool overlap(const Cone& _cone, const Sphere& _sphere);
+
+ ///
+ bool overlap(const Cone& _cone, const Aabb& _aabb);
+
+ ///
+ bool overlap(const Cone& _cone, const Plane& _plane);
+
+ ///
+ bool overlap(const Cone& _cone, const Triangle& _triangle);
+
+ ///
+ bool overlap(const Cone& _cone, const Cylinder& _cylinder);
+
+ ///
+ bool overlap(const Cone& _cone, const Capsule& _capsule);
+
+ ///
+ bool overlap(const Cone& _coneA, const Cone& _coneB);
+
+ ///
+ bool overlap(const Cone& _cone, const Disk& _disk);
+
+ ///
+ bool overlap(const Cone& _cone, const Obb& _obb);
+
+ ///
+ bool overlap(const Cylinder& _cylinder, const Vec3& _pos);
+
+ ///
+ bool overlap(const Cylinder& _cylinder, const Sphere& _sphere);
+
+ ///
+ bool overlap(const Cylinder& _cylinder, const Aabb& _aabb);
+
+ ///
+ bool overlap(const Cylinder& _cylinder, const Plane& _plane);
+
+ ///
+ bool overlap(const Cylinder& _cylinder, const Triangle& _triangle);
+
+ ///
+ bool overlap(const Cylinder& _cylinderA, const Cylinder& _cylinderB);
+
+ ///
+ bool overlap(const Cylinder& _cylinder, const Capsule& _capsule);
+
+ ///
+ bool overlap(const Cylinder& _cylinder, const Cone& _cone);
+
+ ///
+ bool overlap(const Cylinder& _cylinder, const Disk& _disk);
+
+ ///
+ bool overlap(const Cylinder& _cylinder, const Obb& _obb);
+
+ ///
+ bool overlap(const Disk& _disk, const Vec3& _pos);
+
+ ///
+ bool overlap(const Disk& _disk, const Sphere& _sphere);
+
+ ///
+ bool overlap(const Disk& _disk, const Aabb& _aabb);
+
+ ///
+ bool overlap(const Disk& _disk, const Plane& _plane);
+
+ ///
+ bool overlap(const Disk& _disk, const Triangle& _triangle);
+
+ ///
+ bool overlap(const Disk& _disk, const Cylinder& _cylinder);
+
+ ///
+ bool overlap(const Disk& _disk, const Capsule& _capsule);
+
+ ///
+ bool overlap(const Disk& _disk, const Cone& _cone);
+
+ ///
+ bool overlap(const Disk& _diskA, const Disk& _diskB);
+
+ ///
+ bool overlap(const Disk& _disk, const Obb& _obb);
+
+ ///
+ bool overlap(const Obb& _obb, const Vec3& _pos);
+
+ ///
+ bool overlap(const Obb& _obb, const Sphere& _sphere);
+
+ ///
+ bool overlap(const Obb& _obb, const Aabb& _aabb);
+
+ ///
+ bool overlap(const Obb& _obb, const Plane& _plane);
+
+ ///
+ bool overlap(const Obb& _obb, const Triangle& _triangle);
+
+ ///
+ bool overlap(const Obb& _obb, const Cylinder& _cylinder);
+
+ ///
+ bool overlap(const Obb& _obb, const Capsule& _capsule);
+
+ ///
+ bool overlap(const Obb& _obb, const Cone& _cone);
+
+ ///
+ bool overlap(const Obb& _obb, const Disk& _disk);
+
+ ///
+ bool overlap(const Obb& _obbA, const Obb& _obbB);
+
+ ///
+ bool overlap(const Plane& _plane, const Vec3& _pos);
+
+ ///
+ bool overlap(const Plane& _plane, const Sphere& _sphere);
+
+ ///
+ bool overlap(const Plane& _plane, const Aabb& _aabb);
+
+ ///
+ bool overlap(const Plane& _planeA, const Plane& _planeB);
+
+ ///
+ bool overlap(const Plane& _plane, const Triangle& _triangle);
+
+ ///
+ bool overlap(const Plane& _plane, const Cylinder& _cylinder);
+
+ ///
+ bool overlap(const Plane& _plane, const Capsule& _capsule);
+
+ ///
+ bool overlap(const Plane& _plane, const Cone& _cone);
+
+ ///
+ bool overlap(const Plane& _plane, const Disk& _disk);
+
+ ///
+ bool overlap(const Plane& _plane, const Obb& _obb);
+
+ ///
+ bool overlap(const Sphere& _sphere, const Vec3& _pos);
+
+ ///
+ bool overlap(const Sphere& _sphereA, const Sphere& _sphereB);
+
+ ///
+ bool overlap(const Sphere& _sphere, const Aabb& _aabb);
+
+ ///
+ bool overlap(const Sphere& _sphere, const Plane& _plane);
+
+ ///
+ bool overlap(const Sphere& _sphere, const Triangle& _triangle);
+
+ ///
+ bool overlap(const Sphere& _sphere, const Cylinder& _cylinder);
+
+ ///
+ bool overlap(const Sphere& _sphere, const Capsule& _capsule);
+
+ ///
+ bool overlap(const Sphere& _sphere, const Cone& _cone);
+
+ ///
+ bool overlap(const Sphere& _sphere, const Disk& _disk);
+
+ ///
+ bool overlap(const Sphere& _sphere, const Obb& _obb);
+
+ ///
+ bool overlap(const Triangle& _triangle, const Vec3& _pos);
+
+ ///
+ bool overlap(const Triangle& _triangle, const Sphere& _sphere);
+
+ ///
+ bool overlap(const Triangle& _triangle, const Aabb& _aabb);
+
+ ///
+ bool overlap(const Triangle& _triangle, const Plane& _plane);
+
+ ///
+ bool overlap(const Triangle& _triangleA, const Triangle& _triangleB);
+
+ ///
+ bool overlap(const Triangle& _triangle, const Cylinder& _cylinder);
+
+ ///
+ bool overlap(const Triangle& _triangle, const Capsule& _capsule);
+
+ ///
+ bool overlap(const Triangle& _triangle, const Cone& _cone);
+
+ ///
+ bool overlap(const Triangle& _triangle, const Disk& _disk);
+
+ ///
+ bool overlap(const Triangle& _triangle, const Obb& _obb);
+
+} // namespace bx
+
+#include "inline/bounds.inl"
+
+#endif // BX_BOUNDS_H_HEADER_GUARD
diff --git a/3rdparty/bx/include/bx/bx.h b/3rdparty/bx/include/bx/bx.h
index 7c2d06162aa..fb032a57fc6 100644
--- a/3rdparty/bx/include/bx/bx.h
+++ b/3rdparty/bx/include/bx/bx.h
@@ -1,6 +1,6 @@
/*
- * Copyright 2010-2018 Branimir Karadzic. All rights reserved.
- * License: https://github.com/bkaradzic/bx#license-bsd-2-clause
+ * Copyright 2010-2022 Branimir Karadzic. All rights reserved.
+ * License: https://github.com/bkaradzic/bx/blob/master/LICENSE
*/
#ifndef BX_H_HEADER_GUARD
@@ -14,29 +14,61 @@
#include "platform.h"
#include "config.h"
+#include "constants.h"
#include "macros.h"
+#include "debug.h"
+#include "typetraits.h"
///
#define BX_COUNTOF(_x) sizeof(bx::CountOfRequireArrayArgumentT(_x) )
///
-#define BX_IGNORE_C4127(_x) bx::ignoreC4127(!!(_x) )
+#define BX_OFFSETOF(_type, _member) \
+ (reinterpret_cast<ptrdiff_t>(&(reinterpret_cast<_type*>(16)->_member) )-ptrdiff_t(16) )
///
-#define BX_ENABLED(_x) bx::isEnabled<!!(_x)>()
+#if BX_COMPILER_MSVC
+# define BX_IGNORE_C4127(_x) bx::ignoreC4127(!!(_x) )
+#else
+# define BX_IGNORE_C4127(_x) (!!(_x) )
+#endif // BX_COMPILER_MSVC
+
+///
+#define BX_ENABLED(_x) BX_IGNORE_C4127(bx::isEnabled<!!(_x)>::value)
namespace bx
{
- constexpr int32_t kExitSuccess = 0;
- constexpr int32_t kExitFailure = 1;
+ /// Arithmetic type `Ty` limits.
+ template<typename Ty, bool SignT = isSigned<Ty>()>
+ struct LimitsT;
+
+ /// Find the address of an object of a class that has an overloaded unary ampersand (&) operator.
+ template<typename Ty>
+ Ty* addressOf(Ty& _a);
+
+ /// Find the address of an object of a class that has an overloaded unary ampersand (&) operator.
+ template<typename Ty>
+ const Ty* addressOf(const Ty& _a);
- /// Template for avoiding MSVC: C4127: conditional expression is constant
- template<bool>
- constexpr bool isEnabled();
+ /// Returns typed pointer from typeless pointer offseted.
+ ///
+ /// @param[in] _ptr Pointer to get offset from.
+ /// @param[in] _offsetInBytes Offset from pointer in bytes.
+ ///
+ /// @returns Typed pointer from typeless pointer offseted.
+ ///
+ template<typename Ty>
+ Ty* addressOf(void* _ptr, ptrdiff_t _offsetInBytes = 0);
+ /// Returns typed pointer from typeless pointer offseted.
///
- template<class Ty>
- constexpr bool isTriviallyCopyable();
+ /// @param[in] _ptr Pointer to get offset from.
+ /// @param[in] _offsetInBytes Offset from pointer in bytes.
+ ///
+ /// @returns Typed pointer from typeless pointer offseted.
+ ///
+ template<typename Ty>
+ const Ty* addressOf(const void* _ptr, ptrdiff_t _offsetInBytes = 0);
/// Swap two values.
template<typename Ty>
@@ -45,55 +77,170 @@ namespace bx
/// Swap memory.
void swap(void* _a, void* _b, size_t _numBytes);
- /// Returns minimum of two values.
+ /// Returns numeric minimum of type.
template<typename Ty>
- constexpr Ty min(const Ty& _a, const Ty& _b);
+ constexpr Ty min();
- /// Returns maximum of two values.
+ /// Returns numeric maximum of type.
template<typename Ty>
- constexpr Ty max(const Ty& _a, const Ty& _b);
+ constexpr Ty max();
- /// Returns minimum of three values.
+ /// Returns minimum of two values.
template<typename Ty>
- constexpr Ty min(const Ty& _a, const Ty& _b, const Ty& _c);
+ constexpr Ty min(const Ty& _a, const TypeIdentityType<Ty>& _b);
- /// Returns maximum of three values.
+ /// Returns maximum of two values.
template<typename Ty>
- constexpr Ty max(const Ty& _a, const Ty& _b, const Ty& _c);
+ constexpr Ty max(const Ty& _a, const TypeIdentityType<Ty>& _b);
- /// Returns middle of three values.
- template<typename Ty>
- constexpr Ty mid(const Ty& _a, const Ty& _b, const Ty& _c);
+ /// Returns minimum of three or more values.
+ template<typename Ty, typename... Args>
+ constexpr Ty min(const Ty& _a, const TypeIdentityType<Ty>& _b, const Args&... _args);
+
+ /// Returns maximum of three or more values.
+ template<typename Ty, typename... Args>
+ constexpr Ty max(const Ty& _a, const TypeIdentityType<Ty>& _b, const Args&... _args);
+
+ /// Returns middle of three or more values.
+ template<typename Ty, typename... Args>
+ constexpr Ty mid(const Ty& _a, const TypeIdentityType<Ty>& _b, const Args&... _args);
/// Returns clamped value between min/max.
template<typename Ty>
- constexpr Ty clamp(const Ty& _a, const Ty& _min, const Ty& _max);
+ constexpr Ty clamp(const Ty& _a, const TypeIdentityType<Ty>& _min, const TypeIdentityType<Ty>& _max);
- /// Returns true if value is power of 2.
+ /// Returns true if value `_a` is power of 2.
template<typename Ty>
constexpr bool isPowerOf2(Ty _a);
+ /// Copy memory block.
+ ///
+ /// @param _dst Destination pointer.
+ /// @param _src Source pointer.
+ /// @param _numBytes Number of bytes to copy.
+ ///
+ /// @remark Source and destination memory blocks must not overlap.
///
void memCopy(void* _dst, const void* _src, size_t _numBytes);
+ /// Copy strided memory block.
///
- void memCopy(void* _dst, const void* _src, uint32_t _size, uint32_t _num, uint32_t _srcPitch, uint32_t _dstPitch);
-
+ /// @param _dst Destination pointer.
+ /// @param _dstStride Destination stride.
+ /// @param _src Source pointer.
+ /// @param _srcStride Source stride.
+ /// @param _stride Number of bytes per stride to copy.
+ /// @param _numStrides Number of strides.
///
- void gather(void* _dst, const void* _src, uint32_t _size, uint32_t _num, uint32_t _srcPitch);
-
+ /// @remark Source and destination memory blocks must not overlap.
///
- void scatter(void* _dst, const void* _src, uint32_t _size, uint32_t _num, uint32_t _dstPitch);
-
+ void memCopy(
+ void* _dst
+ , uint32_t _dstStride
+ , const void* _src
+ , uint32_t _srcStride
+ , uint32_t _stride
+ , uint32_t _numStrides
+ );
+
+ /// Copy memory block.
+ ///
+ /// @param _dst Destination pointer.
+ /// @param _src Source pointer.
+ /// @param _numBytes Number of bytes to copy.
+ ///
+ /// @remark If source and destination memory blocks overlap memory will be copied in reverse
+ /// order.
///
void memMove(void* _dst, const void* _src, size_t _numBytes);
+ /// Copy strided memory block.
+ ///
+ /// @param _dst Destination pointer.
+ /// @param _dstStride Destination stride.
+ /// @param _src Source pointer.
+ /// @param _srcStride Source stride.
+ /// @param _stride Number of bytes per stride to copy.
+ /// @param _numStrides Number of strides.
+ ///
+ /// @remark If source and destination memory blocks overlap memory will be copied in reverse
+ /// order.
+ ///
+ void memMove(
+ void* _dst
+ , uint32_t _dstStride
+ , const void* _src
+ , uint32_t _srcStride
+ , uint32_t _stride
+ , uint32_t _numStrides
+ );
+
+ /// Fill memory block to specified value `_ch`.
+ ///
+ /// @param _dst Destination pointer.
+ /// @param _ch Fill value.
+ /// @param _numBytes Number of bytes to copy.
///
void memSet(void* _dst, uint8_t _ch, size_t _numBytes);
+ /// Fill strided memory block to specified value `_ch`.
+ ///
+ /// @param _dst Destination pointer.
+ /// @param _dstStride Destination stride.
+ /// @param _ch Fill value.
+ /// @param _stride Number of bytes per stride to copy.
+ /// @param _numStrides Number of strides.
+ ///
+ void memSet(
+ void* _dst
+ , uint32_t _dstStride
+ , uint8_t _ch
+ , uint32_t _stride
+ , uint32_t _numStrides
+ );
+
+ /// Compare two memory blocks.
+ ///
+ /// @param _lhs Pointer to memory block.
+ /// @param _rhs Pointer to memory block.
+ /// @param _numBytes Number of bytes to compare.
+ ///
+ /// @returns 0 if two blocks are identical, positive value if first different byte in `_lhs` is
+ /// greater than corresponding byte in `_rhs`.
///
int32_t memCmp(const void* _lhs, const void* _rhs, size_t _numBytes);
+ /// Gather data scattered through memory into linear memory block.
+ ///
+ /// @param _dst Destination pointer.
+ /// @param _src Source pointer.
+ /// @param _stride Number of bytes per stride to copy.
+ /// @param _numStrides Number of strides.
+ ///
+ void gather(
+ void* _dst
+ , const void* _src
+ , uint32_t _srcStride
+ , uint32_t _stride
+ , uint32_t _numStrides
+ );
+
+ /// Scatter data from linear memory block through memory.
+ ///
+ /// @param _dst Destination pointer.
+ /// @param _dstStride Destination stride.
+ /// @param _src Source pointer.
+ /// @param _stride Number of bytes per stride to copy.
+ /// @param _numStrides Number of strides.
+ ///
+ void scatter(
+ void* _dst
+ , uint32_t _dstStride
+ , const void* _src
+ , uint32_t _stride
+ , uint32_t _numStrides
+ );
+
} // namespace bx
#include "inline/bx.inl"
diff --git a/3rdparty/bx/include/bx/commandline.h b/3rdparty/bx/include/bx/commandline.h
index dbd2af39427..10adb88cd58 100644
--- a/3rdparty/bx/include/bx/commandline.h
+++ b/3rdparty/bx/include/bx/commandline.h
@@ -1,6 +1,6 @@
/*
- * Copyright 2010-2018 Branimir Karadzic. All rights reserved.
- * License: https://github.com/bkaradzic/bx#license-bsd-2-clause
+ * Copyright 2010-2022 Branimir Karadzic. All rights reserved.
+ * License: https://github.com/bkaradzic/bx/blob/master/LICENSE
*/
#ifndef BX_COMMANDLINE_H_HEADER_GUARD
diff --git a/3rdparty/bx/include/bx/config.h b/3rdparty/bx/include/bx/config.h
index 787859de6cf..4e32ccf23b3 100644
--- a/3rdparty/bx/include/bx/config.h
+++ b/3rdparty/bx/include/bx/config.h
@@ -1,16 +1,18 @@
/*
- * Copyright 2010-2018 Branimir Karadzic. All rights reserved.
- * License: https://github.com/bkaradzic/bx#license-bsd-2-clause
+ * Copyright 2010-2022 Branimir Karadzic. All rights reserved.
+ * License: https://github.com/bkaradzic/bx/blob/master/LICENSE
*/
#ifndef BX_CONFIG_H_HEADER_GUARD
#define BX_CONFIG_H_HEADER_GUARD
-#include "bx.h"
+#ifndef BX_CONFIG_DEBUG
+# error "BX_CONFIG_DEBUG must be defined in build script!"
+#endif // BX_CONFIG_DEBUG
#ifndef BX_CONFIG_ALLOCATOR_DEBUG
-# define BX_CONFIG_ALLOCATOR_DEBUG 0
-#endif // BX_CONFIG_DEBUG_ALLOC
+# define BX_CONFIG_ALLOCATOR_DEBUG BX_CONFIG_DEBUG
+#endif // BX_CONFIG_ALLOCATOR_DEBUG
#ifndef BX_CONFIG_SUPPORTS_THREADING
# define BX_CONFIG_SUPPORTS_THREADING !(0 \
diff --git a/3rdparty/bx/include/bx/constants.h b/3rdparty/bx/include/bx/constants.h
new file mode 100644
index 00000000000..14c4cdbb35f
--- /dev/null
+++ b/3rdparty/bx/include/bx/constants.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2011-2022 Branimir Karadzic. All rights reserved.
+ * License: https://github.com/bkaradzic/bx/blob/master/LICENSE
+ */
+
+#ifndef BX_CONSTANTS_H_HEADER_GUARD
+#define BX_CONSTANTS_H_HEADER_GUARD
+
+namespace bx
+{
+ /// Used to return successful execution of a program code.
+ constexpr int32_t kExitSuccess = 0;
+
+ /// Used to return unsuccessful execution of a program code.
+ constexpr int32_t kExitFailure = 1;
+
+ /// The ratio of a circle's circumference to its diameter,
+ constexpr float kPi = 3.1415926535897932384626433832795f;
+
+ /// The ratio of a circle's circumference to its radius. Pi multiplied by 2, or Tau. pi*2
+ constexpr float kPi2 = 6.2831853071795864769252867665590f;
+
+ /// The reciprocal of pi. 1/pi
+ constexpr float kInvPi = 1.0f/kPi;
+
+ /// Pi divided by two. pi/2
+ constexpr float kPiHalf = 1.5707963267948966192313216916398f;
+
+ /// Pi divided by four. pi/4
+ constexpr float kPiQuarter = 0.7853981633974483096156608458199f;
+
+ /// The square root of two. sqrt(2)
+ constexpr float kSqrt2 = 1.4142135623730950488016887242097f;
+
+ /// ln(10)
+ constexpr float kLogNat10 = 2.3025850929940456840179914546844f;
+
+ /// The logarithm of the e to base 2. ln(kE) / ln(2)
+ constexpr float kInvLogNat2 = 1.4426950408889634073599246810019f;
+
+ /// The natural logarithm of the 2. ln(2)
+ constexpr float kLogNat2Hi = 0.6931471805599453094172321214582f;
+
+ ///
+ constexpr float kLogNat2Lo = 1.90821492927058770002e-10f;
+
+ /// The base of natural logarithms. e(1)
+ constexpr float kE = 2.7182818284590452353602874713527f;
+
+ ///
+ constexpr float kNearZero = 1.0f/float(1 << 28);
+
+ /// Smallest normalized positive floating-point number.
+ constexpr float kFloatSmallest = 1.175494351e-38f;
+
+ /// Maximum representable floating-point number.
+ constexpr float kFloatLargest = 3.402823466e+38f;
+
+ /// Smallest normalized positive double-precision floating-point number.
+ constexpr double kDoubleSmallest = 2.2250738585072014e-308;
+
+ /// Largest representable double-precision floating-point number.
+ constexpr double kDoubleLargest = 1.7976931348623158e+308;
+
+ ///
+ extern const float kInfinity;
+
+} // namespace bx
+
+#endif // BX_CONSTANTS_H_HEADER_GUARD
diff --git a/3rdparty/bx/include/bx/cpu.h b/3rdparty/bx/include/bx/cpu.h
index a2e81a1a1ca..dc3a544bca0 100644
--- a/3rdparty/bx/include/bx/cpu.h
+++ b/3rdparty/bx/include/bx/cpu.h
@@ -1,6 +1,6 @@
/*
- * Copyright 2010-2018 Branimir Karadzic. All rights reserved.
- * License: https://github.com/bkaradzic/bx#license-bsd-2-clause
+ * Copyright 2010-2022 Branimir Karadzic. All rights reserved.
+ * License: https://github.com/bkaradzic/bx/blob/master/LICENSE
*/
#ifndef BX_CPU_H_HEADER_GUARD
diff --git a/3rdparty/bx/include/bx/debug.h b/3rdparty/bx/include/bx/debug.h
index 80efaf97c87..3a0719c32ee 100644
--- a/3rdparty/bx/include/bx/debug.h
+++ b/3rdparty/bx/include/bx/debug.h
@@ -1,15 +1,17 @@
/*
- * Copyright 2010-2018 Branimir Karadzic. All rights reserved.
- * License: https://github.com/bkaradzic/bx#license-bsd-2-clause
+ * Copyright 2010-2022 Branimir Karadzic. All rights reserved.
+ * License: https://github.com/bkaradzic/bx/blob/master/LICENSE
*/
#ifndef BX_DEBUG_H_HEADER_GUARD
#define BX_DEBUG_H_HEADER_GUARD
-#include "string.h"
+#include "bx.h"
namespace bx
{
+ class StringView;
+
///
void debugBreak();
diff --git a/3rdparty/bx/include/bx/easing.h b/3rdparty/bx/include/bx/easing.h
index 8581b975c9c..05ee40e788c 100644
--- a/3rdparty/bx/include/bx/easing.h
+++ b/3rdparty/bx/include/bx/easing.h
@@ -1,6 +1,6 @@
/*
- * Copyright 2011-2018 Branimir Karadzic. All rights reserved.
- * License: https://github.com/bkaradzic/bx#license-bsd-2-clause
+ * Copyright 2011-2022 Branimir Karadzic. All rights reserved.
+ * License: https://github.com/bkaradzic/bx/blob/master/LICENSE
*/
#ifndef BX_EASING_H_HEADER_GUARD
diff --git a/3rdparty/bx/include/bx/endian.h b/3rdparty/bx/include/bx/endian.h
index 22965b5f31a..559e4bab453 100644
--- a/3rdparty/bx/include/bx/endian.h
+++ b/3rdparty/bx/include/bx/endian.h
@@ -1,6 +1,6 @@
/*
- * Copyright 2010-2018 Branimir Karadzic. All rights reserved.
- * License: https://github.com/bkaradzic/bx#license-bsd-2-clause
+ * Copyright 2010-2022 Branimir Karadzic. All rights reserved.
+ * License: https://github.com/bkaradzic/bx/blob/master/LICENSE
*/
#ifndef BX_ENDIAN_H_HEADER_GUARD
@@ -28,13 +28,13 @@ namespace bx
///
uint64_t endianSwap(uint64_t _in);
- /// Input argument is encoded as little endian, convert it if neccessary
- /// depending on host CPU endianess.
+ /// Input argument is encoded as little endian, convert it if necessary
+ /// depending on host CPU endianness.
template <typename Ty>
Ty toLittleEndian(const Ty _in);
- /// Input argument is encoded as big endian, convert it if neccessary
- /// depending on host CPU endianess.
+ /// Input argument is encoded as big endian, convert it if necessary
+ /// depending on host CPU endianness.
template <typename Ty>
Ty toBigEndian(const Ty _in);
diff --git a/3rdparty/bx/include/bx/error.h b/3rdparty/bx/include/bx/error.h
index 1eb220e7be0..a44a3a8d8cb 100644
--- a/3rdparty/bx/include/bx/error.h
+++ b/3rdparty/bx/include/bx/error.h
@@ -1,6 +1,6 @@
/*
- * Copyright 2010-2018 Branimir Karadzic. All rights reserved.
- * License: https://github.com/bkaradzic/bx#license-bsd-2-clause
+ * Copyright 2010-2022 Branimir Karadzic. All rights reserved.
+ * License: https://github.com/bkaradzic/bx/blob/master/LICENSE
*/
#ifndef BX_ERROR_H_HEADER_GUARD
@@ -8,22 +8,22 @@
#include "string.h"
-#define BX_ERROR_SET(_ptr, _result, _msg) \
- BX_MACRO_BLOCK_BEGIN \
- (_ptr)->setError(_result, "" _msg); \
- BX_MACRO_BLOCK_END
+#define BX_ERROR_SET(_ptr, _result, _msg) \
+ BX_MACRO_BLOCK_BEGIN \
+ (_ptr)->setError(_result, "" _msg); \
+ BX_MACRO_BLOCK_END
-#define BX_ERROR_USE_TEMP_WHEN_NULL(_ptr) \
- const bx::Error tmpError; /* It should not be used directly! */ \
- _ptr = NULL == _ptr ? const_cast<bx::Error*>(&tmpError) : _ptr
+#define BX_ERROR_USE_TEMP_WHEN_NULL(_ptr) \
+ const bx::Error tmpError; /* It should not be used directly! */ \
+ _ptr = NULL == _ptr ? const_cast<bx::Error*>(&tmpError) : _ptr
-#define BX_ERROR_SCOPE(_ptr) \
- BX_ERROR_USE_TEMP_WHEN_NULL(_ptr); \
- bx::ErrorScope bxErrorScope(const_cast<bx::Error*>(&tmpError) )
+#define BX_ERROR_SCOPE(_ptr, ...) \
+ BX_ERROR_USE_TEMP_WHEN_NULL(_ptr); \
+ bx::ErrorScope bxErrorScope(const_cast<bx::Error*>(&tmpError), "" __VA_ARGS__)
-#define BX_ERROR_RESULT(_err, _code) \
- BX_STATIC_ASSERT(_code != 0, "ErrorCode 0 is reserved!"); \
- static const bx::ErrorResult _err = { _code }
+#define BX_ERROR_RESULT(_err, _code) \
+ BX_STATIC_ASSERT(_code != 0, "ErrorCode 0 is reserved!"); \
+ static constexpr bx::ErrorResult _err = { _code }
namespace bx
{
@@ -38,7 +38,6 @@ namespace bx
{
BX_CLASS(Error
, NO_COPY
- , NO_ASSIGNMENT
);
public:
@@ -71,23 +70,57 @@ namespace bx
uint32_t m_code;
};
+ /// Do nothing even if error is set.
+ class ErrorIgnore : public Error
+ {
+ public:
+ ///
+ operator Error*();
+ };
+
+ /// In debug build assert if error is set.
+ class ErrorAssert : public Error
+ {
+ public:
+ ///
+ ~ErrorAssert();
+
+ ///
+ operator Error*();
+ };
+
+ /// Exit application if error is set.
+ class ErrorFatal : public Error
+ {
+ public:
+ ///
+ ~ErrorFatal();
+
+ ///
+ operator Error*();
+ };
+
///
class ErrorScope
{
BX_CLASS(ErrorScope
+ , NO_DEFAULT_CTOR
, NO_COPY
- , NO_ASSIGNMENT
);
public:
///
- ErrorScope(Error* _err);
+ ErrorScope(Error* _err, const StringView& _name);
///
~ErrorScope();
+ ///
+ const StringView& getName() const;
+
private:
Error* m_err;
+ const StringView m_name;
};
} // namespace bx
diff --git a/3rdparty/bx/include/bx/file.h b/3rdparty/bx/include/bx/file.h
index 4c0dd415f1b..88def0e0054 100644
--- a/3rdparty/bx/include/bx/file.h
+++ b/3rdparty/bx/include/bx/file.h
@@ -1,6 +1,6 @@
/*
- * Copyright 2010-2018 Branimir Karadzic. All rights reserved.
- * License: https://github.com/bkaradzic/bx#license-bsd-2-clause
+ * Copyright 2010-2022 Branimir Karadzic. All rights reserved.
+ * License: https://github.com/bkaradzic/bx/blob/master/LICENSE
*/
#ifndef BX_FILE_H_HEADER_GUARD
@@ -11,19 +11,19 @@
namespace bx
{
- ///
+ /// Returns standard input reader.
ReaderI* getStdIn();
- ///
+ /// Returns standard output writer.
WriterI* getStdOut();
- ///
+ /// Returns standard error writer.
WriterI* getStdErr();
- ///
+ /// Returns null output writer.
WriterI* getNullOut();
- ///
+ /// File reader.
class FileReader : public FileReaderI
{
public:
@@ -49,7 +49,7 @@ namespace bx
BX_ALIGN_DECL(16, uint8_t) m_internal[64];
};
- ///
+ /// File writer.
class FileWriter : public FileWriterI
{
public:
@@ -75,23 +75,68 @@ namespace bx
BX_ALIGN_DECL(16, uint8_t) m_internal[64];
};
- ///
- struct FileInfo
+ /// File type.
+ struct FileType
{
+ /// File types:
enum Enum
{
- Regular,
- Directory,
+ File, //!< File.
+ Dir, //!< Directory.
Count
};
+ };
+
+ /// File info.
+ struct FileInfo
+ {
+ FilePath filePath; //!< File path.
+ uint64_t size; //!< File size.
+ FileType::Enum type; //!< File type.
+ };
+
+ /// Directory reader.
+ class DirectoryReader : public ReaderOpenI, public CloserI, public ReaderI
+ {
+ public:
+ ///
+ DirectoryReader();
+
+ ///
+ virtual ~DirectoryReader();
+
+ ///
+ virtual bool open(const FilePath& _filePath, Error* _err) override;
+
+ ///
+ virtual void close() override;
+
+ ///
+ virtual int32_t read(void* _data, int32_t _size, Error* _err) override;
- uint64_t m_size;
- Enum m_type;
+ private:
+ BX_ALIGN_DECL(16, uint8_t) m_internal[sizeof(FilePath)+sizeof(FileInfo)+16];
};
+ /// FIle stat.
+ bool stat(FileInfo& _outFileInfo, const FilePath& _filePath);
+
+ /// Creates a directory named `_filePath`.
+ ///
+ bool make(const FilePath& _filePath, Error* _err = bx::ErrorIgnore{});
+
+ /// Creates a directory named `_filePath` along with all necessary parents.
+ ///
+ bool makeAll(const FilePath& _filePath, Error* _err = bx::ErrorIgnore{});
+
+ /// Removes file or directory.
+ ///
+ bool remove(const FilePath& _filePath, Error* _err = bx::ErrorIgnore{});
+
+ /// Removes file or directory recursively.
///
- bool stat(const FilePath& _filePath, FileInfo& _outFileInfo);
+ bool removeAll(const FilePath& _filePath, Error* _err = bx::ErrorIgnore{});
} // namespace bx
diff --git a/3rdparty/bx/include/bx/filepath.h b/3rdparty/bx/include/bx/filepath.h
index c71a1695cfb..464799e2166 100644
--- a/3rdparty/bx/include/bx/filepath.h
+++ b/3rdparty/bx/include/bx/filepath.h
@@ -1,6 +1,6 @@
/*
- * Copyright 2010-2018 Branimir Karadzic. All rights reserved.
- * License: https://github.com/bkaradzic/bx#license-bsd-2-clause
+ * Copyright 2010-2022 Branimir Karadzic. All rights reserved.
+ * License: https://github.com/bkaradzic/bx/blob/master/LICENSE
*/
#ifndef BX_FILEPATH_H_HEADER_GUARD
@@ -9,11 +9,11 @@
#include "error.h"
#include "string.h"
-BX_ERROR_RESULT(BX_ERROR_ACCESS, BX_MAKEFOURCC('b', 'x', 0, 0) );
-BX_ERROR_RESULT(BX_ERROR_NOT_DIRECTORY, BX_MAKEFOURCC('b', 'x', 0, 1) );
-
namespace bx
{
+ BX_ERROR_RESULT(kErrorAccess, BX_MAKEFOURCC('b', 'x', 1, 1) );
+ BX_ERROR_RESULT(kErrorNotDirectory, BX_MAKEFOURCC('b', 'x', 1, 2) );
+
constexpr int32_t kMaxFilePath = 1024;
/// Special predefined OS directories.
@@ -79,9 +79,13 @@ namespace bx
///
void join(const StringView& _str);
- /// Returns C string to file path.
+ /// Implicitly converts FilePath to StringView.
+ ///
+ operator StringView() const;
+
+ /// Returns zero-terminated C string pointer to file path.
///
- const char* get() const;
+ const char* getCPtr() const;
/// If path is `/abv/gd/555/333/pod.mac` returns `/abv/gd/555/333/`.
///
@@ -111,22 +115,6 @@ namespace bx
char m_filePath[kMaxFilePath];
};
- /// Creates a directory named `_filePath`.
- ///
- bool make(const FilePath& _filePath, Error* _err = NULL);
-
- /// Creates a directory named `_filePath` along with all necessary parents.
- ///
- bool makeAll(const FilePath& _filePath, Error* _err = NULL);
-
- /// Removes file or directory.
- ///
- bool remove(const FilePath& _filePath, Error* _err = NULL);
-
- /// Removes file or directory recursivelly.
- ///
- bool removeAll(const FilePath& _filePath, Error* _err = NULL);
-
} // namespace bx
#endif // BX_FILEPATH_H_HEADER_GUARD
diff --git a/3rdparty/bx/include/bx/float4x4_t.h b/3rdparty/bx/include/bx/float4x4_t.h
index 3250d929db3..54bc492aece 100644
--- a/3rdparty/bx/include/bx/float4x4_t.h
+++ b/3rdparty/bx/include/bx/float4x4_t.h
@@ -1,6 +1,6 @@
/*
- * Copyright 2010-2018 Branimir Karadzic. All rights reserved.
- * License: https://github.com/bkaradzic/bx#license-bsd-2-clause
+ * Copyright 2010-2022 Branimir Karadzic. All rights reserved.
+ * License: https://github.com/bkaradzic/bx/blob/master/LICENSE
*/
#ifndef BX_FLOAT4X4_H_HEADER_GUARD
@@ -10,25 +10,35 @@
namespace bx
{
- ///
+ /// 4x4 matrix.
BX_ALIGN_DECL_16(struct) float4x4_t
{
simd128_t col[4];
};
- ///
+ /// Multiplies vector `_a` with matrix `_b` ignoring W component of vector `_a`.
simd128_t simd_mul_xyz1(simd128_t _a, const float4x4_t* _b);
- ///
+ /// Multiplies vector `_a` with matrix `_b`.
simd128_t simd_mul(simd128_t _a, const float4x4_t* _b);
- ///
+ /// Multiplies two matrices.
void float4x4_mul(float4x4_t* _result, const float4x4_t* _a, const float4x4_t* _b);
- ///
+ /// Multiplies two 3x4 affine matrices (i.e. "model" or "world" matrices).
+ /// This function is a micro-optimized version of float4x4_mul() in the case
+ /// when the last row of the both input matrices are (0, 0, 0, 1).
+ void model4x4_mul(float4x4_t* _result, const float4x4_t* _a, const float4x4_t* _b);
+
+ /// Multiplies a 3x4 affine matrix with a general 4x4 matrix.
+ /// This function is a micro-optimized version of float4x4_mul() in the case
+ /// when the last row of the _model input matrix is (0, 0, 0, 1).
+ void model4x4_mul_viewproj4x4(float4x4_t* _result, const float4x4_t* _model, const float4x4_t* _viewProj);
+
+ /// Transpose of matrix.
void float4x4_transpose(float4x4_t* _result, const float4x4_t* _mtx);
- ///
+ /// Inverse of matrix.
void float4x4_inverse(float4x4_t* _result, const float4x4_t* _a);
} // namespace bx
diff --git a/3rdparty/bx/include/bx/handlealloc.h b/3rdparty/bx/include/bx/handlealloc.h
index 21b07ccca63..f7335e452ca 100644
--- a/3rdparty/bx/include/bx/handlealloc.h
+++ b/3rdparty/bx/include/bx/handlealloc.h
@@ -1,6 +1,6 @@
/*
- * Copyright 2010-2018 Branimir Karadzic. All rights reserved.
- * License: https://github.com/bkaradzic/bx#license-bsd-2-clause
+ * Copyright 2010-2022 Branimir Karadzic. All rights reserved.
+ * License: https://github.com/bkaradzic/bx/blob/master/LICENSE
*/
#ifndef BX_HANDLE_ALLOC_H_HEADER_GUARD
@@ -12,7 +12,7 @@
namespace bx
{
- static const uint16_t kInvalidHandle = UINT16_MAX;
+ constexpr uint16_t kInvalidHandle = UINT16_MAX;
///
class HandleAlloc
diff --git a/3rdparty/bx/include/bx/hash.h b/3rdparty/bx/include/bx/hash.h
index 9ced6947c9f..cb6fe18764f 100644
--- a/3rdparty/bx/include/bx/hash.h
+++ b/3rdparty/bx/include/bx/hash.h
@@ -1,6 +1,6 @@
/*
- * Copyright 2010-2018 Branimir Karadzic. All rights reserved.
- * License: https://github.com/bkaradzic/bx#license-bsd-2-clause
+ * Copyright 2010-2022 Branimir Karadzic. All rights reserved.
+ * License: https://github.com/bkaradzic/bx/blob/master/LICENSE
*/
#ifndef BX_HASH_H_HEADER_GUARD
@@ -11,95 +11,99 @@
namespace bx
{
- /// MurmurHash2 was written by Austin Appleby, and is placed in the public
- /// domain. The author hereby disclaims copyright to this source code.
- ///
- class HashMurmur2A
+ /// 32-bit Adler checksum hash.
+ class HashAdler32
{
public:
///
- void begin(uint32_t _seed = 0);
+ void begin();
+
+ ///
+ void add(const void* _data, int32_t _len);
+
+ ///
+ void add(const char* _data);
///
- void add(const void* _data, int _len);
+ void add(const StringView& _data);
///
template<typename Ty>
- void add(Ty _value);
+ void add(const Ty& _data);
///
uint32_t end();
private:
- ///
- void addAligned(const void* _data, int _len);
+ uint32_t m_a;
+ uint32_t m_b;
+ };
- ///
- void addUnaligned(const void* _data, int _len);
+ /// 32-bit cyclic redundancy checksum hash.
+ class HashCrc32
+ {
+ public:
+ enum Enum
+ {
+ Ieee, //!< 0xedb88320
+ Castagnoli, //!< 0x82f63b78
+ Koopman, //!< 0xeb31d82e
- ///
- static void readUnaligned(const void* _data, uint32_t& _out);
+ Count
+ };
///
- void mixTail(const uint8_t*& _data, int& _len);
+ void begin(Enum _type = Ieee);
- uint32_t m_hash;
- uint32_t m_tail;
- uint32_t m_count;
- uint32_t m_size;
- };
+ ///
+ void add(const void* _data, int32_t _len);
- ///
- class HashAdler32
- {
- public:
///
- void begin();
+ void add(const char* _data);
///
- void add(const void* _data, int _len);
+ void add(const StringView& _data);
///
template<typename Ty>
- void add(Ty _value);
+ void add(const Ty& _data);
///
uint32_t end();
private:
- uint32_t m_a;
- uint32_t m_b;
+ const uint32_t* m_table;
+ uint32_t m_hash;
};
- ///
- class HashCrc32
+ /// 32-bit multiply and rotate hash.
+ class HashMurmur2A
{
public:
- enum Enum
- {
- Ieee, //!< 0xedb88320
- Castagnoli, //!< 0x82f63b78
- Koopman, //!< 0xeb31d82e
+ ///
+ void begin(uint32_t _seed = 0);
- Count
- };
+ ///
+ void add(const void* _data, int32_t _len);
///
- void begin(Enum _type = Ieee);
+ void add(const char* _data);
///
- void add(const void* _data, int _len);
+ void add(const StringView& _data);
///
template<typename Ty>
- void add(Ty _value);
+ void add(const Ty& _data);
///
uint32_t end();
private:
- const uint32_t* m_table;
uint32_t m_hash;
+ uint32_t m_tail;
+ uint32_t m_count;
+ uint32_t m_size;
};
///
@@ -107,16 +111,16 @@ namespace bx
uint32_t hash(const void* _data, uint32_t _size);
///
- template<typename HashT, typename Ty>
- uint32_t hash(const Ty& _data);
+ template<typename HashT>
+ uint32_t hash(const char* _data);
///
template<typename HashT>
uint32_t hash(const StringView& _data);
///
- template<typename HashT>
- uint32_t hash(const char* _data);
+ template<typename HashT, typename Ty>
+ uint32_t hash(const Ty& _data);
} // namespace bx
diff --git a/3rdparty/bx/include/bx/inline/allocator.inl b/3rdparty/bx/include/bx/inline/allocator.inl
index 1ff5f647345..82788d1fedd 100644
--- a/3rdparty/bx/include/bx/inline/allocator.inl
+++ b/3rdparty/bx/include/bx/inline/allocator.inl
@@ -1,6 +1,6 @@
/*
- * Copyright 2010-2018 Branimir Karadzic. All rights reserved.
- * License: https://github.com/bkaradzic/bx#license-bsd-2-clause
+ * Copyright 2010-2022 Branimir Karadzic. All rights reserved.
+ * License: https://github.com/bkaradzic/bx/blob/master/LICENSE
*/
#ifndef BX_ALLOCATOR_H_HEADER_GUARD
@@ -22,20 +22,12 @@ namespace bx
{
}
- inline bool isAligned(const void* _ptr, size_t _align)
- {
- union { const void* ptr; uintptr_t addr; } un;
- un.ptr = _ptr;
- return 0 == (un.addr & (_align-1) );
- }
-
inline void* alignPtr(void* _ptr, size_t _extra, size_t _align)
{
union { void* ptr; uintptr_t addr; } un;
un.ptr = _ptr;
uintptr_t unaligned = un.addr + _extra; // space for header
- uintptr_t mask = _align-1;
- uintptr_t aligned = BX_ALIGN_MASK(unaligned, mask);
+ uintptr_t aligned = bx::alignUp(unaligned, int32_t(_align) );
un.addr = aligned;
return un.ptr;
}
@@ -57,7 +49,7 @@ namespace bx
inline void* alignedAlloc(AllocatorI* _allocator, size_t _size, size_t _align, const char* _file, uint32_t _line)
{
- const size_t align = max(_align, sizeof(uint32_t) );;
+ const size_t align = max(_align, sizeof(uint32_t) );
const size_t total = _size + align;
uint8_t* ptr = (uint8_t*)alloc(_allocator, total, 0, _file, _line);
uint8_t* aligned = (uint8_t*)alignPtr(ptr, sizeof(uint32_t), align);
diff --git a/3rdparty/bx/include/bx/inline/bounds.inl b/3rdparty/bx/include/bx/inline/bounds.inl
new file mode 100644
index 00000000000..1ecc59a8f18
--- /dev/null
+++ b/3rdparty/bx/include/bx/inline/bounds.inl
@@ -0,0 +1,257 @@
+/*
+ * Copyright 2011-2022 Branimir Karadzic. All rights reserved.
+ * License: https://github.com/bkaradzic/bgfx#license-bsd-2-clause
+ */
+
+#ifndef BX_BOUNDS_H_HEADER_GUARD
+# error "Must be included from bounds.h!"
+#endif // BX_BOUNDS_H_HEADER_GUARD
+
+namespace bx
+{
+ inline Interval::Interval(float _val)
+ : min(_val)
+ , max(_val)
+ {
+ }
+
+ inline Interval::Interval(float _min, float _max)
+ : min(_min)
+ , max(_max)
+ {
+ }
+
+ inline void Interval::set(float _val)
+ {
+ min = _val;
+ max = _val;
+ }
+
+ inline void Interval::setCenter(float _val)
+ {
+ const float extents = (max - min) * 0.5f;
+ min = _val - extents;
+ max = _val + extents;
+ }
+
+ inline void Interval::expand(float _val)
+ {
+ min = bx::min(min, _val);
+ max = bx::max(max, _val);
+ }
+
+ inline Vec3 getPointAt(const Ray& _ray, float _t)
+ {
+ return mad(_ray.dir, _t, _ray.pos);
+ }
+
+ inline Vec3 getPointAt(const Line& _line, float _t)
+ {
+ return mad(_line.dir, _t, _line.pos);
+ }
+
+ inline Vec3 getPointAt(const LineSegment& _line, float _t)
+ {
+ return lerp(_line.pos, _line.end, _t);
+ }
+
+ inline bool intersect(const Ray& _ray, const Plane& _plane, Hit* _hit)
+ {
+ return intersect(_ray, _plane, false, _hit);
+ }
+
+ inline bool overlap(const Interval& _interval, float _t)
+ {
+ return _t > _interval.min
+ && _t < _interval.max
+ ;
+ }
+
+ inline bool overlap(const Interval& _intervalA, const Interval& _intervalB)
+ {
+ return _intervalA.max > _intervalB.min
+ && _intervalB.max > _intervalA.min
+ ;
+ }
+
+ inline bool overlap(const Aabb& _aabb, const Sphere& _sphere)
+ {
+ return overlap(_sphere, _aabb);
+ }
+
+ inline bool overlap(const Aabb& _aabb, const Cylinder& _cylinder)
+ {
+ return overlap(_cylinder, _aabb);
+ }
+
+ inline bool overlap(const Capsule& _capsule, const Sphere& _sphere)
+ {
+ return overlap(_sphere, _capsule);
+ }
+
+ inline bool overlap(const Capsule& _capsule, const Aabb& _aabb)
+ {
+ return overlap(_aabb, _capsule);
+ }
+
+ inline bool overlap(const Capsule& _capsule, const Triangle& _triangle)
+ {
+ return overlap(_triangle, _capsule);
+ }
+
+ inline bool overlap(const Capsule& _capsule, const Cone& _cone)
+ {
+ return overlap(_cone, _capsule);
+ }
+
+ inline bool overlap(const Capsule& _capsule, const Cylinder& _cylinder)
+ {
+ return overlap(_cylinder, _capsule);
+ }
+
+ inline bool overlap(const Capsule& _capsule, const Disk& _disk)
+ {
+ return overlap(_disk, _capsule);
+ }
+
+ inline bool overlap(const Capsule& _capsule, const Obb& _obb)
+ {
+ return overlap(_obb, _capsule);
+ }
+
+ inline bool overlap(const Cone& _cone, const Sphere& _sphere)
+ {
+ return overlap(_sphere, _cone);
+ }
+
+ inline bool overlap(const Cone& _cone, const Aabb& _aabb)
+ {
+ return overlap(_aabb, _cone);
+ }
+
+ inline bool overlap(const Cone& _cone, const Plane& _plane)
+ {
+ return overlap(_plane, _cone);
+ }
+
+ inline bool overlap(const Cone& _cone, const Triangle& _triangle)
+ {
+ return overlap(_triangle, _cone);
+ }
+
+ inline bool overlap(const Cylinder& _cylinder, const Triangle& _triangle)
+ {
+ return overlap(_triangle, _cylinder);
+ }
+
+ inline bool overlap(const Cylinder& _cylinder, const Cone& _cone)
+ {
+ return overlap(_cone, _cylinder);
+ }
+
+ inline bool overlap(const Disk& _disk, const Sphere& _sphere)
+ {
+ return overlap(_sphere, _disk);
+ }
+
+ inline bool overlap(const Disk& _disk, const Aabb& _aabb)
+ {
+ return overlap(_aabb, _disk);
+ }
+
+ inline bool overlap(const Disk& _disk, const Triangle& _triangle)
+ {
+ return overlap(_triangle, _disk);
+ }
+
+ inline bool overlap(const Disk& _disk, const Cylinder& _cylinder)
+ {
+ return overlap(_cylinder, _disk);
+ }
+
+ inline bool overlap(const Disk& _disk, const Cone& _cone)
+ {
+ return overlap(_cone, _disk);
+ }
+
+ inline bool overlap(const Obb& _obb, const Sphere& _sphere)
+ {
+ return overlap(_sphere, _obb);
+ }
+
+ inline bool overlap(const Obb& _obb, const Aabb& _aabb)
+ {
+ return overlap(_aabb, _obb);
+ }
+
+ inline bool overlap(const Obb& _obb, const Triangle& _triangle)
+ {
+ return overlap(_triangle, _obb);
+ }
+
+ inline bool overlap(const Obb& _obb, const Cylinder& _cylinder)
+ {
+ return overlap(_cylinder, _obb);
+ }
+
+ inline bool overlap(const Obb& _obb, const Cone& _cone)
+ {
+ return overlap(_cone, _obb);
+ }
+
+ inline bool overlap(const Obb& _obb, const Disk& _disk)
+ {
+ return overlap(_disk, _obb);
+ }
+
+ inline bool overlap(const Plane& _plane, const Sphere& _sphere)
+ {
+ return overlap(_sphere, _plane);
+ }
+
+ inline bool overlap(const Plane& _plane, const Aabb& _aabb)
+ {
+ return overlap(_aabb, _plane);
+ }
+
+ inline bool overlap(const Plane& _plane, const Triangle& _triangle)
+ {
+ return overlap(_triangle, _plane);
+ }
+
+ inline bool overlap(const Plane& _plane, const Cylinder& _cylinder)
+ {
+ return overlap(_cylinder, _plane);
+ }
+
+ inline bool overlap(const Plane& _plane, const Capsule& _capsule)
+ {
+ return overlap(_capsule, _plane);
+ }
+
+ inline bool overlap(const Plane& _plane, const Disk& _disk)
+ {
+ return overlap(_disk, _plane);
+ }
+
+ inline bool overlap(const Plane& _plane, const Obb& _obb)
+ {
+ return overlap(_obb, _plane);
+ }
+
+ inline bool overlap(const Sphere& _sphere, const Cylinder& _cylinder)
+ {
+ return overlap(_cylinder, _sphere);
+ }
+
+ inline bool overlap(const Triangle& _triangle, const Sphere& _sphere)
+ {
+ return overlap(_sphere, _triangle);
+ }
+
+ inline bool overlap(const Triangle& _triangle, const Aabb& _aabb)
+ {
+ return overlap(_aabb, _triangle);
+ }
+
+} // namespace bx
diff --git a/3rdparty/bx/include/bx/inline/bx.inl b/3rdparty/bx/include/bx/inline/bx.inl
index c17649a5d69..3c651854281 100644
--- a/3rdparty/bx/include/bx/inline/bx.inl
+++ b/3rdparty/bx/include/bx/inline/bx.inl
@@ -1,6 +1,6 @@
/*
- * Copyright 2010-2018 Branimir Karadzic. All rights reserved.
- * License: https://github.com/bkaradzic/bx#license-bsd-2-clause
+ * Copyright 2010-2022 Branimir Karadzic. All rights reserved.
+ * License: https://github.com/bkaradzic/bx/blob/master/LICENSE
*/
#ifndef BX_H_HEADER_GUARD
@@ -12,70 +12,131 @@ namespace bx
// Reference(S):
// - https://web.archive.org/web/20181115035420/http://cnicholson.net/2011/01/stupid-c-tricks-a-better-sizeof_array/
//
- template<typename Ty, size_t Num>
- char(&CountOfRequireArrayArgumentT(const Ty(&)[Num]))[Num];
+ template<typename Ty, size_t NumT>
+ char (&CountOfRequireArrayArgumentT(const Ty (&)[NumT]) )[NumT];
- template<bool>
- inline constexpr bool isEnabled()
+ template<bool B>
+ struct isEnabled
{
- return true;
+ // Template for avoiding MSVC: C4127: conditional expression is constant
+ static constexpr bool value = B;
+ };
+
+ inline constexpr bool ignoreC4127(bool _x)
+ {
+ return _x;
}
- template<class Ty>
- inline constexpr bool isTriviallyCopyable()
+ template<typename Ty>
+ inline Ty* addressOf(Ty& _a)
{
- return __is_trivially_copyable(Ty);
+ return reinterpret_cast<Ty*>(
+ &const_cast<char&>(
+ reinterpret_cast<const volatile char&>(_a)
+ )
+ );
}
- template<>
- inline constexpr bool isEnabled<false>()
+ template<typename Ty>
+ inline const Ty* addressOf(const Ty& _a)
{
- return false;
+ return reinterpret_cast<const Ty*>(
+ &const_cast<char&>(
+ reinterpret_cast<const volatile char&>(_a)
+ )
+ );
}
- inline constexpr bool ignoreC4127(bool _x)
+ template<typename Ty>
+ inline Ty* addressOf(void* _ptr, ptrdiff_t _offsetInBytes)
{
- return _x;
+ return (Ty*)( (uint8_t*)_ptr + _offsetInBytes);
}
template<typename Ty>
- inline void swap(Ty& _a, Ty& _b)
+ inline const Ty* addressOf(const void* _ptr, ptrdiff_t _offsetInBytes)
{
- Ty tmp = _a; _a = _b; _b = tmp;
+ return (const Ty*)( (const uint8_t*)_ptr + _offsetInBytes);
}
template<typename Ty>
- inline constexpr Ty min(const Ty& _a, const Ty& _b)
+ inline void swap(Ty& _a, Ty& _b)
{
- return _a < _b ? _a : _b;
+ Ty tmp = move(_a); _a = move(_b); _b = move(tmp);
}
template<typename Ty>
- inline constexpr Ty max(const Ty& _a, const Ty& _b)
+ struct LimitsT<Ty, true>
{
- return _a > _b ? _a : _b;
+ static constexpr Ty max = ( ( (Ty(1) << ( (sizeof(Ty) * 8) - 2) ) - Ty(1) ) << 1) | Ty(1);
+ static constexpr Ty min = -max - Ty(1);
+ };
+
+ template<typename Ty>
+ struct LimitsT<Ty, false>
+ {
+ static constexpr Ty min = 0;
+ static constexpr Ty max = Ty(-1);
+ };
+
+ template<>
+ struct LimitsT<float, true>
+ {
+ static constexpr float min = -kFloatLargest;
+ static constexpr float max = kFloatLargest;
+ };
+
+ template<>
+ struct LimitsT<double, true>
+ {
+ static constexpr double min = -kDoubleLargest;
+ static constexpr double max = kDoubleLargest;
+ };
+
+ template<typename Ty>
+ inline constexpr Ty max()
+ {
+ return bx::LimitsT<Ty>::max;
}
template<typename Ty>
- inline constexpr Ty min(const Ty& _a, const Ty& _b, const Ty& _c)
+ inline constexpr Ty min()
{
- return min(min(_a, _b), _c);
+ return bx::LimitsT<Ty>::min;
}
template<typename Ty>
- inline constexpr Ty max(const Ty& _a, const Ty& _b, const Ty& _c)
+ inline constexpr Ty min(const Ty& _a, const TypeIdentityType<Ty>& _b)
{
- return max(max(_a, _b), _c);
+ return _a < _b ? _a : _b;
}
template<typename Ty>
- inline constexpr Ty mid(const Ty& _a, const Ty& _b, const Ty& _c)
+ inline constexpr Ty max(const Ty& _a, const TypeIdentityType<Ty>& _b)
+ {
+ return _a > _b ? _a : _b;
+ }
+
+ template<typename Ty, typename... Args>
+ inline constexpr Ty min(const Ty& _a, const TypeIdentityType<Ty>& _b, const Args&... _args)
+ {
+ return min(min(_a, _b), _args...);
+ }
+
+ template<typename Ty, typename... Args>
+ inline constexpr Ty max(const Ty& _a, const TypeIdentityType<Ty>& _b, const Args&... _args)
+ {
+ return max(max(_a, _b), _args...);
+ }
+
+ template<typename Ty, typename... Args>
+ inline constexpr Ty mid(const Ty& _a, const TypeIdentityType<Ty>& _b, const Args&... _args)
{
- return max(min(_a, _b), min(max(_a, _b), _c) );
+ return max(min(_a, _b), min(max(_a, _b), _args...) );
}
template<typename Ty>
- inline constexpr Ty clamp(const Ty& _a, const Ty& _min, const Ty& _max)
+ inline constexpr Ty clamp(const Ty& _a, const TypeIdentityType<Ty>& _min, const TypeIdentityType<Ty>& _max)
{
return max(min(_a, _max), _min);
}
diff --git a/3rdparty/bx/include/bx/inline/cpu.inl b/3rdparty/bx/include/bx/inline/cpu.inl
index 3ff2a231fd3..756aa175682 100644
--- a/3rdparty/bx/include/bx/inline/cpu.inl
+++ b/3rdparty/bx/include/bx/inline/cpu.inl
@@ -1,6 +1,6 @@
/*
- * Copyright 2010-2018 Branimir Karadzic. All rights reserved.
- * License: https://github.com/bkaradzic/bx#license-bsd-2-clause
+ * Copyright 2010-2022 Branimir Karadzic. All rights reserved.
+ * License: https://github.com/bkaradzic/bx/blob/master/LICENSE
*/
#ifndef BX_CPU_H_HEADER_GUARD
@@ -8,11 +8,16 @@
#endif // BX_CPU_H_HEADER_GUARD
#if BX_COMPILER_MSVC
-# if BX_PLATFORM_WINRT
+# if BX_PLATFORM_WINRT || (BX_PLATFORM_WINDOWS && !BX_CPU_X86)
+# ifndef WIN32_LEAN_AND_MEAN
+# define WIN32_LEAN_AND_MEAN
+# endif // WIN32_LEAN_AND_MEAN
# include <windows.h>
-# endif // BX_PLATFORM_WINRT
+# endif // BX_PLATFORM_WINRT || (BX_PLATFORM_WINDOWS && !BX_CPU_X86)
-# include <emmintrin.h> // _mm_fence
+# if BX_CPU_X86
+# include <emmintrin.h> // _mm_fence
+# endif // BX_CPU_X86
extern "C" void _ReadBarrier();
# pragma intrinsic(_ReadBarrier)
@@ -66,7 +71,7 @@ namespace bx
_ReadBarrier();
#else
asm volatile("":::"memory");
-#endif // BX_COMPILER
+#endif // BX_COMPILER_*
}
inline void writeBarrier()
@@ -75,7 +80,7 @@ namespace bx
_WriteBarrier();
#else
asm volatile("":::"memory");
-#endif // BX_COMPILER
+#endif // BX_COMPILER_*
}
inline void readWriteBarrier()
@@ -84,18 +89,20 @@ namespace bx
_ReadWriteBarrier();
#else
asm volatile("":::"memory");
-#endif // BX_COMPILER
+#endif // BX_COMPILER_*
}
inline void memoryBarrier()
{
-#if BX_PLATFORM_WINRT
- MemoryBarrier();
-#elif BX_COMPILER_MSVC
+#if BX_COMPILER_MSVC
+# if BX_CPU_X86
_mm_mfence();
+# else
+ MemoryBarrier();
+# endif // BX_CPU_X86
#else
__sync_synchronize();
-#endif // BX_COMPILER
+#endif // BX_COMPILER_MSVC
}
template<>
@@ -105,7 +112,7 @@ namespace bx
return int32_t(_InterlockedCompareExchange( (volatile long*)(_ptr), long(_new), long(_old) ) );
#else
return __sync_val_compare_and_swap( (volatile int32_t*)_ptr, _old, _new);
-#endif // BX_COMPILER
+#endif // BX_COMPILER_*
}
template<>
@@ -115,7 +122,7 @@ namespace bx
return uint32_t(_InterlockedCompareExchange( (volatile long*)(_ptr), long(_new), long(_old) ) );
#else
return __sync_val_compare_and_swap( (volatile int32_t*)_ptr, _old, _new);
-#endif // BX_COMPILER
+#endif // BX_COMPILER_*
}
template<>
@@ -125,7 +132,7 @@ namespace bx
return _InterlockedCompareExchange64(_ptr, _new, _old);
#else
return __sync_val_compare_and_swap( (volatile int64_t*)_ptr, _old, _new);
-#endif // BX_COMPILER
+#endif // BX_COMPILER_*
}
template<>
@@ -135,7 +142,7 @@ namespace bx
return uint64_t(_InterlockedCompareExchange64( (volatile int64_t*)(_ptr), int64_t(_new), int64_t(_old) ) );
#else
return __sync_val_compare_and_swap( (volatile int64_t*)_ptr, _old, _new);
-#endif // BX_COMPILER
+#endif // BX_COMPILER_*
}
template<>
@@ -145,7 +152,7 @@ namespace bx
return _InterlockedExchangeAdd( (volatile long*)_ptr, _add);
#else
return __sync_fetch_and_add(_ptr, _add);
-#endif // BX_COMPILER_
+#endif // BX_COMPILER_*
}
template<>
@@ -174,7 +181,7 @@ namespace bx
# endif
#else
return __sync_fetch_and_add(_ptr, _add);
-#endif // BX_COMPILER_
+#endif // BX_COMPILER_*
}
template<>
@@ -190,7 +197,7 @@ namespace bx
return atomicFetchAndAdd(_ptr, _add) + _add;
#else
return __sync_add_and_fetch(_ptr, _add);
-#endif // BX_COMPILER_
+#endif // BX_COMPILER_*
}
template<>
@@ -200,7 +207,7 @@ namespace bx
return atomicFetchAndAdd(_ptr, _add) + _add;
#else
return __sync_add_and_fetch(_ptr, _add);
-#endif // BX_COMPILER_
+#endif // BX_COMPILER_*
}
template<>
@@ -222,7 +229,7 @@ namespace bx
return atomicFetchAndAdd(_ptr, -_sub);
#else
return __sync_fetch_and_sub(_ptr, _sub);
-#endif // BX_COMPILER_
+#endif // BX_COMPILER_*
}
template<>
@@ -232,7 +239,7 @@ namespace bx
return atomicFetchAndAdd(_ptr, -_sub);
#else
return __sync_fetch_and_sub(_ptr, _sub);
-#endif // BX_COMPILER_
+#endif // BX_COMPILER_*
}
template<>
@@ -254,7 +261,7 @@ namespace bx
return atomicFetchAndAdd(_ptr, -_sub) - _sub;
#else
return __sync_sub_and_fetch(_ptr, _sub);
-#endif // BX_COMPILER_
+#endif // BX_COMPILER_*
}
template<>
@@ -264,7 +271,7 @@ namespace bx
return atomicFetchAndAdd(_ptr, -_sub) - _sub;
#else
return __sync_sub_and_fetch(_ptr, _sub);
-#endif // BX_COMPILER_
+#endif // BX_COMPILER_*
}
template<>
@@ -345,7 +352,7 @@ namespace bx
return _InterlockedExchangePointer(_ptr, _new);
#else
return __sync_lock_test_and_set(_ptr, _new);
-#endif // BX_COMPILER
+#endif // BX_COMPILER_*
}
} // namespace bx
diff --git a/3rdparty/bx/include/bx/inline/easing.inl b/3rdparty/bx/include/bx/inline/easing.inl
index 3cdab9a77cb..c484337a776 100644
--- a/3rdparty/bx/include/bx/inline/easing.inl
+++ b/3rdparty/bx/include/bx/inline/easing.inl
@@ -1,6 +1,6 @@
/*
- * Copyright 2011-2018 Branimir Karadzic. All rights reserved.
- * License: https://github.com/bkaradzic/bx#license-bsd-2-clause
+ * Copyright 2011-2022 Branimir Karadzic. All rights reserved.
+ * License: https://github.com/bkaradzic/bx/blob/master/LICENSE
*/
#ifndef BX_EASING_H_HEADER_GUARD
diff --git a/3rdparty/bx/include/bx/inline/endian.inl b/3rdparty/bx/include/bx/inline/endian.inl
index 332e2b6102a..eef5e08e7c2 100644
--- a/3rdparty/bx/include/bx/inline/endian.inl
+++ b/3rdparty/bx/include/bx/inline/endian.inl
@@ -1,6 +1,6 @@
/*
- * Copyright 2010-2018 Branimir Karadzic. All rights reserved.
- * License: https://github.com/bkaradzic/bx#license-bsd-2-clause
+ * Copyright 2010-2022 Branimir Karadzic. All rights reserved.
+ * License: https://github.com/bkaradzic/bx/blob/master/LICENSE
*/
#ifndef BX_ENDIAN_H_HEADER_GUARD
@@ -46,7 +46,7 @@ namespace bx
}
template <typename Ty>
- inline Ty toLittleEndian(const Ty _in)
+ inline Ty toLittleEndian(Ty _in)
{
#if BX_CPU_ENDIAN_BIG
return endianSwap(_in);
@@ -56,7 +56,7 @@ namespace bx
}
template <typename Ty>
- inline Ty toBigEndian(const Ty _in)
+ inline Ty toBigEndian(Ty _in)
{
#if BX_CPU_ENDIAN_LITTLE
return endianSwap(_in);
@@ -66,7 +66,7 @@ namespace bx
}
template <typename Ty>
- inline Ty toHostEndian(const Ty _in, bool _fromLittleEndian)
+ inline Ty toHostEndian(Ty _in, bool _fromLittleEndian)
{
#if BX_CPU_ENDIAN_LITTLE
return _fromLittleEndian ? _in : endianSwap(_in);
diff --git a/3rdparty/bx/include/bx/inline/error.inl b/3rdparty/bx/include/bx/inline/error.inl
index af5c31a1991..1379a6cb950 100644
--- a/3rdparty/bx/include/bx/inline/error.inl
+++ b/3rdparty/bx/include/bx/inline/error.inl
@@ -1,12 +1,14 @@
/*
- * Copyright 2010-2018 Branimir Karadzic. All rights reserved.
- * License: https://github.com/bkaradzic/bx#license-bsd-2-clause
+ * Copyright 2010-2022 Branimir Karadzic. All rights reserved.
+ * License: https://github.com/bkaradzic/bx/blob/master/LICENSE
*/
#ifndef BX_ERROR_H_HEADER_GUARD
# error "Must be included from bx/error!"
#endif // BX_ERROR_H_HEADER_GUARD
+#include <bx/debug.h>
+
namespace bx
{
inline Error::Error()
@@ -22,7 +24,7 @@ namespace bx
inline void Error::setError(ErrorResult _errorResult, const StringView& _msg)
{
- BX_CHECK(0 != _errorResult.code, "Invalid ErrorResult passed to setError!");
+ BX_ASSERT(0 != _errorResult.code, "Invalid ErrorResult passed to setError!");
if (!isOk() )
{
@@ -59,15 +61,72 @@ namespace bx
return _rhs.code != m_code;
}
- inline ErrorScope::ErrorScope(Error* _err)
+ inline ErrorIgnore::operator Error*()
+ {
+ return this;
+ }
+
+ inline ErrorAssert::~ErrorAssert()
+ {
+ BX_ASSERT(isOk(), "Error: 0x%08x `%S`"
+ , get().code
+ , &getMessage()
+ );
+ }
+
+ inline ErrorFatal::operator Error*()
+ {
+ return this;
+ }
+
+ inline ErrorFatal::~ErrorFatal()
+ {
+ if (!isOk() )
+ {
+ printf("Error: 0x%08x `%S`"
+ , get().code
+ , &getMessage()
+ );
+
+ exit(kExitFailure);
+ }
+ }
+
+ inline ErrorAssert::operator Error*()
+ {
+ return this;
+ }
+
+ inline ErrorScope::ErrorScope(Error* _err, const StringView& _name)
: m_err(_err)
+ , m_name(_name)
{
- BX_CHECK(NULL != _err, "_err can't be NULL");
+ BX_UNUSED(m_err);
+ BX_ASSERT(NULL != _err, "_err can't be NULL");
}
inline ErrorScope::~ErrorScope()
{
- BX_CHECK(m_err->isOk(), "Error: %d", m_err->get().code);
+ if (m_name.isEmpty() )
+ {
+ BX_ASSERT(m_err->isOk(), "Error: 0x%08x `%S`"
+ , m_err->get().code
+ , &m_err->getMessage()
+ );
+ }
+ else
+ {
+ BX_ASSERT(m_err->isOk(), "Error: %S - 0x%08x `%S`"
+ , &m_name
+ , m_err->get().code
+ , &m_err->getMessage()
+ );
+ }
+ }
+
+ inline const StringView& ErrorScope::getName() const
+ {
+ return m_name;
}
} // namespace bx
diff --git a/3rdparty/bx/include/bx/inline/float4x4_t.inl b/3rdparty/bx/include/bx/inline/float4x4_t.inl
index 222c111c361..3860d033ecb 100644
--- a/3rdparty/bx/include/bx/inline/float4x4_t.inl
+++ b/3rdparty/bx/include/bx/inline/float4x4_t.inl
@@ -1,6 +1,6 @@
/*
- * Copyright 2010-2018 Branimir Karadzic. All rights reserved.
- * License: https://github.com/bkaradzic/bx#license-bsd-2-clause
+ * Copyright 2010-2022 Branimir Karadzic. All rights reserved.
+ * License: https://github.com/bkaradzic/bx/blob/master/LICENSE
*/
#ifndef BX_FLOAT4X4_H_HEADER_GUARD
@@ -40,10 +40,99 @@ namespace bx
BX_SIMD_INLINE void float4x4_mul(float4x4_t* _result, const float4x4_t* _a, const float4x4_t* _b)
{
+#if BX_CONFIG_SUPPORTS_SIMD
_result->col[0] = simd_mul(_a->col[0], _b);
_result->col[1] = simd_mul(_a->col[1], _b);
_result->col[2] = simd_mul(_a->col[2], _b);
_result->col[3] = simd_mul(_a->col[3], _b);
+#else
+ const float* aa = (const float*)_a;
+ const float* bb = (const float*)_b;
+ float *rr = (float*)_result;
+
+ rr[ 0] = aa[ 0]*bb[ 0] + aa[ 1]*bb[ 4] + aa[ 2]*bb[ 8] + aa[ 3]*bb[12];
+ rr[ 1] = aa[ 0]*bb[ 1] + aa[ 1]*bb[ 5] + aa[ 2]*bb[ 9] + aa[ 3]*bb[13];
+ rr[ 2] = aa[ 0]*bb[ 2] + aa[ 1]*bb[ 6] + aa[ 2]*bb[10] + aa[ 3]*bb[14];
+ rr[ 3] = aa[ 0]*bb[ 3] + aa[ 1]*bb[ 7] + aa[ 2]*bb[11] + aa[ 3]*bb[15];
+
+ rr[ 4] = aa[ 4]*bb[ 0] + aa[ 5]*bb[ 4] + aa[ 6]*bb[ 8] + aa[ 7]*bb[12];
+ rr[ 5] = aa[ 4]*bb[ 1] + aa[ 5]*bb[ 5] + aa[ 6]*bb[ 9] + aa[ 7]*bb[13];
+ rr[ 6] = aa[ 4]*bb[ 2] + aa[ 5]*bb[ 6] + aa[ 6]*bb[10] + aa[ 7]*bb[14];
+ rr[ 7] = aa[ 4]*bb[ 3] + aa[ 5]*bb[ 7] + aa[ 6]*bb[11] + aa[ 7]*bb[15];
+
+ rr[ 8] = aa[ 8]*bb[ 0] + aa[ 9]*bb[ 4] + aa[10]*bb[ 8] + aa[11]*bb[12];
+ rr[ 9] = aa[ 8]*bb[ 1] + aa[ 9]*bb[ 5] + aa[10]*bb[ 9] + aa[11]*bb[13];
+ rr[10] = aa[ 8]*bb[ 2] + aa[ 9]*bb[ 6] + aa[10]*bb[10] + aa[11]*bb[14];
+ rr[11] = aa[ 8]*bb[ 3] + aa[ 9]*bb[ 7] + aa[10]*bb[11] + aa[11]*bb[15];
+
+ rr[12] = aa[12]*bb[ 0] + aa[13]*bb[ 4] + aa[14]*bb[ 8] + aa[15]*bb[12];
+ rr[13] = aa[12]*bb[ 1] + aa[13]*bb[ 5] + aa[14]*bb[ 9] + aa[15]*bb[13];
+ rr[14] = aa[12]*bb[ 2] + aa[13]*bb[ 6] + aa[14]*bb[10] + aa[15]*bb[14];
+ rr[15] = aa[12]*bb[ 3] + aa[13]*bb[ 7] + aa[14]*bb[11] + aa[15]*bb[15];
+#endif // BX_CONFIG_SUPPORTS_SIMD
+ }
+
+ BX_SIMD_INLINE void model4x4_mul(float4x4_t* _result, const float4x4_t* _a, const float4x4_t* _b)
+ {
+#if BX_CONFIG_SUPPORTS_SIMD
+ // With SIMD faster to do the general 4x4 form:
+ float4x4_mul(_result, _a, _b);
+#else
+ const float* aa = (const float*)_a; // aa[ 3] == aa[ 7] == aa[11] == 0.0f, aa[15] = 1.0f
+ const float* bb = (const float*)_b; // bb[ 3] == bb[ 7] == bb[11] == 0.0f, bb[15] = 1.0f
+ float *rr = (float*)_result;
+
+ rr[ 0] = aa[ 0]*bb[ 0] + aa[ 1]*bb[ 4] + aa[ 2]*bb[ 8];
+ rr[ 1] = aa[ 0]*bb[ 1] + aa[ 1]*bb[ 5] + aa[ 2]*bb[ 9];
+ rr[ 2] = aa[ 0]*bb[ 2] + aa[ 1]*bb[ 6] + aa[ 2]*bb[10];
+ rr[ 3] = 0.0f;
+
+ rr[ 4] = aa[ 4]*bb[ 0] + aa[ 5]*bb[ 4] + aa[ 6]*bb[ 8];
+ rr[ 5] = aa[ 4]*bb[ 1] + aa[ 5]*bb[ 5] + aa[ 6]*bb[ 9];
+ rr[ 6] = aa[ 4]*bb[ 2] + aa[ 5]*bb[ 6] + aa[ 6]*bb[10];
+ rr[ 7] = 0.0f;
+
+ rr[ 8] = aa[ 8]*bb[ 0] + aa[ 9]*bb[ 4] + aa[10]*bb[ 8];
+ rr[ 9] = aa[ 8]*bb[ 1] + aa[ 9]*bb[ 5] + aa[10]*bb[ 9];
+ rr[10] = aa[ 8]*bb[ 2] + aa[ 9]*bb[ 6] + aa[10]*bb[10];
+ rr[11] = 0.0f;
+
+ rr[12] = aa[12]*bb[ 0] + aa[13]*bb[ 4] + aa[14]*bb[ 8] + bb[12];
+ rr[13] = aa[12]*bb[ 1] + aa[13]*bb[ 5] + aa[14]*bb[ 9] + bb[13];
+ rr[14] = aa[12]*bb[ 2] + aa[13]*bb[ 6] + aa[14]*bb[10] + bb[14];
+ rr[15] = 1.0f;
+#endif // BX_CONFIG_SUPPORTS_SIMD
+ }
+
+ BX_SIMD_INLINE void model4x4_mul_viewproj4x4(float4x4_t* _result, const float4x4_t* _model, const float4x4_t* _viewProj)
+ {
+#if BX_CONFIG_SUPPORTS_SIMD
+ // With SIMD faster to do the general 4x4 form:
+ float4x4_mul(_result, _model, _viewProj);
+#else
+ const float* aa = (const float*)_model; // aa[ 3] == aa[ 7] == aa[11] == 0.0f, aa[15] == 1.0f
+ const float* bb = (const float*)_viewProj;
+ float *rr = (float*)_result;
+ rr[ 0] = aa[ 0]*bb[ 0] + aa[ 1]*bb[ 4] + aa[ 2]*bb[ 8];
+ rr[ 1] = aa[ 0]*bb[ 1] + aa[ 1]*bb[ 5] + aa[ 2]*bb[ 9];
+ rr[ 2] = aa[ 0]*bb[ 2] + aa[ 1]*bb[ 6] + aa[ 2]*bb[10];
+ rr[ 3] = aa[ 0]*bb[ 3] + aa[ 1]*bb[ 7] + aa[ 2]*bb[11];
+
+ rr[ 4] = aa[ 4]*bb[ 0] + aa[ 5]*bb[ 4] + aa[ 6]*bb[ 8];
+ rr[ 5] = aa[ 4]*bb[ 1] + aa[ 5]*bb[ 5] + aa[ 6]*bb[ 9];
+ rr[ 6] = aa[ 4]*bb[ 2] + aa[ 5]*bb[ 6] + aa[ 6]*bb[10];
+ rr[ 7] = aa[ 4]*bb[ 3] + aa[ 5]*bb[ 7] + aa[ 6]*bb[11];
+
+ rr[ 8] = aa[ 8]*bb[ 0] + aa[ 9]*bb[ 4] + aa[10]*bb[ 8];
+ rr[ 9] = aa[ 8]*bb[ 1] + aa[ 9]*bb[ 5] + aa[10]*bb[ 9];
+ rr[10] = aa[ 8]*bb[ 2] + aa[ 9]*bb[ 6] + aa[10]*bb[10];
+ rr[11] = aa[ 8]*bb[ 3] + aa[ 9]*bb[ 7] + aa[10]*bb[11];
+
+ rr[12] = aa[12]*bb[ 0] + aa[13]*bb[ 4] + aa[14]*bb[ 8] + bb[12];
+ rr[13] = aa[12]*bb[ 1] + aa[13]*bb[ 5] + aa[14]*bb[ 9] + bb[13];
+ rr[14] = aa[12]*bb[ 2] + aa[13]*bb[ 6] + aa[14]*bb[10] + bb[14];
+ rr[15] = aa[12]*bb[ 3] + aa[13]*bb[ 7] + aa[14]*bb[11] + bb[15];
+#endif // BX_CONFIG_SUPPORTS_SIMD
}
BX_SIMD_FORCE_INLINE void float4x4_transpose(float4x4_t* _result, const float4x4_t* _mtx)
diff --git a/3rdparty/bx/include/bx/inline/handlealloc.inl b/3rdparty/bx/include/bx/inline/handlealloc.inl
index 3bb364b66b3..7051692587b 100644
--- a/3rdparty/bx/include/bx/inline/handlealloc.inl
+++ b/3rdparty/bx/include/bx/inline/handlealloc.inl
@@ -1,6 +1,6 @@
/*
- * Copyright 2010-2018 Branimir Karadzic. All rights reserved.
- * License: https://github.com/bkaradzic/bx#license-bsd-2-clause
+ * Copyright 2010-2022 Branimir Karadzic. All rights reserved.
+ * License: https://github.com/bkaradzic/bx/blob/master/LICENSE
*/
#ifndef BX_HANDLE_ALLOC_H_HEADER_GUARD
@@ -186,7 +186,7 @@ namespace bx
template <uint16_t MaxHandlesT>
inline uint16_t HandleListT<MaxHandlesT>::getNext(uint16_t _handle) const
{
- BX_CHECK(isValid(_handle), "Invalid handle %d!", _handle);
+ BX_ASSERT(isValid(_handle), "Invalid handle %d!", _handle);
const Link& curr = m_links[_handle];
return curr.m_next;
}
@@ -194,7 +194,7 @@ namespace bx
template <uint16_t MaxHandlesT>
inline uint16_t HandleListT<MaxHandlesT>::getPrev(uint16_t _handle) const
{
- BX_CHECK(isValid(_handle), "Invalid handle %d!", _handle);
+ BX_ASSERT(isValid(_handle), "Invalid handle %d!", _handle);
const Link& curr = m_links[_handle];
return curr.m_prev;
}
@@ -202,7 +202,7 @@ namespace bx
template <uint16_t MaxHandlesT>
inline void HandleListT<MaxHandlesT>::remove(uint16_t _handle)
{
- BX_CHECK(isValid(_handle), "Invalid handle %d!", _handle);
+ BX_ASSERT(isValid(_handle), "Invalid handle %d!", _handle);
Link& curr = m_links[_handle];
if (kInvalidHandle != curr.m_prev)
@@ -358,7 +358,7 @@ namespace bx
template <uint16_t MaxHandlesT>
inline void HandleAllocLruT<MaxHandlesT>::free(uint16_t _handle)
{
- BX_CHECK(isValid(_handle), "Invalid handle %d!", _handle);
+ BX_ASSERT(isValid(_handle), "Invalid handle %d!", _handle);
m_list.remove(_handle);
m_alloc.free(_handle);
}
@@ -366,7 +366,7 @@ namespace bx
template <uint16_t MaxHandlesT>
inline void HandleAllocLruT<MaxHandlesT>::touch(uint16_t _handle)
{
- BX_CHECK(isValid(_handle), "Invalid handle %d!", _handle);
+ BX_ASSERT(isValid(_handle), "Invalid handle %d!", _handle);
m_list.remove(_handle);
m_list.pushFront(_handle);
}
diff --git a/3rdparty/bx/include/bx/inline/hash.inl b/3rdparty/bx/include/bx/inline/hash.inl
index 18bee143c70..bad8ba0b5e1 100644
--- a/3rdparty/bx/include/bx/inline/hash.inl
+++ b/3rdparty/bx/include/bx/inline/hash.inl
@@ -1,6 +1,6 @@
/*
- * Copyright 2010-2018 Branimir Karadzic. All rights reserved.
- * License: https://github.com/bkaradzic/bx#license-bsd-2-clause
+ * Copyright 2010-2022 Branimir Karadzic. All rights reserved.
+ * License: https://github.com/bkaradzic/bx/blob/master/LICENSE
*/
#ifndef BX_HASH_H_HEADER_GUARD
@@ -9,171 +9,89 @@
namespace bx
{
-#define MURMUR_M 0x5bd1e995
-#define MURMUR_R 24
-#define mmix(_h, _k) { _k *= MURMUR_M; _k ^= _k >> MURMUR_R; _k *= MURMUR_M; _h *= MURMUR_M; _h ^= _k; }
-
- inline void HashMurmur2A::begin(uint32_t _seed)
+ inline void HashAdler32::begin()
{
- m_hash = _seed;
- m_tail = 0;
- m_count = 0;
- m_size = 0;
+ m_a = 1;
+ m_b = 0;
}
- inline void HashMurmur2A::add(const void* _data, int _len)
+ inline void HashAdler32::add(const void* _data, int32_t _len)
{
- if (BX_UNLIKELY(!isAligned(_data, 4) ) )
- {
- addUnaligned(_data, _len);
- return;
- }
-
- addAligned(_data, _len);
- }
+ constexpr uint32_t kModAdler = 65521;
- inline void HashMurmur2A::addAligned(const void* _data, int _len)
- {
const uint8_t* data = (const uint8_t*)_data;
- m_size += _len;
-
- mixTail(data, _len);
-
- while(_len >= 4)
+ for (; _len != 0; --_len)
{
- uint32_t kk = *(uint32_t*)data;
-
- mmix(m_hash, kk);
-
- data += 4;
- _len -= 4;
+ m_a = (m_a + *data++) % kModAdler;
+ m_b = (m_b + m_a ) % kModAdler;
}
-
- mixTail(data, _len);
}
- inline void HashMurmur2A::addUnaligned(const void* _data, int _len)
+ inline void HashAdler32::add(const char* _data)
{
- const uint8_t* data = (const uint8_t*)_data;
- m_size += _len;
-
- mixTail(data, _len);
-
- while(_len >= 4)
- {
- uint32_t kk;
- readUnaligned(data, kk);
-
- mmix(m_hash, kk);
-
- data += 4;
- _len -= 4;
- }
+ return add(StringView(_data) );
+ }
- mixTail(data, _len);
+ inline void HashAdler32::add(const StringView& _data)
+ {
+ return add(_data.getPtr(), _data.getLength() );
}
template<typename Ty>
- inline void HashMurmur2A::add(Ty _value)
+ inline void HashAdler32::add(const Ty& _data)
{
- add(&_value, sizeof(Ty) );
+ add(&_data, sizeof(Ty) );
}
- inline uint32_t HashMurmur2A::end()
+ inline uint32_t HashAdler32::end()
{
- mmix(m_hash, m_tail);
- mmix(m_hash, m_size);
-
- m_hash ^= m_hash >> 13;
- m_hash *= MURMUR_M;
- m_hash ^= m_hash >> 15;
-
- return m_hash;
+ return m_a | (m_b<<16);
}
- inline void HashMurmur2A::readUnaligned(const void* _data, uint32_t& _out)
+ inline void HashCrc32::add(const char* _data)
{
- const uint8_t* data = (const uint8_t*)_data;
- if (BX_ENABLED(BX_CPU_ENDIAN_BIG) )
- {
- _out = 0
- | data[0]<<24
- | data[1]<<16
- | data[2]<<8
- | data[3]
- ;
- }
- else
- {
- _out = 0
- | data[0]
- | data[1]<<8
- | data[2]<<16
- | data[3]<<24
- ;
- }
+ return add(StringView(_data) );
}
- inline void HashMurmur2A::mixTail(const uint8_t*& _data, int& _len)
+ inline void HashCrc32::add(const StringView& _data)
{
- while( _len && ((_len<4) || m_count) )
- {
- m_tail |= (*_data++) << (m_count * 8);
-
- m_count++;
- _len--;
-
- if(m_count == 4)
- {
- mmix(m_hash, m_tail);
- m_tail = 0;
- m_count = 0;
- }
- }
+ return add(_data.getPtr(), _data.getLength() );
}
-#undef MURMUR_M
-#undef MURMUR_R
-#undef mmix
-
- inline void HashAdler32::begin()
+ template<typename Ty>
+ inline void HashCrc32::add(const Ty& _data)
{
- m_a = 1;
- m_b = 0;
+ add(&_data, sizeof(Ty) );
}
- inline void HashAdler32::add(const void* _data, int _len)
+ inline uint32_t HashCrc32::end()
{
- const uint32_t kModAdler = 65521;
- const uint8_t* data = (const uint8_t*)_data;
- for (; _len != 0; --_len)
- {
- m_a = (m_a + *data++) % kModAdler;
- m_b = (m_b + m_a ) % kModAdler;
- }
+ m_hash ^= UINT32_MAX;
+ return m_hash;
}
- template<typename Ty>
- inline void HashAdler32::add(Ty _value)
+ inline void HashMurmur2A::begin(uint32_t _seed)
{
- add(&_value, sizeof(Ty) );
+ m_hash = _seed;
+ m_tail = 0;
+ m_count = 0;
+ m_size = 0;
}
- inline uint32_t HashAdler32::end()
+ inline void HashMurmur2A::add(const char* _data)
{
- return m_a | (m_b<<16);
+ return add(StringView(_data) );
}
- template<typename Ty>
- inline void HashCrc32::add(Ty _value)
+ inline void HashMurmur2A::add(const StringView& _data)
{
- add(&_value, sizeof(Ty) );
+ return add(_data.getPtr(), _data.getLength() );
}
- inline uint32_t HashCrc32::end()
+ template<typename Ty>
+ inline void HashMurmur2A::add(const Ty& _data)
{
- m_hash ^= UINT32_MAX;
- return m_hash;
+ add(&_data, sizeof(Ty) );
}
template<typename HashT>
@@ -181,15 +99,14 @@ namespace bx
{
HashT hh;
hh.begin();
- hh.add(_data, (int)_size);
+ hh.add(_data, (int32_t)_size);
return hh.end();
}
- template<typename HashT, typename Ty>
- inline uint32_t hash(const Ty& _data)
+ template<typename HashT>
+ inline uint32_t hash(const char* _data)
{
- BX_STATIC_ASSERT(isTriviallyCopyable<Ty>() );
- return hash<HashT>(&_data, sizeof(Ty) );
+ return hash<HashT>(StringView(_data) );
}
template<typename HashT>
@@ -198,10 +115,11 @@ namespace bx
return hash<HashT>(_data.getPtr(), _data.getLength() );
}
- template<typename HashT>
- inline uint32_t hash(const char* _data)
+ template<typename HashT, typename Ty>
+ inline uint32_t hash(const Ty& _data)
{
- return hash<HashT>(StringView(_data) );
+ BX_STATIC_ASSERT(isTriviallyCopyable<Ty>() );
+ return hash<HashT>(&_data, sizeof(Ty) );
}
} // namespace bx
diff --git a/3rdparty/bx/include/bx/inline/math.inl b/3rdparty/bx/include/bx/inline/math.inl
index 29c88797e94..df433fc6e67 100644
--- a/3rdparty/bx/include/bx/inline/math.inl
+++ b/3rdparty/bx/include/bx/inline/math.inl
@@ -1,6 +1,6 @@
/*
- * Copyright 2011-2018 Branimir Karadzic. All rights reserved.
- * License: https://github.com/bkaradzic/bx#license-bsd-2-clause
+ * Copyright 2011-2022 Branimir Karadzic. All rights reserved.
+ * License: https://github.com/bkaradzic/bx/blob/master/LICENSE
*/
// FPU math lib
@@ -10,6 +10,7 @@
#endif // BX_MATH_H_HEADER_GUARD
#include <bx/simd_t.h>
+#include <bx/uint32_t.h>
namespace bx
{
@@ -95,24 +96,46 @@ namespace bx
return tmp == UINT64_C(0x7ff0000000000000);
}
- inline BX_CONST_FUNC float round(float _f)
+ inline BX_CONSTEXPR_FUNC float floor(float _a)
{
- return floor(_f + 0.5f);
+ if (_a < 0.0f)
+ {
+ const float fr = fract(-_a);
+ const float tr = trunc(-_a);
+
+ return -tr - float(0.0f != fr);
+ }
+
+ return _a - fract(_a);
}
- inline BX_CONST_FUNC float ceil(float _a)
+ inline BX_CONSTEXPR_FUNC float ceil(float _a)
{
return -floor(-_a);
}
+ inline BX_CONSTEXPR_FUNC float round(float _f)
+ {
+ return floor(_f + 0.5f);
+ }
+
inline BX_CONSTEXPR_FUNC float lerp(float _a, float _b, float _t)
{
- return _a + (_b - _a) * _t;
+ // Reference(s):
+ // - Linear interpolation past, present and future
+ // https://web.archive.org/web/20200404165201/https://fgiesen.wordpress.com/2012/08/15/linear-interpolation-past-present-and-future/
+ //
+ return mad(_t, _b, nms(_t, _a, _a) );
+ }
+
+ inline BX_CONSTEXPR_FUNC float invLerp(float _a, float _b, float _value)
+ {
+ return (_value - _a) / (_b - _a);
}
inline BX_CONSTEXPR_FUNC float sign(float _a)
{
- return _a < 0.0f ? -1.0f : 1.0f;
+ return float( (0.0f < _a) - (0.0f > _a) );
}
inline BX_CONSTEXPR_FUNC float abs(float _a)
@@ -175,11 +198,18 @@ namespace bx
return pow(2.0f, _a);
}
+ template<>
inline BX_CONST_FUNC float log2(float _a)
{
return log(_a) * kInvLogNat2;
}
+ template<>
+ inline BX_CONST_FUNC int32_t log2(int32_t _a)
+ {
+ return 31 - uint32_cntlz(_a);
+ }
+
inline BX_CONST_FUNC float rsqrtRef(float _a)
{
return pow(_a, -0.5f);
@@ -248,9 +278,34 @@ namespace bx
return _a - trunc(_a);
}
+ inline BX_CONSTEXPR_FUNC float nms(float _a, float _b, float _c)
+ {
+ return _c - _a * _b;
+ }
+
+ inline BX_CONSTEXPR_FUNC float add(float _a, float _b)
+ {
+ return _a + _b;
+ }
+
+ inline BX_CONSTEXPR_FUNC float sub(float _a, float _b)
+ {
+ return _a - _b;
+ }
+
+ inline BX_CONSTEXPR_FUNC float mul(float _a, float _b)
+ {
+ return _a * _b;
+ }
+
inline BX_CONSTEXPR_FUNC float mad(float _a, float _b, float _c)
{
- return _a * _b + _c;
+ return add(mul(_a, _b), _c);
+ }
+
+ inline BX_CONSTEXPR_FUNC float rcp(float _a)
+ {
+ return 1.0f / _a;
}
inline BX_CONST_FUNC float mod(float _a, float _b)
@@ -258,22 +313,23 @@ namespace bx
return _a - _b * floor(_a / _b);
}
- inline BX_CONSTEXPR_FUNC bool equal(float _a, float _b, float _epsilon)
+ inline BX_CONSTEXPR_FUNC bool isEqual(float _a, float _b, float _epsilon)
{
// Reference(s):
- // - https://web.archive.org/web/20181103180318/http://realtimecollisiondetection.net/blog/?p=89
+ // - Floating-point tolerances revisited
+ // https://web.archive.org/web/20181103180318/http://realtimecollisiondetection.net/blog/?p=89
//
const float lhs = abs(_a - _b);
const float rhs = _epsilon * max(1.0f, abs(_a), abs(_b) );
return lhs <= rhs;
}
- inline BX_CONST_FUNC bool equal(const float* _a, const float* _b, uint32_t _num, float _epsilon)
+ inline BX_CONST_FUNC bool isEqual(const float* _a, const float* _b, uint32_t _num, float _epsilon)
{
- bool result = equal(_a[0], _b[0], _epsilon);
+ bool result = isEqual(_a[0], _b[0], _epsilon);
for (uint32_t ii = 1; result && ii < _num; ++ii)
{
- result = equal(_a[ii], _b[ii], _epsilon);
+ result = isEqual(_a[ii], _b[ii], _epsilon);
}
return result;
}
@@ -300,6 +356,11 @@ namespace bx
return square(_a)*(3.0f - 2.0f*_a);
}
+ inline BX_CONST_FUNC float invSmoothStep(float _a)
+ {
+ return 0.5f - sin(asin(1.0f - 2.0f * _a) / 3.0f);
+ }
+
inline BX_CONSTEXPR_FUNC float bias(float _time, float _bias)
{
return _time / ( ( (1.0f/_bias - 2.0f)*(1.0f - _time) ) + 1.0f);
@@ -331,26 +392,114 @@ namespace bx
return _a + angleDiff(_a, _b) * _t;
}
- inline Vec3 load(const void* _ptr)
+ template<typename Ty>
+ inline Ty load(const void* _ptr)
{
- const float* ptr = reinterpret_cast<const float*>(_ptr);
- return
- {
- ptr[0],
- ptr[1],
- ptr[2],
- };
+ Ty result(init::None);
+ memCopy(&result, _ptr, sizeof(Ty) );
+ return result;
+ }
+
+ template<typename Ty>
+ inline void store(void* _ptr, const Ty& _a)
+ {
+ memCopy(_ptr, &_a, sizeof(Ty) );
}
- inline void store(void* _ptr, const Vec3& _a)
+ inline Vec3::Vec3(init::NoneTag)
{
- float* ptr = reinterpret_cast<float*>(_ptr);
- ptr[0] = _a.x;
- ptr[1] = _a.y;
- ptr[2] = _a.z;
}
- inline BX_CONSTEXPR_FUNC Vec3 abs(const Vec3& _a)
+ constexpr Vec3::Vec3(init::ZeroTag)
+ : x(0.0f)
+ , y(0.0f)
+ , z(0.0f)
+ {
+ }
+
+ constexpr Vec3::Vec3(init::IdentityTag)
+ : x(0.0f)
+ , y(0.0f)
+ , z(0.0f)
+ {
+ }
+
+ constexpr Vec3::Vec3(float _v)
+ : x(_v)
+ , y(_v)
+ , z(_v)
+ {
+ }
+
+ constexpr Vec3::Vec3(float _x, float _y, float _z)
+ : x(_x)
+ , y(_y)
+ , z(_z)
+ {
+ }
+
+ inline Plane::Plane(init::NoneTag)
+ : normal(init::None)
+ {
+ }
+
+ constexpr Plane::Plane(init::ZeroTag)
+ : normal(init::Zero)
+ , dist(0.0f)
+ {
+ }
+
+ constexpr Plane::Plane(init::IdentityTag)
+ : normal(0.0f, 1.0f, 0.0f)
+ , dist(0.0f)
+ {
+ }
+
+ constexpr Plane::Plane(Vec3 _normal, float _dist)
+ : normal(_normal)
+ , dist(_dist)
+ {
+ }
+
+ inline Quaternion::Quaternion(init::NoneTag)
+ {
+ }
+
+ constexpr Quaternion::Quaternion(init::ZeroTag)
+ : x(0.0f)
+ , y(0.0f)
+ , z(0.0f)
+ , w(0.0f)
+ {
+ }
+
+ constexpr Quaternion::Quaternion(init::IdentityTag)
+ : x(0.0f)
+ , y(0.0f)
+ , z(0.0f)
+ , w(1.0f)
+ {
+ }
+
+ constexpr Quaternion::Quaternion(float _x, float _y, float _z, float _w)
+ : x(_x)
+ , y(_y)
+ , z(_z)
+ , w(_w)
+ {
+ }
+
+ inline BX_CONSTEXPR_FUNC Vec3 round(const Vec3 _a)
+ {
+ return
+ {
+ round(_a.x),
+ round(_a.y),
+ round(_a.z),
+ };
+ }
+
+ inline BX_CONSTEXPR_FUNC Vec3 abs(const Vec3 _a)
{
return
{
@@ -360,7 +509,7 @@ namespace bx
};
}
- inline BX_CONSTEXPR_FUNC Vec3 neg(const Vec3& _a)
+ inline BX_CONSTEXPR_FUNC Vec3 neg(const Vec3 _a)
{
return
{
@@ -370,7 +519,7 @@ namespace bx
};
}
- inline BX_CONSTEXPR_FUNC Vec3 add(const Vec3& _a, const Vec3& _b)
+ inline BX_CONSTEXPR_FUNC Vec3 add(const Vec3 _a, const Vec3 _b)
{
return
{
@@ -380,7 +529,7 @@ namespace bx
};
}
- inline BX_CONSTEXPR_FUNC Vec3 add(const Vec3& _a, float _b)
+ inline BX_CONSTEXPR_FUNC Vec3 add(const Vec3 _a, float _b)
{
return
{
@@ -390,7 +539,7 @@ namespace bx
};
}
- inline BX_CONSTEXPR_FUNC Vec3 sub(const Vec3& _a, const Vec3& _b)
+ inline BX_CONSTEXPR_FUNC Vec3 sub(const Vec3 _a, const Vec3 _b)
{
return
{
@@ -400,7 +549,7 @@ namespace bx
};
}
- inline BX_CONSTEXPR_FUNC Vec3 sub(const Vec3& _a, float _b)
+ inline BX_CONSTEXPR_FUNC Vec3 sub(const Vec3 _a, float _b)
{
return
{
@@ -410,7 +559,7 @@ namespace bx
};
}
- inline BX_CONSTEXPR_FUNC Vec3 mul(const Vec3& _a, const Vec3& _b)
+ inline BX_CONSTEXPR_FUNC Vec3 mul(const Vec3 _a, const Vec3 _b)
{
return
{
@@ -420,7 +569,7 @@ namespace bx
};
}
- inline BX_CONSTEXPR_FUNC Vec3 mul(const Vec3& _a, float _b)
+ inline BX_CONSTEXPR_FUNC Vec3 mul(const Vec3 _a, float _b)
{
return
{
@@ -430,17 +579,42 @@ namespace bx
};
}
- inline BX_CONSTEXPR_FUNC Vec3 mad(const Vec3& _a, const Vec3& _b, const Vec3& _c)
+ inline BX_CONSTEXPR_FUNC Vec3 div(const Vec3 _a, const Vec3 _b)
+ {
+ return mul(_a, rcp(_b) );
+ }
+
+ inline BX_CONSTEXPR_FUNC Vec3 div(const Vec3 _a, float _b)
+ {
+ return mul(_a, rcp(_b) );
+ }
+
+ inline BX_CONSTEXPR_FUNC Vec3 nms(const Vec3 _a, const float _b, const Vec3 _c)
+ {
+ return sub(_c, mul(_a, _b) );
+ }
+
+ inline BX_CONSTEXPR_FUNC Vec3 nms(const Vec3 _a, const Vec3 _b, const Vec3 _c)
+ {
+ return sub(_c, mul(_a, _b) );
+ }
+
+ inline BX_CONSTEXPR_FUNC Vec3 mad(const Vec3 _a, const float _b, const Vec3 _c)
+ {
+ return add(mul(_a, _b), _c);
+ }
+
+ inline BX_CONSTEXPR_FUNC Vec3 mad(const Vec3 _a, const Vec3 _b, const Vec3 _c)
{
return add(mul(_a, _b), _c);
}
- inline BX_CONSTEXPR_FUNC float dot(const Vec3& _a, const Vec3& _b)
+ inline BX_CONSTEXPR_FUNC float dot(const Vec3 _a, const Vec3 _b)
{
return _a.x*_b.x + _a.y*_b.y + _a.z*_b.z;
}
- inline BX_CONSTEXPR_FUNC Vec3 cross(const Vec3& _a, const Vec3& _b)
+ inline BX_CONSTEXPR_FUNC Vec3 cross(const Vec3 _a, const Vec3 _b)
{
return
{
@@ -450,12 +624,23 @@ namespace bx
};
}
- inline BX_CONST_FUNC float length(const Vec3& _a)
+ inline BX_CONST_FUNC float length(const Vec3 _a)
{
return sqrt(dot(_a, _a) );
}
- inline BX_CONSTEXPR_FUNC Vec3 lerp(const Vec3& _a, const Vec3& _b, float _t)
+ inline BX_CONST_FUNC float distanceSq(const Vec3 _a, const Vec3 _b)
+ {
+ const Vec3 ba = sub(_b, _a);
+ return dot(ba, ba);
+ }
+
+ inline BX_CONST_FUNC float distance(const Vec3 _a, const Vec3 _b)
+ {
+ return length(sub(_b, _a) );
+ }
+
+ inline BX_CONSTEXPR_FUNC Vec3 lerp(const Vec3 _a, const Vec3 _b, float _t)
{
return
{
@@ -465,7 +650,7 @@ namespace bx
};
}
- inline BX_CONSTEXPR_FUNC Vec3 lerp(const Vec3& _a, const Vec3& _b, const Vec3& _t)
+ inline BX_CONSTEXPR_FUNC Vec3 lerp(const Vec3 _a, const Vec3 _b, const Vec3 _t)
{
return
{
@@ -475,14 +660,14 @@ namespace bx
};
}
- inline BX_CONST_FUNC Vec3 normalize(const Vec3& _a)
+ inline BX_CONST_FUNC Vec3 normalize(const Vec3 _a)
{
const float invLen = 1.0f/length(_a);
- const Vec3 result = mul(_a, invLen);
+ const Vec3 result = mul(_a, invLen);
return result;
}
- inline BX_CONSTEXPR_FUNC Vec3 min(const Vec3& _a, const Vec3& _b)
+ inline BX_CONSTEXPR_FUNC Vec3 min(const Vec3 _a, const Vec3 _b)
{
return
{
@@ -492,7 +677,7 @@ namespace bx
};
}
- inline BX_CONSTEXPR_FUNC Vec3 max(const Vec3& _a, const Vec3& _b)
+ inline BX_CONSTEXPR_FUNC Vec3 max(const Vec3 _a, const Vec3 _b)
{
return
{
@@ -502,7 +687,7 @@ namespace bx
};
}
- inline BX_CONSTEXPR_FUNC Vec3 rcp(const Vec3& _a)
+ inline BX_CONSTEXPR_FUNC Vec3 rcp(const Vec3 _a)
{
return
{
@@ -512,7 +697,15 @@ namespace bx
};
}
- inline void calcTangentFrame(Vec3& _outT, Vec3& _outB, const Vec3& _n)
+ inline BX_CONSTEXPR_FUNC bool isEqual(const Vec3 _a, const Vec3 _b, float _epsilon)
+ {
+ return isEqual(_a.x, _b.x, _epsilon)
+ && isEqual(_a.y, _b.y, _epsilon)
+ && isEqual(_a.z, _b.z, _epsilon)
+ ;
+ }
+
+ inline void calcTangentFrame(Vec3& _outT, Vec3& _outB, const Vec3 _n)
{
const float nx = _n.x;
const float ny = _n.y;
@@ -536,7 +729,7 @@ namespace bx
_outB = cross(_n, _outT);
}
- inline void calcTangentFrame(Vec3& _outT, Vec3& _outB, const Vec3& _n, float _angle)
+ inline void calcTangentFrame(Vec3& _outT, Vec3& _outB, const Vec3 _n, float _angle)
{
calcTangentFrame(_outT, _outB, _n);
@@ -552,7 +745,7 @@ namespace bx
inline BX_CONST_FUNC Vec3 fromLatLong(float _u, float _v)
{
- Vec3 result;
+ Vec3 result(init::None);
const float phi = _u * kPi2;
const float theta = _v * kPi;
@@ -567,292 +760,317 @@ namespace bx
return result;
}
- inline void toLatLong(float* _outU, float* _outV, const Vec3& _dir)
+ inline void toLatLong(float* _outU, float* _outV, const Vec3 _dir)
{
const float phi = atan2(_dir.x, _dir.z);
const float theta = acos(_dir.y);
- *_outU = (bx::kPi + phi)/bx::kPi2;
- *_outV = theta*bx::kInvPi;
+ *_outU = (kPi + phi)/kPi2;
+ *_outV = theta*kInvPi;
}
- inline void vec3Add(float* _result, const float* _a, const float* _b)
+ inline BX_CONSTEXPR_FUNC Quaternion invert(const Quaternion _a)
{
- _result[0] = _a[0] + _b[0];
- _result[1] = _a[1] + _b[1];
- _result[2] = _a[2] + _b[2];
+ return
+ {
+ -_a.x,
+ -_a.y,
+ -_a.z,
+ _a.w,
+ };
}
- inline void vec3Sub(float* _result, const float* _a, const float* _b)
+ inline BX_CONSTEXPR_FUNC Vec3 mulXyz(const Quaternion _a, const Quaternion _b)
{
- _result[0] = _a[0] - _b[0];
- _result[1] = _a[1] - _b[1];
- _result[2] = _a[2] - _b[2];
+ const float ax = _a.x;
+ const float ay = _a.y;
+ const float az = _a.z;
+ const float aw = _a.w;
+
+ const float bx = _b.x;
+ const float by = _b.y;
+ const float bz = _b.z;
+ const float bw = _b.w;
+
+ return
+ {
+ aw * bx + ax * bw + ay * bz - az * by,
+ aw * by - ax * bz + ay * bw + az * bx,
+ aw * bz + ax * by - ay * bx + az * bw,
+ };
}
- inline void vec3Mul(float* _result, const float* _a, const float* _b)
+ inline BX_CONSTEXPR_FUNC Quaternion add(const Quaternion _a, const Quaternion _b)
{
- _result[0] = _a[0] * _b[0];
- _result[1] = _a[1] * _b[1];
- _result[2] = _a[2] * _b[2];
+ return
+ {
+ _a.x + _b.x,
+ _a.y + _b.y,
+ _a.z + _b.z,
+ _a.w + _b.w,
+ };
}
- inline void vec3Mul(float* _result, const float* _a, float _b)
+ inline BX_CONSTEXPR_FUNC Quaternion sub(const Quaternion _a, const Quaternion _b)
{
- _result[0] = _a[0] * _b;
- _result[1] = _a[1] * _b;
- _result[2] = _a[2] * _b;
+ return
+ {
+ _a.x - _b.x,
+ _a.y - _b.y,
+ _a.z - _b.z,
+ _a.w - _b.w,
+ };
}
- inline float vec3Dot(const float* _a, const float* _b)
+ inline BX_CONSTEXPR_FUNC Quaternion mul(const Quaternion _a, float _b)
{
- return _a[0]*_b[0] + _a[1]*_b[1] + _a[2]*_b[2];
+ return
+ {
+ _a.x * _b,
+ _a.y * _b,
+ _a.z * _b,
+ _a.w * _b,
+ };
}
- inline void vec3Cross(float* _result, const float* _a, const float* _b)
+ inline BX_CONSTEXPR_FUNC Quaternion mul(const Quaternion _a, const Quaternion _b)
{
- _result[0] = _a[1]*_b[2] - _a[2]*_b[1];
- _result[1] = _a[2]*_b[0] - _a[0]*_b[2];
- _result[2] = _a[0]*_b[1] - _a[1]*_b[0];
+ const float ax = _a.x;
+ const float ay = _a.y;
+ const float az = _a.z;
+ const float aw = _a.w;
+
+ const float bx = _b.x;
+ const float by = _b.y;
+ const float bz = _b.z;
+ const float bw = _b.w;
+
+ return
+ {
+ aw * bx + ax * bw + ay * bz - az * by,
+ aw * by - ax * bz + ay * bw + az * bx,
+ aw * bz + ax * by - ay * bx + az * bw,
+ aw * bw - ax * bx - ay * by - az * bz,
+ };
}
- inline float vec3Length(const float* _a)
+ inline BX_CONSTEXPR_FUNC Vec3 mul(const Vec3 _v, const Quaternion _q)
{
- return sqrt(vec3Dot(_a, _a) );
+ const Quaternion tmp0 = invert(_q);
+ const Quaternion qv = { _v.x, _v.y, _v.z, 0.0f };
+ const Quaternion tmp1 = mul(tmp0, qv);
+ const Vec3 result = mulXyz(tmp1, _q);
+
+ return result;
}
- inline float vec3Norm(float* _result, const float* _a)
+ inline BX_CONSTEXPR_FUNC float dot(const Quaternion _a, const Quaternion _b)
{
- const float len = vec3Length(_a);
- const float invLen = 1.0f/len;
- _result[0] = _a[0] * invLen;
- _result[1] = _a[1] * invLen;
- _result[2] = _a[2] * invLen;
- return len;
+ return
+ _a.x * _b.x
+ + _a.y * _b.y
+ + _a.z * _b.z
+ + _a.w * _b.w
+ ;
}
- inline void vec3TangentFrame(const float* _n, float* _t, float* _b)
+ inline BX_CONSTEXPR_FUNC Quaternion normalize(const Quaternion _a)
{
- const float nx = _n[0];
- const float ny = _n[1];
- const float nz = _n[2];
-
- if (abs(nx) > abs(nz) )
- {
- float invLen = 1.0f / sqrt(nx*nx + nz*nz);
- _t[0] = -nz * invLen;
- _t[1] = 0.0f;
- _t[2] = nx * invLen;
- }
- else
+ const float norm = dot(_a, _a);
+ if (0.0f < norm)
{
- float invLen = 1.0f / sqrt(ny*ny + nz*nz);
- _t[0] = 0.0f;
- _t[1] = nz * invLen;
- _t[2] = -ny * invLen;
+ const float invNorm = rsqrt(norm);
+
+ return mul(_a, invNorm);
}
- vec3Cross(_b, _n, _t);
+ return
+ {
+ 0.0f,
+ 0.0f,
+ 0.0f,
+ 1.0f,
+ };
}
- inline void vec3TangentFrame(const float* _n, float* _t, float* _b, float _angle)
+ inline BX_CONSTEXPR_FUNC Quaternion lerp(const Quaternion _a, const Quaternion _b, float _t)
{
- vec3TangentFrame(_n, _t, _b);
-
- const float sa = sin(_angle);
- const float ca = cos(_angle);
+ const float sa = 1.0f - _t;
+ const float adotb = dot(_a, _b);
+ const float sb = sign(adotb) * _t;
- _t[0] = -sa * _b[0] + ca * _t[0];
- _t[1] = -sa * _b[1] + ca * _t[1];
- _t[2] = -sa * _b[2] + ca * _t[2];
+ const Quaternion aa = mul(_a, sa);
+ const Quaternion bb = mul(_b, sb);
+ const Quaternion qq = add(aa, bb);
- vec3Cross(_b, _n, _t);
+ return normalize(qq);
}
- inline void vec3FromLatLong(float* _vec, float _u, float _v)
+ inline BX_CONST_FUNC Quaternion fromEuler(const Vec3 _euler)
{
- const float phi = _u * kPi2;
- const float theta = _v * kPi;
-
- const float st = sin(theta);
- const float sp = sin(phi);
- const float ct = cos(theta);
- const float cp = cos(phi);
+ const float sx = sin(_euler.x * 0.5f);
+ const float cx = cos(_euler.x * 0.5f);
+ const float sy = sin(_euler.y * 0.5f);
+ const float cy = cos(_euler.y * 0.5f);
+ const float sz = sin(_euler.z * 0.5f);
+ const float cz = cos(_euler.z * 0.5f);
- _vec[0] = -st*sp;
- _vec[1] = ct;
- _vec[2] = -st*cp;
+ return
+ {
+ sx * cy * cz - cx * sy * sz,
+ cx * sy * cz + sx * cy * sz,
+ cx * cy * sz - sx * sy * cz,
+ cx * cy * cz + sx * sy * sz,
+ };
}
- inline void vec3ToLatLong(float* _outU, float* _outV, const float* _dir)
+ inline BX_CONST_FUNC Vec3 toEuler(const Quaternion _a)
{
- const float phi = atan2(_dir[0], _dir[2]);
- const float theta = acos(_dir[1]);
+ const float xx = _a.x;
+ const float yy = _a.y;
+ const float zz = _a.z;
+ const float ww = _a.w;
+ const float xsq = square(xx);
+ const float ysq = square(yy);
+ const float zsq = square(zz);
- *_outU = (bx::kPi + phi)/bx::kPi2;
- *_outV = theta*bx::kInvPi;
+ return
+ {
+ atan2(2.0f * (xx * ww - yy * zz), 1.0f - 2.0f * (xsq + zsq) ),
+ atan2(2.0f * (yy * ww + xx * zz), 1.0f - 2.0f * (ysq + zsq) ),
+ asin( 2.0f * (xx * yy + zz * ww) ),
+ };
}
- inline void quatIdentity(float* _result)
+ inline BX_CONST_FUNC Vec3 toXAxis(const Quaternion _a)
{
- _result[0] = 0.0f;
- _result[1] = 0.0f;
- _result[2] = 0.0f;
- _result[3] = 1.0f;
- }
+ const float xx = _a.x;
+ const float yy = _a.y;
+ const float zz = _a.z;
+ const float ww = _a.w;
+ const float ysq = square(yy);
+ const float zsq = square(zz);
- inline void quatMove(float* _result, const float* _a)
- {
- _result[0] = _a[0];
- _result[1] = _a[1];
- _result[2] = _a[2];
- _result[3] = _a[3];
+ return
+ {
+ 1.0f - 2.0f * ysq - 2.0f * zsq,
+ 2.0f * xx * yy + 2.0f * zz * ww,
+ 2.0f * xx * zz - 2.0f * yy * ww,
+ };
}
- inline void quatMulXYZ(float* _result, const float* _qa, const float* _qb)
+ inline BX_CONST_FUNC Vec3 toYAxis(const Quaternion _a)
{
- const float ax = _qa[0];
- const float ay = _qa[1];
- const float az = _qa[2];
- const float aw = _qa[3];
+ const float xx = _a.x;
+ const float yy = _a.y;
+ const float zz = _a.z;
+ const float ww = _a.w;
+ const float xsq = square(xx);
+ const float zsq = square(zz);
- const float bx = _qb[0];
- const float by = _qb[1];
- const float bz = _qb[2];
- const float bw = _qb[3];
-
- _result[0] = aw * bx + ax * bw + ay * bz - az * by;
- _result[1] = aw * by - ax * bz + ay * bw + az * bx;
- _result[2] = aw * bz + ax * by - ay * bx + az * bw;
+ return
+ {
+ 2.0f * xx * yy - 2.0f * zz * ww,
+ 1.0f - 2.0f * xsq - 2.0f * zsq,
+ 2.0f * yy * zz + 2.0f * xx * ww,
+ };
}
- inline void quatMul(float* _result, const float* _qa, const float* _qb)
+ inline BX_CONST_FUNC Vec3 toZAxis(const Quaternion _a)
{
- const float ax = _qa[0];
- const float ay = _qa[1];
- const float az = _qa[2];
- const float aw = _qa[3];
-
- const float bx = _qb[0];
- const float by = _qb[1];
- const float bz = _qb[2];
- const float bw = _qb[3];
+ const float xx = _a.x;
+ const float yy = _a.y;
+ const float zz = _a.z;
+ const float ww = _a.w;
+ const float xsq = square(xx);
+ const float ysq = square(yy);
- _result[0] = aw * bx + ax * bw + ay * bz - az * by;
- _result[1] = aw * by - ax * bz + ay * bw + az * bx;
- _result[2] = aw * bz + ax * by - ay * bx + az * bw;
- _result[3] = aw * bw - ax * bx - ay * by - az * bz;
- }
-
- inline void quatInvert(float* _result, const float* _quat)
- {
- _result[0] = -_quat[0];
- _result[1] = -_quat[1];
- _result[2] = -_quat[2];
- _result[3] = _quat[3];
+ return
+ {
+ 2.0f * xx * zz + 2.0f * yy * ww,
+ 2.0f * yy * zz - 2.0f * xx * ww,
+ 1.0f - 2.0f * xsq - 2.0f * ysq,
+ };
}
- inline float quatDot(const float* _a, const float* _b)
+ inline BX_CONST_FUNC Quaternion fromAxisAngle(const Vec3 _axis, float _angle)
{
- return _a[0]*_b[0]
- + _a[1]*_b[1]
- + _a[2]*_b[2]
- + _a[3]*_b[3]
- ;
- }
+ const float ha = _angle * 0.5f;
+ const float sa = sin(ha);
- inline void quatNorm(float* _result, const float* _quat)
- {
- const float norm = quatDot(_quat, _quat);
- if (0.0f < norm)
- {
- const float invNorm = 1.0f / sqrt(norm);
- _result[0] = _quat[0] * invNorm;
- _result[1] = _quat[1] * invNorm;
- _result[2] = _quat[2] * invNorm;
- _result[3] = _quat[3] * invNorm;
- }
- else
+ return
{
- quatIdentity(_result);
- }
+ _axis.x * sa,
+ _axis.y * sa,
+ _axis.z * sa,
+ cos(ha),
+ };
}
- inline void quatToEuler(float* _result, const float* _quat)
+ inline void toAxisAngle(Vec3& _outAxis, float& _outAngle, const Quaternion _a)
{
- const float x = _quat[0];
- const float y = _quat[1];
- const float z = _quat[2];
- const float w = _quat[3];
+ const float ww = _a.w;
+ const float sa = sqrt(1.0f - square(ww) );
- const float yy = y * y;
- const float zz = z * z;
+ _outAngle = 2.0f * acos(ww);
- const float xx = x * x;
- _result[0] = atan2(2.0f * (x * w - y * z), 1.0f - 2.0f * (xx + zz) );
- _result[1] = atan2(2.0f * (y * w + x * z), 1.0f - 2.0f * (yy + zz) );
- _result[2] = asin (2.0f * (x * y + z * w) );
- }
+ if (0.001f > sa)
+ {
+ _outAxis = { _a.x, _a.y, _a.z };
+ return;
+ }
- inline void quatRotateAxis(float* _result, const float* _axis, float _angle)
- {
- const float ha = _angle * 0.5f;
- const float ca = cos(ha);
- const float sa = sin(ha);
- _result[0] = _axis[0] * sa;
- _result[1] = _axis[1] * sa;
- _result[2] = _axis[2] * sa;
- _result[3] = ca;
+ const float invSa = 1.0f/sa;
+
+ _outAxis = { _a.x * invSa, _a.y * invSa, _a.z * invSa };
}
- inline void quatRotateX(float* _result, float _ax)
+ inline BX_CONST_FUNC Quaternion rotateX(float _ax)
{
const float hx = _ax * 0.5f;
- const float cx = cos(hx);
- const float sx = sin(hx);
- _result[0] = sx;
- _result[1] = 0.0f;
- _result[2] = 0.0f;
- _result[3] = cx;
+
+ return
+ {
+ sin(hx),
+ 0.0f,
+ 0.0f,
+ cos(hx),
+ };
}
- inline void quatRotateY(float* _result, float _ay)
+ inline BX_CONST_FUNC Quaternion rotateY(float _ay)
{
const float hy = _ay * 0.5f;
- const float cy = cos(hy);
- const float sy = sin(hy);
- _result[0] = 0.0f;
- _result[1] = sy;
- _result[2] = 0.0f;
- _result[3] = cy;
+
+ return
+ {
+ 0.0f,
+ sin(hy),
+ 0.0f,
+ cos(hy),
+ };
}
- inline void quatRotateZ(float* _result, float _az)
+ inline BX_CONST_FUNC Quaternion rotateZ(float _az)
{
const float hz = _az * 0.5f;
- const float cz = cos(hz);
- const float sz = sin(hz);
- _result[0] = 0.0f;
- _result[1] = 0.0f;
- _result[2] = sz;
- _result[3] = cz;
+
+ return
+ {
+ 0.0f,
+ 0.0f,
+ sin(hz),
+ cos(hz),
+ };
}
- inline void vec3MulQuat(float* _result, const float* _vec, const float* _quat)
+ inline BX_CONSTEXPR_FUNC bool isEqual(const Quaternion _a, const Quaternion _b, float _epsilon)
{
- float tmp0[4];
- quatInvert(tmp0, _quat);
-
- float qv[4];
- qv[0] = _vec[0];
- qv[1] = _vec[1];
- qv[2] = _vec[2];
- qv[3] = 0.0f;
-
- float tmp1[4];
- quatMul(tmp1, tmp0, qv);
-
- quatMulXYZ(_result, tmp1, _quat);
+ return isEqual(_a.x, _b.x, _epsilon)
+ && isEqual(_a.y, _b.y, _epsilon)
+ && isEqual(_a.z, _b.z, _epsilon)
+ && isEqual(_a.w, _b.w, _epsilon)
+ ;
}
inline void mtxIdentity(float* _result)
@@ -883,63 +1101,63 @@ namespace bx
mtxScale(_result, _scale, _scale, _scale);
}
- inline void mtxFromNormal(float* _result, const float* _normal, float _scale, const float* _pos)
+ inline void mtxFromNormal(float* _result, const Vec3& _normal, float _scale, const Vec3& _pos)
{
- float tangent[3];
- float bitangent[3];
- vec3TangentFrame(_normal, tangent, bitangent);
+ Vec3 tangent(init::None);
+ Vec3 bitangent(init::None);
+ calcTangentFrame(tangent, bitangent, _normal);
- vec3Mul(&_result[ 0], bitangent, _scale);
- vec3Mul(&_result[ 4], _normal, _scale);
- vec3Mul(&_result[ 8], tangent, _scale);
+ store(&_result[ 0], mul(bitangent, _scale) );
+ store(&_result[ 4], mul(_normal, _scale) );
+ store(&_result[ 8], mul(tangent, _scale) );
_result[ 3] = 0.0f;
_result[ 7] = 0.0f;
_result[11] = 0.0f;
- _result[12] = _pos[0];
- _result[13] = _pos[1];
- _result[14] = _pos[2];
+ _result[12] = _pos.x;
+ _result[13] = _pos.y;
+ _result[14] = _pos.z;
_result[15] = 1.0f;
}
- inline void mtxFromNormal(float* _result, const float* _normal, float _scale, const float* _pos, float _angle)
+ inline void mtxFromNormal(float* _result, const Vec3& _normal, float _scale, const Vec3& _pos, float _angle)
{
- float tangent[3];
- float bitangent[3];
- vec3TangentFrame(_normal, tangent, bitangent, _angle);
+ Vec3 tangent(init::None);
+ Vec3 bitangent(init::None);
+ calcTangentFrame(tangent, bitangent, _normal, _angle);
- vec3Mul(&_result[ 0], bitangent, _scale);
- vec3Mul(&_result[ 4], _normal, _scale);
- vec3Mul(&_result[ 8], tangent, _scale);
+ store(&_result[0], mul(bitangent, _scale) );
+ store(&_result[4], mul(_normal, _scale) );
+ store(&_result[8], mul(tangent, _scale) );
_result[ 3] = 0.0f;
_result[ 7] = 0.0f;
_result[11] = 0.0f;
- _result[12] = _pos[0];
- _result[13] = _pos[1];
- _result[14] = _pos[2];
+ _result[12] = _pos.x;
+ _result[13] = _pos.y;
+ _result[14] = _pos.z;
_result[15] = 1.0f;
}
- inline void mtxQuat(float* _result, const float* _quat)
+ inline void mtxFromQuaternion(float* _result, const Quaternion& _rotation)
{
- const float x = _quat[0];
- const float y = _quat[1];
- const float z = _quat[2];
- const float w = _quat[3];
+ const float qx = _rotation.x;
+ const float qy = _rotation.y;
+ const float qz = _rotation.z;
+ const float qw = _rotation.w;
- const float x2 = x + x;
- const float y2 = y + y;
- const float z2 = z + z;
- const float x2x = x2 * x;
- const float x2y = x2 * y;
- const float x2z = x2 * z;
- const float x2w = x2 * w;
- const float y2y = y2 * y;
- const float y2z = y2 * z;
- const float y2w = y2 * w;
- const float z2z = z2 * z;
- const float z2w = z2 * w;
+ const float x2 = qx + qx;
+ const float y2 = qy + qy;
+ const float z2 = qz + qz;
+ const float x2x = x2 * qx;
+ const float x2y = x2 * qy;
+ const float x2z = x2 * qz;
+ const float x2w = x2 * qw;
+ const float y2y = y2 * qy;
+ const float y2z = y2 * qz;
+ const float y2w = y2 * qw;
+ const float z2z = z2 * qz;
+ const float z2w = z2 * qw;
_result[ 0] = 1.0f - (y2y + z2z);
_result[ 1] = x2y - z2w;
@@ -962,27 +1180,15 @@ namespace bx
_result[15] = 1.0f;
}
- inline void mtxQuatTranslation(float* _result, const float* _quat, const float* _translation)
+ inline void mtxFromQuaternion(float* _result, const Quaternion& _rotation, const Vec3& _translation)
{
- mtxQuat(_result, _quat);
- _result[12] = -(_result[0]*_translation[0] + _result[4]*_translation[1] + _result[ 8]*_translation[2]);
- _result[13] = -(_result[1]*_translation[0] + _result[5]*_translation[1] + _result[ 9]*_translation[2]);
- _result[14] = -(_result[2]*_translation[0] + _result[6]*_translation[1] + _result[10]*_translation[2]);
- }
-
- inline void mtxQuatTranslationHMD(float* _result, const float* _quat, const float* _translation)
- {
- float quat[4];
- quat[0] = -_quat[0];
- quat[1] = -_quat[1];
- quat[2] = _quat[2];
- quat[3] = _quat[3];
- mtxQuatTranslation(_result, quat, _translation);
+ mtxFromQuaternion(_result, _rotation);
+ store(&_result[12], neg(mulXyz0(_translation, _result) ) );
}
inline Vec3 mul(const Vec3& _vec, const float* _mat)
{
- Vec3 result;
+ Vec3 result(init::None);
result.x = _vec.x * _mat[0] + _vec.y * _mat[4] + _vec.z * _mat[ 8] + _mat[12];
result.y = _vec.x * _mat[1] + _vec.y * _mat[5] + _vec.z * _mat[ 9] + _mat[13];
result.z = _vec.x * _mat[2] + _vec.y * _mat[6] + _vec.z * _mat[10] + _mat[14];
@@ -991,7 +1197,7 @@ namespace bx
inline Vec3 mulXyz0(const Vec3& _vec, const float* _mat)
{
- Vec3 result;
+ Vec3 result(init::None);
result.x = _vec.x * _mat[0] + _vec.y * _mat[4] + _vec.z * _mat[ 8];
result.y = _vec.x * _mat[1] + _vec.y * _mat[5] + _vec.z * _mat[ 9];
result.z = _vec.x * _mat[2] + _vec.y * _mat[6] + _vec.z * _mat[10];
@@ -1016,48 +1222,6 @@ namespace bx
return result;
}
- inline void vec3MulMtx(float* _result, const float* _vec, const float* _mat)
- {
- _result[0] = _vec[0] * _mat[ 0] + _vec[1] * _mat[4] + _vec[2] * _mat[ 8] + _mat[12];
- _result[1] = _vec[0] * _mat[ 1] + _vec[1] * _mat[5] + _vec[2] * _mat[ 9] + _mat[13];
- _result[2] = _vec[0] * _mat[ 2] + _vec[1] * _mat[6] + _vec[2] * _mat[10] + _mat[14];
- }
-
- inline void vec3MulMtxXyz0(float* _result, const float* _vec, const float* _mat)
- {
- _result[0] = _vec[0] * _mat[ 0] + _vec[1] * _mat[4] + _vec[2] * _mat[ 8];
- _result[1] = _vec[0] * _mat[ 1] + _vec[1] * _mat[5] + _vec[2] * _mat[ 9];
- _result[2] = _vec[0] * _mat[ 2] + _vec[1] * _mat[6] + _vec[2] * _mat[10];
- }
-
- inline void vec3MulMtxH(float* _result, const float* _vec, const float* _mat)
- {
- float xx = _vec[0] * _mat[ 0] + _vec[1] * _mat[4] + _vec[2] * _mat[ 8] + _mat[12];
- float yy = _vec[0] * _mat[ 1] + _vec[1] * _mat[5] + _vec[2] * _mat[ 9] + _mat[13];
- float zz = _vec[0] * _mat[ 2] + _vec[1] * _mat[6] + _vec[2] * _mat[10] + _mat[14];
- float ww = _vec[0] * _mat[ 3] + _vec[1] * _mat[7] + _vec[2] * _mat[11] + _mat[15];
- float invW = sign(ww)/ww;
- _result[0] = xx*invW;
- _result[1] = yy*invW;
- _result[2] = zz*invW;
- }
-
- inline void vec4Mul(float* _result, const float* _a, const float* _b)
- {
- _result[0] = _a[0] * _b[0];
- _result[1] = _a[1] * _b[1];
- _result[2] = _a[2] * _b[2];
- _result[3] = _a[3] * _b[3];
- }
-
- inline void vec4Mul(float* _result, const float* _a, float _b)
- {
- _result[0] = _a[0] * _b;
- _result[1] = _a[1] * _b;
- _result[2] = _a[2] * _b;
- _result[3] = _a[3] * _b;
- }
-
inline void vec4MulMtx(float* _result, const float* _vec, const float* _mat)
{
_result[0] = _vec[0] * _mat[ 0] + _vec[1] * _mat[4] + _vec[2] * _mat[ 8] + _vec[3] * _mat[12];
@@ -1094,75 +1258,37 @@ namespace bx
_result[15] = _a[15];
}
- /// Convert LH to RH projection matrix and vice versa.
- inline void mtxProjFlipHandedness(float* _dst, const float* _src)
+ inline Vec3 calcNormal(const Vec3& _va, const Vec3& _vb, const Vec3& _vc)
{
- _dst[ 0] = -_src[ 0];
- _dst[ 1] = -_src[ 1];
- _dst[ 2] = -_src[ 2];
- _dst[ 3] = -_src[ 3];
- _dst[ 4] = _src[ 4];
- _dst[ 5] = _src[ 5];
- _dst[ 6] = _src[ 6];
- _dst[ 7] = _src[ 7];
- _dst[ 8] = -_src[ 8];
- _dst[ 9] = -_src[ 9];
- _dst[10] = -_src[10];
- _dst[11] = -_src[11];
- _dst[12] = _src[12];
- _dst[13] = _src[13];
- _dst[14] = _src[14];
- _dst[15] = _src[15];
+ const Vec3 ba = sub(_vb, _va);
+ const Vec3 ca = sub(_vc, _va);
+ const Vec3 baxca = cross(ba, ca);
+
+ return normalize(baxca);
}
- /// Convert LH to RH view matrix and vice versa.
- inline void mtxViewFlipHandedness(float* _dst, const float* _src)
+ inline void calcPlane(Plane& _outPlane, const Vec3& _va, const Vec3& _vb, const Vec3& _vc)
{
- _dst[ 0] = -_src[ 0];
- _dst[ 1] = _src[ 1];
- _dst[ 2] = -_src[ 2];
- _dst[ 3] = _src[ 3];
- _dst[ 4] = -_src[ 4];
- _dst[ 5] = _src[ 5];
- _dst[ 6] = -_src[ 6];
- _dst[ 7] = _src[ 7];
- _dst[ 8] = -_src[ 8];
- _dst[ 9] = _src[ 9];
- _dst[10] = -_src[10];
- _dst[11] = _src[11];
- _dst[12] = -_src[12];
- _dst[13] = _src[13];
- _dst[14] = -_src[14];
- _dst[15] = _src[15];
+ Vec3 normal = calcNormal(_va, _vb, _vc);
+ calcPlane(_outPlane, normal, _va);
}
- inline void calcNormal(float _result[3], const float _va[3], const float _vb[3], const float _vc[3])
+ inline void calcPlane(Plane& _outPlane, const Vec3& _normal, const Vec3& _pos)
{
- float ba[3];
- vec3Sub(ba, _vb, _va);
-
- float ca[3];
- vec3Sub(ca, _vc, _va);
-
- float baxca[3];
- vec3Cross(baxca, ba, ca);
-
- vec3Norm(_result, baxca);
+ _outPlane.normal = _normal;
+ _outPlane.dist = -dot(_normal, _pos);
}
- inline void calcPlane(float _result[4], const float _va[3], const float _vb[3], const float _vc[3])
+ inline BX_CONSTEXPR_FUNC float distance(const Plane& _plane, const Vec3& _pos)
{
- float normal[3];
- calcNormal(normal, _va, _vb, _vc);
- calcPlane(_result, normal, _va);
+ return dot(_plane.normal, _pos) + _plane.dist;
}
- inline void calcPlane(float _result[4], const float _normal[3], const float _pos[3])
+ inline BX_CONSTEXPR_FUNC bool isEqual(const Plane& _a, const Plane& _b, float _epsilon)
{
- _result[0] = _normal[0];
- _result[1] = _normal[1];
- _result[2] = _normal[2];
- _result[3] = -vec3Dot(_normal, _pos);
+ return isEqual(_a.normal, _b.normal, _epsilon)
+ && isEqual(_a.dist, _b.dist, _epsilon)
+ ;
}
inline BX_CONST_FUNC float toLinear(float _a)
diff --git a/3rdparty/bx/include/bx/inline/mpscqueue.inl b/3rdparty/bx/include/bx/inline/mpscqueue.inl
index a22cf283815..72747b1bfba 100644
--- a/3rdparty/bx/include/bx/inline/mpscqueue.inl
+++ b/3rdparty/bx/include/bx/inline/mpscqueue.inl
@@ -1,6 +1,6 @@
/*
- * Copyright 2010-2018 Branimir Karadzic. All rights reserved.
- * License: https://github.com/bkaradzic/bx#license-bsd-2-clause
+ * Copyright 2010-2022 Branimir Karadzic. All rights reserved.
+ * License: https://github.com/bkaradzic/bx/blob/master/LICENSE
*/
#ifndef BX_MPSCQUEUE_H_HEADER_GUARD
diff --git a/3rdparty/bx/include/bx/inline/mutex.inl b/3rdparty/bx/include/bx/inline/mutex.inl
index 971ebcaa6a8..007317ebccd 100644
--- a/3rdparty/bx/include/bx/inline/mutex.inl
+++ b/3rdparty/bx/include/bx/inline/mutex.inl
@@ -1,6 +1,6 @@
/*
- * Copyright 2010-2018 Branimir Karadzic. All rights reserved.
- * License: https://github.com/bkaradzic/bx#license-bsd-2-clause
+ * Copyright 2010-2022 Branimir Karadzic. All rights reserved.
+ * License: https://github.com/bkaradzic/bx/blob/master/LICENSE
*/
#ifndef BX_MUTEX_H_HEADER_GUARD
diff --git a/3rdparty/bx/include/bx/inline/os.inl b/3rdparty/bx/include/bx/inline/os.inl
new file mode 100644
index 00000000000..736b1fc83e1
--- /dev/null
+++ b/3rdparty/bx/include/bx/inline/os.inl
@@ -0,0 +1,18 @@
+/*
+ * Copyright 2010-2022 Branimir Karadzic. All rights reserved.
+ * License: https://github.com/bkaradzic/bx/blob/master/LICENSE
+ */
+
+#ifndef BX_H_HEADER_GUARD
+# error "Must be included from bx/os.h!"
+#endif // BX_H_HEADER_GUARD
+
+namespace bx
+{
+ template<typename ProtoT>
+ inline ProtoT dlsym(void* _handle, const StringView& _symbol)
+ {
+ return reinterpret_cast<ProtoT>(dlsym(_handle, _symbol) );
+ }
+
+} // namespace bx
diff --git a/3rdparty/bx/include/bx/inline/pixelformat.inl b/3rdparty/bx/include/bx/inline/pixelformat.inl
index 8ac02813521..0c6a334b4da 100644
--- a/3rdparty/bx/include/bx/inline/pixelformat.inl
+++ b/3rdparty/bx/include/bx/inline/pixelformat.inl
@@ -1,6 +1,6 @@
/*
- * Copyright 2010-2018 Branimir Karadzic. All rights reserved.
- * License: https://github.com/bkaradzic/bx#license-bsd-2-clause
+ * Copyright 2010-2022 Branimir Karadzic. All rights reserved.
+ * License: https://github.com/bkaradzic/bx/blob/master/LICENSE
*/
#ifndef BX_PIXEL_FORMAT_H_HEADER_GUARD
@@ -31,6 +31,23 @@ namespace bx
return max(-1.0f, float(_value) / _scale);
}
+ // A8
+ inline void packA8(void* _dst, const float* _src)
+ {
+ uint8_t* dst = (uint8_t*)_dst;
+ dst[0] = uint8_t(toUnorm(_src[3], 255.0f) );
+ }
+
+ inline void unpackA8(float* _dst, const void* _src)
+ {
+ const uint8_t* src = (const uint8_t*)_src;
+ const float aa = fromUnorm(src[0], 255.0f);
+ _dst[0] = aa;
+ _dst[1] = aa;
+ _dst[2] = aa;
+ _dst[3] = aa;
+ }
+
// R8
inline void packR8(void* _dst, const float* _src)
{
@@ -806,8 +823,8 @@ namespace bx
memCopy(_dst, _src, 16);
}
- // R5G6B5
- inline void packR5G6B5(void* _dst, const float* _src)
+ // B5G6R5
+ inline void packB5G6R5(void* _dst, const float* _src)
{
*( (uint16_t*)_dst) = 0
| uint16_t(toUnorm(_src[0], 31.0f)<<11)
@@ -816,7 +833,7 @@ namespace bx
;
}
- inline void unpackR5G6B5(float* _dst, const void* _src)
+ inline void unpackB5G6R5(float* _dst, const void* _src)
{
uint16_t packed = *( (const uint16_t*)_src);
_dst[0] = float( ( (packed>>11) & 0x1f) ) / 31.0f;
@@ -825,6 +842,25 @@ namespace bx
_dst[3] = 1.0f;
}
+ // R5G6B5
+ inline void packR5G6B5(void* _dst, const float* _src)
+ {
+ *( (uint16_t*)_dst) = 0
+ | uint16_t(toUnorm(_src[0], 31.0f) )
+ | uint16_t(toUnorm(_src[1], 63.0f)<< 5)
+ | uint16_t(toUnorm(_src[2], 31.0f)<<11)
+ ;
+ }
+
+ inline void unpackR5G6B5(float* _dst, const void* _src)
+ {
+ uint16_t packed = *( (const uint16_t*)_src);
+ _dst[0] = float( ( (packed ) & 0x1f) ) / 31.0f;
+ _dst[1] = float( ( (packed>> 5) & 0x3f) ) / 63.0f;
+ _dst[2] = float( ( (packed>>11) & 0x1f) ) / 31.0f;
+ _dst[3] = 1.0f;
+ }
+
// RGBA4
inline void packRgba4(void* _dst, const float* _src)
{
@@ -845,7 +881,7 @@ namespace bx
_dst[3] = float( ( (packed>>12) & 0xf) ) / 15.0f;
}
- // RGBA4
+ // BGRA4
inline void packBgra4(void* _dst, const float* _src)
{
*( (uint16_t*)_dst) = 0
@@ -882,7 +918,7 @@ namespace bx
_dst[0] = float( ( (packed ) & 0x1f) ) / 31.0f;
_dst[1] = float( ( (packed>> 5) & 0x1f) ) / 31.0f;
_dst[2] = float( ( (packed>>10) & 0x1f) ) / 31.0f;
- _dst[3] = float( ( (packed>>14) & 0x1) );
+ _dst[3] = float( ( (packed>>15) & 0x1) );
}
// BGR5A1
@@ -902,7 +938,7 @@ namespace bx
_dst[0] = float( ( (packed>>10) & 0x1f) ) / 31.0f;
_dst[1] = float( ( (packed>> 5) & 0x1f) ) / 31.0f;
_dst[2] = float( ( (packed ) & 0x1f) ) / 31.0f;
- _dst[3] = float( ( (packed>>14) & 0x1) );
+ _dst[3] = float( ( (packed>>15) & 0x1) );
}
// RGB10A2
@@ -930,8 +966,8 @@ namespace bx
{
*( (uint32_t*)_dst) = 0
| ( (halfFromFloat(_src[0])>> 4) & 0x7ff)
- | ( (halfFromFloat(_src[0])<< 7) & 0x3ff800)
- | ( (halfFromFloat(_src[0])<<17) & 0xffc00000)
+ | ( (halfFromFloat(_src[1])<< 7) & 0x3ff800)
+ | ( (halfFromFloat(_src[2])<<17) & 0xffc00000)
;
}
diff --git a/3rdparty/bx/include/bx/inline/readerwriter.inl b/3rdparty/bx/include/bx/inline/readerwriter.inl
index 9a365dcee60..fa9300b7a2d 100644
--- a/3rdparty/bx/include/bx/inline/readerwriter.inl
+++ b/3rdparty/bx/include/bx/inline/readerwriter.inl
@@ -1,6 +1,6 @@
/*
- * Copyright 2010-2018 Branimir Karadzic. All rights reserved.
- * License: https://github.com/bkaradzic/bx#license-bsd-2-clause
+ * Copyright 2010-2022 Branimir Karadzic. All rights reserved.
+ * License: https://github.com/bkaradzic/bx/blob/master/LICENSE
*/
#ifndef BX_READERWRITER_H_HEADER_GUARD
@@ -118,7 +118,7 @@ namespace bx
inline int32_t SizerWriter::write(const void* /*_data*/, int32_t _size, Error* _err)
{
- BX_CHECK(NULL != _err, "Reader/Writer interface calling functions must handle errors.");
+ BX_ASSERT(NULL != _err, "Reader/Writer interface calling functions must handle errors.");
int32_t morecore = int32_t(m_pos - m_top) + _size;
@@ -132,7 +132,7 @@ namespace bx
m_pos += size;
if (size != _size)
{
- BX_ERROR_SET(_err, BX_ERROR_READERWRITER_WRITE, "SizerWriter: write truncated.");
+ BX_ERROR_SET(_err, kErrorReaderWriterWrite, "SizerWriter: write truncated.");
}
return size;
}
@@ -170,7 +170,7 @@ namespace bx
inline int32_t MemoryReader::read(void* _data, int32_t _size, Error* _err)
{
- BX_CHECK(NULL != _err, "Reader/Writer interface calling functions must handle errors.");
+ BX_ASSERT(NULL != _err, "Reader/Writer interface calling functions must handle errors.");
int64_t remainder = m_top-m_pos;
int32_t size = uint32_min(_size, uint32_t(min<int64_t>(remainder, INT32_MAX) ) );
@@ -178,7 +178,7 @@ namespace bx
m_pos += size;
if (size != _size)
{
- BX_ERROR_SET(_err, BX_ERROR_READERWRITER_READ, "MemoryReader: read truncated.");
+ BX_ERROR_SET(_err, kErrorReaderWriterRead, "MemoryReader: read truncated.");
}
return size;
}
@@ -233,13 +233,13 @@ namespace bx
inline int32_t MemoryWriter::write(const void* _data, int32_t _size, Error* _err)
{
- BX_CHECK(NULL != _err, "Reader/Writer interface calling functions must handle errors.");
+ BX_ASSERT(NULL != _err, "Reader/Writer interface calling functions must handle errors.");
int32_t morecore = int32_t(m_pos - m_size) + _size;
if (0 < morecore)
{
- morecore = BX_ALIGN_MASK(morecore, 0xfff);
+ morecore = alignUp(morecore, 0x1000);
m_data = (uint8_t*)m_memBlock->more(morecore);
m_size = m_memBlock->getSize();
}
@@ -251,7 +251,7 @@ namespace bx
m_top = max(m_top, m_pos);
if (size != _size)
{
- BX_ERROR_SET(_err, BX_ERROR_READERWRITER_WRITE, "MemoryWriter: write truncated.");
+ BX_ERROR_SET(_err, kErrorReaderWriterWrite, "MemoryWriter: write truncated.");
}
return size;
}
@@ -273,7 +273,7 @@ namespace bx
}
template<typename Ty>
- int32_t read(ReaderI* _reader, Ty& _value, Error* _err)
+ inline int32_t read(ReaderI* _reader, Ty& _value, Error* _err)
{
BX_ERROR_SCOPE(_err);
BX_STATIC_ASSERT(isTriviallyCopyable<Ty>() );
@@ -281,7 +281,7 @@ namespace bx
}
template<typename Ty>
- int32_t readHE(ReaderI* _reader, Ty& _value, bool _fromLittleEndian, Error* _err)
+ inline int32_t readHE(ReaderI* _reader, Ty& _value, bool _fromLittleEndian, Error* _err)
{
BX_ERROR_SCOPE(_err);
BX_STATIC_ASSERT(isTriviallyCopyable<Ty>() );
@@ -329,7 +329,7 @@ namespace bx
}
template<typename Ty>
- int32_t write(WriterI* _writer, const Ty& _value, Error* _err)
+ inline int32_t write(WriterI* _writer, const Ty& _value, Error* _err)
{
BX_ERROR_SCOPE(_err);
BX_STATIC_ASSERT(isTriviallyCopyable<Ty>() );
@@ -337,7 +337,7 @@ namespace bx
}
template<typename Ty>
- int32_t writeLE(WriterI* _writer, const Ty& _value, Error* _err)
+ inline int32_t writeLE(WriterI* _writer, const Ty& _value, Error* _err)
{
BX_ERROR_SCOPE(_err);
BX_STATIC_ASSERT(isTriviallyCopyable<Ty>() );
@@ -346,8 +346,14 @@ namespace bx
return result;
}
+ template<>
+ inline int32_t writeLE(WriterI* _writer, const float& _value, Error* _err)
+ {
+ return writeLE(_writer, floatToBits(_value), _err);
+ }
+
template<typename Ty>
- int32_t writeBE(WriterI* _writer, const Ty& _value, Error* _err)
+ inline int32_t writeBE(WriterI* _writer, const Ty& _value, Error* _err)
{
BX_ERROR_SCOPE(_err);
BX_STATIC_ASSERT(isTriviallyCopyable<Ty>() );
@@ -356,6 +362,12 @@ namespace bx
return result;
}
+ template<>
+ inline int32_t writeBE(WriterI* _writer, const float& _value, Error* _err)
+ {
+ return writeBE(_writer, floatToBits(_value), _err);
+ }
+
inline int64_t skip(SeekerI* _seeker, int64_t _offset)
{
return _seeker->seek(_offset, Whence::Current);
@@ -392,7 +404,7 @@ namespace bx
}
template<typename Ty>
- int32_t peek(ReaderSeekerI* _reader, Ty& _value, Error* _err)
+ inline int32_t peek(ReaderSeekerI* _reader, Ty& _value, Error* _err)
{
BX_ERROR_SCOPE(_err);
BX_STATIC_ASSERT(isTriviallyCopyable<Ty>() );
@@ -410,7 +422,7 @@ namespace bx
const int64_t offset = bx::seek(_reader, size);
if (offset != aligned)
{
- BX_ERROR_SET(_err, BX_ERROR_READERWRITER_WRITE, "Align: read truncated.");
+ BX_ERROR_SET(_err, kErrorReaderWriterWrite, "Align: read truncated.");
}
return int32_t(offset - current);
}
diff --git a/3rdparty/bx/include/bx/inline/ringbuffer.inl b/3rdparty/bx/include/bx/inline/ringbuffer.inl
index 51f365546db..1c1b7ec44d0 100644
--- a/3rdparty/bx/include/bx/inline/ringbuffer.inl
+++ b/3rdparty/bx/include/bx/inline/ringbuffer.inl
@@ -1,6 +1,6 @@
/*
- * Copyright 2010-2018 Branimir Karadzic. All rights reserved.
- * License: https://github.com/bkaradzic/bx#license-bsd-2-clause
+ * Copyright 2010-2022 Branimir Karadzic. All rights reserved.
+ * License: https://github.com/bkaradzic/bx/blob/master/LICENSE
*/
#ifndef BX_RINGBUFFER_H_HEADER_GUARD
@@ -161,7 +161,7 @@ namespace bx
, m_size(_size)
, m_buffer(_buffer)
{
- BX_CHECK(_control.available() >= _size, "%d >= %d", _control.available(), _size);
+ BX_ASSERT(_control.available() >= _size, "%d >= %d", _control.available(), _size);
}
template <typename ControlT>
@@ -210,7 +210,7 @@ namespace bx
{
uint32_t size = m_control.reserve(_size);
BX_UNUSED(size);
- BX_CHECK(size == _size, "%d == %d", size, _size);
+ BX_ASSERT(size == _size, "%d == %d", size, _size);
m_write = m_control.m_current;
m_end = m_write+_size;
}
diff --git a/3rdparty/bx/include/bx/inline/rng.inl b/3rdparty/bx/include/bx/inline/rng.inl
index 9577bb09aa9..123461ddf7d 100644
--- a/3rdparty/bx/include/bx/inline/rng.inl
+++ b/3rdparty/bx/include/bx/inline/rng.inl
@@ -1,6 +1,6 @@
/*
- * Copyright 2010-2018 Branimir Karadzic. All rights reserved.
- * License: https://github.com/bkaradzic/bx#license-bsd-2-clause
+ * Copyright 2010-2022 Branimir Karadzic. All rights reserved.
+ * License: https://github.com/bkaradzic/bx/blob/master/LICENSE
*/
#ifndef BX_RNG_H_HEADER_GUARD
@@ -103,6 +103,10 @@ namespace bx
inline void generateSphereHammersley(void* _data, uint32_t _stride, uint32_t _num, float _scale)
{
+ // Reference(s):
+ // - Sampling with Hammersley and Halton Points
+ // https://web.archive.org/web/20190207230709/http://www.cse.cuhk.edu.hk/~ttwong/papers/udpoint/udpoints.html
+
uint8_t* data = (uint8_t*)_data;
for (uint32_t ii = 0; ii < _num; ii++)
@@ -133,7 +137,7 @@ namespace bx
template<typename Rng, typename Ty>
inline void shuffle(Rng* _rng, Ty* _array, uint32_t _num)
{
- BX_CHECK(_num != 0, "Number of elements can't be 0!");
+ BX_ASSERT(_num != 0, "Number of elements can't be 0!");
for (uint32_t ii = 0, num = _num-1; ii < num; ++ii)
{
diff --git a/3rdparty/bx/include/bx/inline/simd128_langext.inl b/3rdparty/bx/include/bx/inline/simd128_langext.inl
index ac08ba7f9de..6b94e6125af 100644
--- a/3rdparty/bx/include/bx/inline/simd128_langext.inl
+++ b/3rdparty/bx/include/bx/inline/simd128_langext.inl
@@ -1,6 +1,6 @@
/*
- * Copyright 2010-2018 Branimir Karadzic. All rights reserved.
- * License: https://github.com/bkaradzic/bx#license-bsd-2-clause
+ * Copyright 2010-2022 Branimir Karadzic. All rights reserved.
+ * License: https://github.com/bkaradzic/bx/blob/master/LICENSE
*/
#ifndef BX_SIMD_T_H_HEADER_GUARD
@@ -347,6 +347,14 @@ BX_SIMD128_IMPLEMENT_TEST(xyzw , 0xf);
}
template<>
+ BX_SIMD_FORCE_INLINE simd128_langext_t simd_cmpneq(simd128_langext_t _a, simd128_langext_t _b)
+ {
+ simd128_langext_t result;
+ result.vi = _a.vf != _b.vf;
+ return result;
+ }
+
+ template<>
BX_SIMD_FORCE_INLINE simd128_langext_t simd_cmplt(simd128_langext_t _a, simd128_langext_t _b)
{
simd128_langext_t result;
diff --git a/3rdparty/bx/include/bx/inline/simd128_neon.inl b/3rdparty/bx/include/bx/inline/simd128_neon.inl
index 95107eeaa27..0ba98920da7 100644
--- a/3rdparty/bx/include/bx/inline/simd128_neon.inl
+++ b/3rdparty/bx/include/bx/inline/simd128_neon.inl
@@ -1,6 +1,6 @@
/*
- * Copyright 2010-2018 Branimir Karadzic. All rights reserved.
- * License: https://github.com/bkaradzic/bx#license-bsd-2-clause
+ * Copyright 2010-2022 Branimir Karadzic. All rights reserved.
+ * License: https://github.com/bkaradzic/bx/blob/master/LICENSE
*/
#ifndef BX_SIMD_T_H_HEADER_GUARD
@@ -9,6 +9,15 @@
namespace bx
{
+
+#if BX_COMPILER_CLANG
+# define SHUFFLE_A(_a, _i0, _i1, _i2, _i3) __builtin_shufflevector(_a, _a, _i0, _i1, _i2, _i3 )
+# define SHUFFLE_AB(_a, _b, _i0, _i1, _i2, _i3) __builtin_shufflevector(_a, _b, _i0, _i1, _i2, _i3 )
+#else
+# define SHUFFLE_A(_a, _i0, _i1, _i2, _i3) __builtin_shuffle(_a, (uint32x4_t){ _i0, _i1, _i2, _i3 })
+# define SHUFFLE_AB(_a, _b, _i0, _i1, _i2, _i3) __builtin_shuffle(_a, _b, (uint32x4_t){ _i0, _i1, _i2, _i3 })
+#endif
+
#define ELEMx 0
#define ELEMy 1
#define ELEMz 2
@@ -17,7 +26,7 @@ namespace bx
template<> \
BX_SIMD_FORCE_INLINE simd128_neon_t simd_swiz_##_x##_y##_z##_w(simd128_neon_t _a) \
{ \
- return __builtin_shuffle(_a, (uint32x4_t){ ELEM##_x, ELEM##_y, ELEM##_z, ELEM##_w }); \
+ return SHUFFLE_A(_a, ELEM##_x, ELEM##_y, ELEM##_z, ELEM##_w ); \
}
#include "simd128_swizzle.inl"
@@ -74,50 +83,52 @@ BX_SIMD128_IMPLEMENT_TEST(yzw, yzww);
template<>
BX_SIMD_FORCE_INLINE simd128_neon_t simd_shuf_xyAB(simd128_neon_t _a, simd128_neon_t _b)
{
- return __builtin_shuffle(_a, _b, (uint32x4_t){ 0, 1, 4, 5 });
+ return SHUFFLE_AB(_a, _b, 0, 1, 4, 5 );
}
template<>
BX_SIMD_FORCE_INLINE simd128_neon_t simd_shuf_ABxy(simd128_neon_t _a, simd128_neon_t _b)
{
- return __builtin_shuffle(_a, _b, (uint32x4_t){ 4, 5, 0, 1 });
+ return SHUFFLE_AB(_a, _b, 4, 5, 0, 1 );
}
template<>
BX_SIMD_FORCE_INLINE simd128_neon_t simd_shuf_CDzw(simd128_neon_t _a, simd128_neon_t _b)
{
- return __builtin_shuffle(_a, _b, (uint32x4_t){ 6, 7, 2, 3 });
+ return SHUFFLE_AB(_a, _b, 6, 7, 2, 3 );
}
template<>
BX_SIMD_FORCE_INLINE simd128_neon_t simd_shuf_zwCD(simd128_neon_t _a, simd128_neon_t _b)
{
- return __builtin_shuffle(_a, _b, (uint32x4_t){ 2, 3, 6, 7 });
+ return SHUFFLE_AB(_a, _b, 2, 3, 6, 7 );
}
template<>
BX_SIMD_FORCE_INLINE simd128_neon_t simd_shuf_xAyB(simd128_neon_t _a, simd128_neon_t _b)
{
- return __builtin_shuffle(_a, _b, (uint32x4_t){ 0, 4, 1, 5 });
+ return SHUFFLE_AB(_a, _b, 0, 4, 1, 5 );
}
template<>
BX_SIMD_FORCE_INLINE simd128_neon_t simd_shuf_AxBy(simd128_neon_t _a, simd128_neon_t _b)
{
- return __builtin_shuffle(_a, _b, (uint32x4_t){ 1, 5, 0, 4 });
+ return SHUFFLE_AB(_a, _b, 4, 0, 5, 1 );
}
template<>
BX_SIMD_FORCE_INLINE simd128_neon_t simd_shuf_zCwD(simd128_neon_t _a, simd128_neon_t _b)
{
- return __builtin_shuffle(_a, _b, (uint32x4_t){ 2, 6, 3, 7 });
+ return SHUFFLE_AB(_a, _b, 2, 6, 3, 7 );
}
template<>
BX_SIMD_FORCE_INLINE simd128_neon_t simd_shuf_CzDw(simd128_neon_t _a, simd128_neon_t _b)
{
- return __builtin_shuffle(_a, _b, (uint32x4_t){ 6, 2, 7, 3 });
+ return SHUFFLE_AB(_a, _b, 6, 2, 7, 3 );
}
+#undef SHUFFLE_A
+#undef SHUFFLE_AB
template<>
BX_SIMD_FORCE_INLINE float simd_x(simd128_neon_t _a)
@@ -273,10 +284,16 @@ BX_SIMD128_IMPLEMENT_TEST(yzw, yzww);
}
template<>
+ BX_SIMD_FORCE_INLINE simd128_neon_t simd_cmpneq(simd128_neon_t _a, simd128_neon_t _b)
+ {
+ return simd_cmpneq_ni(_a, _b);
+ }
+
+ template<>
BX_SIMD_FORCE_INLINE simd128_neon_t simd_cmplt(simd128_neon_t _a, simd128_neon_t _b)
{
- const uint32x4_t tmp = vcltq_f32(_a, _b);
- const simd128_neon_t result = vreinterpretq_f32_u32(tmp);
+ const uint32x4_t tmp = vcltq_f32(_a, _b);
+ const simd128_neon_t result = vreinterpretq_f32_u32(tmp);
return result;
}
@@ -284,8 +301,8 @@ BX_SIMD128_IMPLEMENT_TEST(yzw, yzww);
template<>
BX_SIMD_FORCE_INLINE simd128_neon_t simd_cmple(simd128_neon_t _a, simd128_neon_t _b)
{
- const uint32x4_t tmp = vcleq_f32(_a, _b);
- const simd128_neon_t result = vreinterpretq_f32_u32(tmp);
+ const uint32x4_t tmp = vcleq_f32(_a, _b);
+ const simd128_neon_t result = vreinterpretq_f32_u32(tmp);
return result;
}
@@ -293,8 +310,8 @@ BX_SIMD128_IMPLEMENT_TEST(yzw, yzww);
template<>
BX_SIMD_FORCE_INLINE simd128_neon_t simd_cmpgt(simd128_neon_t _a, simd128_neon_t _b)
{
- const uint32x4_t tmp = vcgtq_f32(_a, _b);
- const simd128_neon_t result = vreinterpretq_f32_u32(tmp);
+ const uint32x4_t tmp = vcgtq_f32(_a, _b);
+ const simd128_neon_t result = vreinterpretq_f32_u32(tmp);
return result;
}
@@ -302,8 +319,8 @@ BX_SIMD128_IMPLEMENT_TEST(yzw, yzww);
template<>
BX_SIMD_FORCE_INLINE simd128_neon_t simd_cmpge(simd128_neon_t _a, simd128_neon_t _b)
{
- const uint32x4_t tmp = vcgeq_f32(_a, _b);
- const simd128_neon_t result = vreinterpretq_f32_u32(tmp);
+ const uint32x4_t tmp = vcgeq_f32(_a, _b);
+ const simd128_neon_t result = vreinterpretq_f32_u32(tmp);
return result;
}
@@ -367,6 +384,7 @@ BX_SIMD128_IMPLEMENT_TEST(yzw, yzww);
template<>
BX_SIMD_FORCE_INLINE simd128_neon_t simd_sll(simd128_neon_t _a, int _count)
{
+#if !BX_COMPILER_CLANG
if (__builtin_constant_p(_count) )
{
const uint32x4_t tmp0 = vreinterpretq_u32_f32(_a);
@@ -375,7 +393,7 @@ BX_SIMD128_IMPLEMENT_TEST(yzw, yzww);
return result;
}
-
+#endif
const uint32x4_t tmp0 = vreinterpretq_u32_f32(_a);
const int32x4_t shift = vdupq_n_s32(_count);
const uint32x4_t tmp1 = vshlq_u32(tmp0, shift);
@@ -387,6 +405,7 @@ BX_SIMD128_IMPLEMENT_TEST(yzw, yzww);
template<>
BX_SIMD_FORCE_INLINE simd128_neon_t simd_srl(simd128_neon_t _a, int _count)
{
+#if !BX_COMPILER_CLANG
if (__builtin_constant_p(_count) )
{
const uint32x4_t tmp0 = vreinterpretq_u32_f32(_a);
@@ -395,7 +414,7 @@ BX_SIMD128_IMPLEMENT_TEST(yzw, yzww);
return result;
}
-
+#endif
const uint32x4_t tmp0 = vreinterpretq_u32_f32(_a);
const int32x4_t shift = vdupq_n_s32(-_count);
const uint32x4_t tmp1 = vshlq_u32(tmp0, shift);
@@ -407,6 +426,7 @@ BX_SIMD128_IMPLEMENT_TEST(yzw, yzww);
template<>
BX_SIMD_FORCE_INLINE simd128_neon_t simd_sra(simd128_neon_t _a, int _count)
{
+#if !BX_COMPILER_CLANG
if (__builtin_constant_p(_count) )
{
const int32x4_t tmp0 = vreinterpretq_s32_f32(_a);
@@ -415,7 +435,7 @@ BX_SIMD128_IMPLEMENT_TEST(yzw, yzww);
return result;
}
-
+#endif
const int32x4_t tmp0 = vreinterpretq_s32_f32(_a);
const int32x4_t shift = vdupq_n_s32(-_count);
const int32x4_t tmp1 = vshlq_s32(tmp0, shift);
diff --git a/3rdparty/bx/include/bx/inline/simd128_ref.inl b/3rdparty/bx/include/bx/inline/simd128_ref.inl
index 6895b24f46a..b0a97b0e627 100644
--- a/3rdparty/bx/include/bx/inline/simd128_ref.inl
+++ b/3rdparty/bx/include/bx/inline/simd128_ref.inl
@@ -1,6 +1,6 @@
/*
- * Copyright 2010-2018 Branimir Karadzic. All rights reserved.
- * License: https://github.com/bkaradzic/bx#license-bsd-2-clause
+ * Copyright 2010-2022 Branimir Karadzic. All rights reserved.
+ * License: https://github.com/bkaradzic/bx/blob/master/LICENSE
*/
#ifndef BX_SIMD_T_H_HEADER_GUARD
@@ -59,21 +59,21 @@ namespace bx
return (_mask) == (tmp&(_mask) ); \
}
-BX_SIMD128_IMPLEMENT_TEST(x , 0x1);
-BX_SIMD128_IMPLEMENT_TEST(y , 0x2);
-BX_SIMD128_IMPLEMENT_TEST(xy , 0x3);
-BX_SIMD128_IMPLEMENT_TEST(z , 0x4);
-BX_SIMD128_IMPLEMENT_TEST(xz , 0x5);
-BX_SIMD128_IMPLEMENT_TEST(yz , 0x6);
-BX_SIMD128_IMPLEMENT_TEST(xyz , 0x7);
-BX_SIMD128_IMPLEMENT_TEST(w , 0x8);
-BX_SIMD128_IMPLEMENT_TEST(xw , 0x9);
-BX_SIMD128_IMPLEMENT_TEST(yw , 0xa);
-BX_SIMD128_IMPLEMENT_TEST(xyw , 0xb);
-BX_SIMD128_IMPLEMENT_TEST(zw , 0xc);
-BX_SIMD128_IMPLEMENT_TEST(xzw , 0xd);
-BX_SIMD128_IMPLEMENT_TEST(yzw , 0xe);
-BX_SIMD128_IMPLEMENT_TEST(xyzw , 0xf);
+BX_SIMD128_IMPLEMENT_TEST(x , 0x1)
+BX_SIMD128_IMPLEMENT_TEST(y , 0x2)
+BX_SIMD128_IMPLEMENT_TEST(xy , 0x3)
+BX_SIMD128_IMPLEMENT_TEST(z , 0x4)
+BX_SIMD128_IMPLEMENT_TEST(xz , 0x5)
+BX_SIMD128_IMPLEMENT_TEST(yz , 0x6)
+BX_SIMD128_IMPLEMENT_TEST(xyz , 0x7)
+BX_SIMD128_IMPLEMENT_TEST(w , 0x8)
+BX_SIMD128_IMPLEMENT_TEST(xw , 0x9)
+BX_SIMD128_IMPLEMENT_TEST(yw , 0xa)
+BX_SIMD128_IMPLEMENT_TEST(xyw , 0xb)
+BX_SIMD128_IMPLEMENT_TEST(zw , 0xc)
+BX_SIMD128_IMPLEMENT_TEST(xzw , 0xd)
+BX_SIMD128_IMPLEMENT_TEST(yzw , 0xe)
+BX_SIMD128_IMPLEMENT_TEST(xyzw , 0xf)
#undef BX_SIMD128_IMPLEMENT_TEST
@@ -136,10 +136,10 @@ BX_SIMD128_IMPLEMENT_TEST(xyzw , 0xf);
BX_SIMD_FORCE_INLINE simd128_ref_t simd_shuf_AxBy(simd128_ref_t _a, simd128_ref_t _b)
{
simd128_ref_t result;
- result.uxyzw[0] = _a.uxyzw[1];
- result.uxyzw[1] = _b.uxyzw[1];
- result.uxyzw[2] = _a.uxyzw[0];
- result.uxyzw[3] = _b.uxyzw[0];
+ result.uxyzw[0] = _b.uxyzw[0];
+ result.uxyzw[1] = _a.uxyzw[0];
+ result.uxyzw[2] = _b.uxyzw[1];
+ result.uxyzw[3] = _a.uxyzw[1];
return result;
}
@@ -397,6 +397,17 @@ BX_SIMD128_IMPLEMENT_TEST(xyzw , 0xf);
}
template<>
+ BX_SIMD_FORCE_INLINE simd128_ref_t simd_cmpneq(simd128_ref_t _a, simd128_ref_t _b)
+ {
+ simd128_ref_t result;
+ result.ixyzw[0] = _a.fxyzw[0] != _b.fxyzw[0] ? 0xffffffff : 0x0;
+ result.ixyzw[1] = _a.fxyzw[1] != _b.fxyzw[1] ? 0xffffffff : 0x0;
+ result.ixyzw[2] = _a.fxyzw[2] != _b.fxyzw[2] ? 0xffffffff : 0x0;
+ result.ixyzw[3] = _a.fxyzw[3] != _b.fxyzw[3] ? 0xffffffff : 0x0;
+ return result;
+ }
+
+ template<>
BX_SIMD_FORCE_INLINE simd128_ref_t simd_cmplt(simd128_ref_t _a, simd128_ref_t _b)
{
simd128_ref_t result;
diff --git a/3rdparty/bx/include/bx/inline/simd128_sse.inl b/3rdparty/bx/include/bx/inline/simd128_sse.inl
index 229c1431fe3..c8c2a475e34 100644
--- a/3rdparty/bx/include/bx/inline/simd128_sse.inl
+++ b/3rdparty/bx/include/bx/inline/simd128_sse.inl
@@ -1,6 +1,6 @@
/*
- * Copyright 2010-2018 Branimir Karadzic. All rights reserved.
- * License: https://github.com/bkaradzic/bx#license-bsd-2-clause
+ * Copyright 2010-2022 Branimir Karadzic. All rights reserved.
+ * License: https://github.com/bkaradzic/bx/blob/master/LICENSE
*/
#ifndef BX_SIMD_T_H_HEADER_GUARD
@@ -41,21 +41,21 @@ namespace bx
return (_mask) == (_mm_movemask_ps(_test)&(_mask) ); \
}
-BX_SIMD128_IMPLEMENT_TEST(x , 0x1);
-BX_SIMD128_IMPLEMENT_TEST(y , 0x2);
-BX_SIMD128_IMPLEMENT_TEST(xy , 0x3);
-BX_SIMD128_IMPLEMENT_TEST(z , 0x4);
-BX_SIMD128_IMPLEMENT_TEST(xz , 0x5);
-BX_SIMD128_IMPLEMENT_TEST(yz , 0x6);
-BX_SIMD128_IMPLEMENT_TEST(xyz , 0x7);
-BX_SIMD128_IMPLEMENT_TEST(w , 0x8);
-BX_SIMD128_IMPLEMENT_TEST(xw , 0x9);
-BX_SIMD128_IMPLEMENT_TEST(yw , 0xa);
-BX_SIMD128_IMPLEMENT_TEST(xyw , 0xb);
-BX_SIMD128_IMPLEMENT_TEST(zw , 0xc);
-BX_SIMD128_IMPLEMENT_TEST(xzw , 0xd);
-BX_SIMD128_IMPLEMENT_TEST(yzw , 0xe);
-BX_SIMD128_IMPLEMENT_TEST(xyzw , 0xf);
+BX_SIMD128_IMPLEMENT_TEST(x , 0x1)
+BX_SIMD128_IMPLEMENT_TEST(y , 0x2)
+BX_SIMD128_IMPLEMENT_TEST(xy , 0x3)
+BX_SIMD128_IMPLEMENT_TEST(z , 0x4)
+BX_SIMD128_IMPLEMENT_TEST(xz , 0x5)
+BX_SIMD128_IMPLEMENT_TEST(yz , 0x6)
+BX_SIMD128_IMPLEMENT_TEST(xyz , 0x7)
+BX_SIMD128_IMPLEMENT_TEST(w , 0x8)
+BX_SIMD128_IMPLEMENT_TEST(xw , 0x9)
+BX_SIMD128_IMPLEMENT_TEST(yw , 0xa)
+BX_SIMD128_IMPLEMENT_TEST(xyw , 0xb)
+BX_SIMD128_IMPLEMENT_TEST(zw , 0xc)
+BX_SIMD128_IMPLEMENT_TEST(xzw , 0xd)
+BX_SIMD128_IMPLEMENT_TEST(yzw , 0xe)
+BX_SIMD128_IMPLEMENT_TEST(xyzw , 0xf)
#undef BX_SIMD128_IMPLEMENT_TEST
@@ -309,6 +309,12 @@ BX_SIMD128_IMPLEMENT_TEST(xyzw , 0xf);
}
template<>
+ BX_SIMD_FORCE_INLINE simd128_sse_t simd_cmpneq(simd128_sse_t _a, simd128_sse_t _b)
+ {
+ return _mm_cmpneq_ps(_a, _b);
+ }
+
+ template<>
BX_SIMD_FORCE_INLINE simd128_sse_t simd_cmplt(simd128_sse_t _a, simd128_sse_t _b)
{
return _mm_cmplt_ps(_a, _b);
diff --git a/3rdparty/bx/include/bx/inline/simd128_swizzle.inl b/3rdparty/bx/include/bx/inline/simd128_swizzle.inl
index b1ff9a0d183..34ac39b7e57 100644
--- a/3rdparty/bx/include/bx/inline/simd128_swizzle.inl
+++ b/3rdparty/bx/include/bx/inline/simd128_swizzle.inl
@@ -1,6 +1,6 @@
/*
* Copyright 2010-2015 Branimir Karadzic. All rights reserved.
- * License: https://github.com/bkaradzic/bx#license-bsd-2-clause
+ * License: https://github.com/bkaradzic/bx/blob/master/LICENSE
*/
#ifndef BX_SIMD_T_H_HEADER_GUARD
diff --git a/3rdparty/bx/include/bx/inline/simd256_avx.inl b/3rdparty/bx/include/bx/inline/simd256_avx.inl
index 4dd9c666f71..1dce947c79b 100644
--- a/3rdparty/bx/include/bx/inline/simd256_avx.inl
+++ b/3rdparty/bx/include/bx/inline/simd256_avx.inl
@@ -1,6 +1,6 @@
/*
- * Copyright 2010-2018 Branimir Karadzic. All rights reserved.
- * License: https://github.com/bkaradzic/bx#license-bsd-2-clause
+ * Copyright 2010-2022 Branimir Karadzic. All rights reserved.
+ * License: https://github.com/bkaradzic/bx/blob/master/LICENSE
*/
#ifndef BX_SIMD_T_H_HEADER_GUARD
diff --git a/3rdparty/bx/include/bx/inline/simd256_ref.inl b/3rdparty/bx/include/bx/inline/simd256_ref.inl
index 0c84d9d82a0..f27204780b3 100644
--- a/3rdparty/bx/include/bx/inline/simd256_ref.inl
+++ b/3rdparty/bx/include/bx/inline/simd256_ref.inl
@@ -1,6 +1,6 @@
/*
- * Copyright 2010-2018 Branimir Karadzic. All rights reserved.
- * License: https://github.com/bkaradzic/bx#license-bsd-2-clause
+ * Copyright 2010-2022 Branimir Karadzic. All rights reserved.
+ * License: https://github.com/bkaradzic/bx/blob/master/LICENSE
*/
#ifndef BX_SIMD_T_H_HEADER_GUARD
diff --git a/3rdparty/bx/include/bx/inline/simd_ni.inl b/3rdparty/bx/include/bx/inline/simd_ni.inl
index eb388513e88..579bb0bc21f 100644
--- a/3rdparty/bx/include/bx/inline/simd_ni.inl
+++ b/3rdparty/bx/include/bx/inline/simd_ni.inl
@@ -1,6 +1,6 @@
/*
- * Copyright 2010-2018 Branimir Karadzic. All rights reserved.
- * License: https://github.com/bkaradzic/bx#license-bsd-2-clause
+ * Copyright 2010-2022 Branimir Karadzic. All rights reserved.
+ * License: https://github.com/bkaradzic/bx/blob/master/LICENSE
*/
namespace bx
@@ -125,6 +125,15 @@ namespace bx
}
template<typename Ty>
+ BX_SIMD_INLINE Ty simd_cmpneq_ni(Ty _a, Ty _b)
+ {
+ const Ty tmp0 = simd_cmpeq(_a, _b);
+ const Ty result = simd_not(tmp0);
+
+ return result;
+ }
+
+ template<typename Ty>
BX_SIMD_INLINE Ty simd_min_ni(Ty _a, Ty _b)
{
const Ty mask = simd_cmplt(_a, _b);
diff --git a/3rdparty/bx/include/bx/inline/sort.inl b/3rdparty/bx/include/bx/inline/sort.inl
index 27a085362da..ed72c3a3293 100644
--- a/3rdparty/bx/include/bx/inline/sort.inl
+++ b/3rdparty/bx/include/bx/inline/sort.inl
@@ -1,6 +1,6 @@
/*
- * Copyright 2010-2018 Branimir Karadzic. All rights reserved.
- * License: https://github.com/bkaradzic/bx#license-bsd-2-clause
+ * Copyright 2010-2022 Branimir Karadzic. All rights reserved.
+ * License: https://github.com/bkaradzic/bx/blob/master/LICENSE
*/
#ifndef BX_SORT_H_HEADER_GUARD
@@ -9,21 +9,127 @@
namespace bx
{
-#define BX_RADIXSORT_BITS 11
-#define BX_RADIXSORT_HISTOGRAM_SIZE (1<<BX_RADIXSORT_BITS)
-#define BX_RADIXSORT_BIT_MASK (BX_RADIXSORT_HISTOGRAM_SIZE-1)
+ template<typename Ty>
+ inline int32_t compareAscending(const void* _lhs, const void* _rhs)
+ {
+ const Ty lhs = *static_cast<const Ty*>(_lhs);
+ const Ty rhs = *static_cast<const Ty*>(_rhs);
+ return (lhs > rhs) - (lhs < rhs);
+ }
+
+ template<typename Ty>
+ inline int32_t compareDescending(const void* _lhs, const void* _rhs)
+ {
+ return compareAscending<Ty>(_rhs, _lhs);
+ }
+
+ template<>
+ inline int32_t compareAscending<const char*>(const void* _lhs, const void* _rhs)
+ {
+ return strCmp(*(const char**)_lhs, *(const char**)_rhs);
+ }
+
+ template<>
+ inline int32_t compareAscending<StringView>(const void* _lhs, const void* _rhs)
+ {
+ return strCmp(*(const StringView*)_lhs, *(const StringView*)_rhs);
+ }
+
+ template<typename Ty>
+ inline void quickSort(void* _data, uint32_t _num, uint32_t _stride, const ComparisonFn _fn)
+ {
+ BX_STATIC_ASSERT(isTriviallyMoveAssignable<Ty>(), "Element type must be trivially move assignable");
+ quickSort(_data, _num, _stride, _fn);
+ }
+
+ template<typename Ty>
+ inline void quickSort(Ty* _data, uint32_t _num, const ComparisonFn _fn)
+ {
+ BX_STATIC_ASSERT(isTriviallyMoveAssignable<Ty>(), "Element type must be trivially move assignable");
+ quickSort( (void*)_data, _num, sizeof(Ty), _fn);
+ }
+
+ template<typename Ty>
+ inline uint32_t unique(void* _data, uint32_t _num, uint32_t _stride, const ComparisonFn _fn)
+ {
+ BX_STATIC_ASSERT(isTriviallyMoveAssignable<Ty>(), "Element type must be trivially move assignable");
+ return unique(_data, _num, _stride, _fn);
+ }
+
+ template<typename Ty>
+ inline uint32_t unique(Ty* _data, uint32_t _num, const ComparisonFn _fn)
+ {
+ BX_STATIC_ASSERT(isTriviallyMoveAssignable<Ty>(), "Element type must be trivially move assignable");
+ return unique( (void*)_data, _num, sizeof(Ty), _fn);
+ }
+
+ template<typename Ty>
+ inline uint32_t lowerBound(const Ty& _key, const Ty* _data, uint32_t _num, const ComparisonFn _fn)
+ {
+ return lowerBound( (const void*)&_key, _data, _num, sizeof(Ty), _fn);
+ }
+
+ template<typename Ty>
+ inline uint32_t lowerBound(const Ty& _key, const void* _data, uint32_t _num, uint32_t _stride, const ComparisonFn _fn)
+ {
+ return lowerBound( (const void*)&_key, _data, _num, _stride, _fn);
+ }
+
+ template<typename Ty>
+ inline uint32_t upperBound(const Ty& _key, const Ty* _data, uint32_t _num, const ComparisonFn _fn)
+ {
+ return upperBound( (const void*)&_key, _data, _num, sizeof(Ty), _fn);
+ }
+
+ template<typename Ty>
+ inline uint32_t upperBound(const Ty& _key, const void* _data, uint32_t _num, uint32_t _stride, const ComparisonFn _fn)
+ {
+ return upperBound( (const void*)&_key, _data, _num, _stride, _fn);
+ }
+
+ template<typename Ty>
+ inline bool isSorted(const Ty* _data, uint32_t _num, const ComparisonFn _fn)
+ {
+ return isSorted(_data, _num, sizeof(Ty), _fn);
+ }
+
+ template<typename Ty>
+ inline bool isSorted(const void* _data, uint32_t _num, uint32_t _stride, const ComparisonFn _fn)
+ {
+ return isSorted(_data, _num, _stride, _fn);
+ }
+
+ template<typename Ty>
+ inline int32_t binarySearch(const Ty& _key, const Ty* _data, uint32_t _num, const ComparisonFn _fn)
+ {
+ return binarySearch( (const void*)&_key, _data, _num, sizeof(Ty), _fn);
+ }
+
+ template<typename Ty>
+ inline int32_t binarySearch(const Ty& _key, const void* _data, uint32_t _num, uint32_t _stride, const ComparisonFn _fn)
+ {
+ return binarySearch( (const void*)&_key, _data, _num, _stride, _fn);
+ }
+
+ namespace radix_sort_detail
+ {
+ constexpr uint32_t kBits = 11;
+ constexpr uint32_t kHistogramSize = 1<<kBits;
+ constexpr uint32_t kBitMask = kHistogramSize-1;
+
+ } // namespace radix_sort_detail
inline void radixSort(uint32_t* _keys, uint32_t* _tempKeys, uint32_t _size)
{
uint32_t* keys = _keys;
uint32_t* tempKeys = _tempKeys;
- uint32_t histogram[BX_RADIXSORT_HISTOGRAM_SIZE];
+ uint32_t histogram[radix_sort_detail::kHistogramSize];
uint16_t shift = 0;
uint32_t pass = 0;
for (; pass < 3; ++pass)
{
- memSet(histogram, 0, sizeof(uint32_t)*BX_RADIXSORT_HISTOGRAM_SIZE);
+ memSet(histogram, 0, sizeof(uint32_t)*radix_sort_detail::kHistogramSize);
bool sorted = true;
{
@@ -32,7 +138,7 @@ namespace bx
for (uint32_t ii = 0; ii < _size; ++ii, prevKey = key)
{
key = keys[ii];
- uint16_t index = (key>>shift)&BX_RADIXSORT_BIT_MASK;
+ uint16_t index = (key>>shift)&radix_sort_detail::kBitMask;
++histogram[index];
sorted &= prevKey <= key;
}
@@ -44,7 +150,7 @@ namespace bx
}
uint32_t offset = 0;
- for (uint32_t ii = 0; ii < BX_RADIXSORT_HISTOGRAM_SIZE; ++ii)
+ for (uint32_t ii = 0; ii < radix_sort_detail::kHistogramSize; ++ii)
{
uint32_t count = histogram[ii];
histogram[ii] = offset;
@@ -54,7 +160,7 @@ namespace bx
for (uint32_t ii = 0; ii < _size; ++ii)
{
uint32_t key = keys[ii];
- uint16_t index = (key>>shift)&BX_RADIXSORT_BIT_MASK;
+ uint16_t index = (key>>shift)&radix_sort_detail::kBitMask;
uint32_t dest = histogram[index]++;
tempKeys[dest] = key;
}
@@ -63,7 +169,7 @@ namespace bx
tempKeys = keys;
keys = swapKeys;
- shift += BX_RADIXSORT_BITS;
+ shift += radix_sort_detail::kBits;
}
done:
@@ -77,17 +183,19 @@ done:
template <typename Ty>
inline void radixSort(uint32_t* _keys, uint32_t* _tempKeys, Ty* _values, Ty* _tempValues, uint32_t _size)
{
+ BX_STATIC_ASSERT(isTriviallyMoveAssignable<Ty>(), "Sort element type must be trivially move assignable");
+
uint32_t* keys = _keys;
uint32_t* tempKeys = _tempKeys;
Ty* values = _values;
Ty* tempValues = _tempValues;
- uint32_t histogram[BX_RADIXSORT_HISTOGRAM_SIZE];
+ uint32_t histogram[radix_sort_detail::kHistogramSize];
uint16_t shift = 0;
uint32_t pass = 0;
for (; pass < 3; ++pass)
{
- memSet(histogram, 0, sizeof(uint32_t)*BX_RADIXSORT_HISTOGRAM_SIZE);
+ memSet(histogram, 0, sizeof(uint32_t)*radix_sort_detail::kHistogramSize);
bool sorted = true;
{
@@ -96,7 +204,7 @@ done:
for (uint32_t ii = 0; ii < _size; ++ii, prevKey = key)
{
key = keys[ii];
- uint16_t index = (key>>shift)&BX_RADIXSORT_BIT_MASK;
+ uint16_t index = (key>>shift)&radix_sort_detail::kBitMask;
++histogram[index];
sorted &= prevKey <= key;
}
@@ -108,7 +216,7 @@ done:
}
uint32_t offset = 0;
- for (uint32_t ii = 0; ii < BX_RADIXSORT_HISTOGRAM_SIZE; ++ii)
+ for (uint32_t ii = 0; ii < radix_sort_detail::kHistogramSize; ++ii)
{
uint32_t count = histogram[ii];
histogram[ii] = offset;
@@ -118,7 +226,7 @@ done:
for (uint32_t ii = 0; ii < _size; ++ii)
{
uint32_t key = keys[ii];
- uint16_t index = (key>>shift)&BX_RADIXSORT_BIT_MASK;
+ uint16_t index = (key>>shift)&radix_sort_detail::kBitMask;
uint32_t dest = histogram[index]++;
tempKeys[dest] = key;
tempValues[dest] = values[ii];
@@ -132,7 +240,7 @@ done:
tempValues = values;
values = swapValues;
- shift += BX_RADIXSORT_BITS;
+ shift += radix_sort_detail::kBits;
}
done:
@@ -152,12 +260,12 @@ done:
uint64_t* keys = _keys;
uint64_t* tempKeys = _tempKeys;
- uint32_t histogram[BX_RADIXSORT_HISTOGRAM_SIZE];
+ uint32_t histogram[radix_sort_detail::kHistogramSize];
uint16_t shift = 0;
uint32_t pass = 0;
for (; pass < 6; ++pass)
{
- memSet(histogram, 0, sizeof(uint32_t)*BX_RADIXSORT_HISTOGRAM_SIZE);
+ memSet(histogram, 0, sizeof(uint32_t)*radix_sort_detail::kHistogramSize);
bool sorted = true;
{
@@ -166,7 +274,7 @@ done:
for (uint32_t ii = 0; ii < _size; ++ii, prevKey = key)
{
key = keys[ii];
- uint16_t index = (key>>shift)&BX_RADIXSORT_BIT_MASK;
+ uint16_t index = (key>>shift)&radix_sort_detail::kBitMask;
++histogram[index];
sorted &= prevKey <= key;
}
@@ -178,7 +286,7 @@ done:
}
uint32_t offset = 0;
- for (uint32_t ii = 0; ii < BX_RADIXSORT_HISTOGRAM_SIZE; ++ii)
+ for (uint32_t ii = 0; ii < radix_sort_detail::kHistogramSize; ++ii)
{
uint32_t count = histogram[ii];
histogram[ii] = offset;
@@ -188,7 +296,7 @@ done:
for (uint32_t ii = 0; ii < _size; ++ii)
{
uint64_t key = keys[ii];
- uint16_t index = (key>>shift)&BX_RADIXSORT_BIT_MASK;
+ uint16_t index = (key>>shift)&radix_sort_detail::kBitMask;
uint32_t dest = histogram[index]++;
tempKeys[dest] = key;
}
@@ -197,7 +305,7 @@ done:
tempKeys = keys;
keys = swapKeys;
- shift += BX_RADIXSORT_BITS;
+ shift += radix_sort_detail::kBits;
}
done:
@@ -211,17 +319,19 @@ done:
template <typename Ty>
inline void radixSort(uint64_t* _keys, uint64_t* _tempKeys, Ty* _values, Ty* _tempValues, uint32_t _size)
{
+ BX_STATIC_ASSERT(isTriviallyMoveAssignable<Ty>(), "Sort element type must be trivially move assignable");
+
uint64_t* keys = _keys;
uint64_t* tempKeys = _tempKeys;
Ty* values = _values;
Ty* tempValues = _tempValues;
- uint32_t histogram[BX_RADIXSORT_HISTOGRAM_SIZE];
+ uint32_t histogram[radix_sort_detail::kHistogramSize];
uint16_t shift = 0;
uint32_t pass = 0;
for (; pass < 6; ++pass)
{
- memSet(histogram, 0, sizeof(uint32_t)*BX_RADIXSORT_HISTOGRAM_SIZE);
+ memSet(histogram, 0, sizeof(uint32_t)*radix_sort_detail::kHistogramSize);
bool sorted = true;
{
@@ -230,7 +340,7 @@ done:
for (uint32_t ii = 0; ii < _size; ++ii, prevKey = key)
{
key = keys[ii];
- uint16_t index = (key>>shift)&BX_RADIXSORT_BIT_MASK;
+ uint16_t index = (key>>shift)&radix_sort_detail::kBitMask;
++histogram[index];
sorted &= prevKey <= key;
}
@@ -242,7 +352,7 @@ done:
}
uint32_t offset = 0;
- for (uint32_t ii = 0; ii < BX_RADIXSORT_HISTOGRAM_SIZE; ++ii)
+ for (uint32_t ii = 0; ii < radix_sort_detail::kHistogramSize; ++ii)
{
uint32_t count = histogram[ii];
histogram[ii] = offset;
@@ -252,7 +362,7 @@ done:
for (uint32_t ii = 0; ii < _size; ++ii)
{
uint64_t key = keys[ii];
- uint16_t index = (key>>shift)&BX_RADIXSORT_BIT_MASK;
+ uint16_t index = (key>>shift)&radix_sort_detail::kBitMask;
uint32_t dest = histogram[index]++;
tempKeys[dest] = key;
tempValues[dest] = values[ii];
@@ -266,7 +376,7 @@ done:
tempValues = values;
values = swapValues;
- shift += BX_RADIXSORT_BITS;
+ shift += radix_sort_detail::kBits;
}
done:
@@ -281,8 +391,4 @@ done:
}
}
-#undef BX_RADIXSORT_BITS
-#undef BX_RADIXSORT_HISTOGRAM_SIZE
-#undef BX_RADIXSORT_BIT_MASK
-
} // namespace bx
diff --git a/3rdparty/bx/include/bx/inline/spscqueue.inl b/3rdparty/bx/include/bx/inline/spscqueue.inl
index e0fae02ef29..9db8b748d70 100644
--- a/3rdparty/bx/include/bx/inline/spscqueue.inl
+++ b/3rdparty/bx/include/bx/inline/spscqueue.inl
@@ -1,6 +1,6 @@
/*
- * Copyright 2010-2018 Branimir Karadzic. All rights reserved.
- * License: https://github.com/bkaradzic/bx#license-bsd-2-clause
+ * Copyright 2010-2022 Branimir Karadzic. All rights reserved.
+ * License: https://github.com/bkaradzic/bx/blob/master/LICENSE
*/
#ifndef BX_SPSCQUEUE_H_HEADER_GUARD
@@ -9,7 +9,10 @@
namespace bx
{
- // http://drdobbs.com/article/print?articleId=210604448&siteSectionName=
+ // Reference(s):
+ // - Writing Lock-Free Code: A Corrected Queue
+ // https://web.archive.org/web/20190207230604/http://www.drdobbs.com/parallel/writing-lock-free-code-a-corrected-queue/210604448
+ //
inline SpScUnboundedQueue::SpScUnboundedQueue(AllocatorI* _allocator)
: m_allocator(_allocator)
, m_first(BX_NEW(m_allocator, Node)(NULL) )
diff --git a/3rdparty/bx/include/bx/inline/string.inl b/3rdparty/bx/include/bx/inline/string.inl
index a387128679e..a696f342ff3 100644
--- a/3rdparty/bx/include/bx/inline/string.inl
+++ b/3rdparty/bx/include/bx/inline/string.inl
@@ -1,6 +1,6 @@
/*
- * Copyright 2010-2018 Branimir Karadzic. All rights reserved.
- * License: https://github.com/bkaradzic/bx#license-bsd-2-clause
+ * Copyright 2010-2022 Branimir Karadzic. All rights reserved.
+ * License: https://github.com/bkaradzic/bx/blob/master/LICENSE
*/
#ifndef BX_STRING_H_HEADER_GUARD
@@ -37,22 +37,6 @@ namespace bx
va_end(argList);
}
- template <typename Ty>
- inline Ty replaceAll(const Ty& _str, const char* _from, const char* _to)
- {
- Ty str = _str;
- typename Ty::size_type startPos = 0;
- const typename Ty::size_type fromLen = strLen(_from);
- const typename Ty::size_type toLen = strLen(_to);
- while ( (startPos = str.find(_from, startPos) ) != Ty::npos)
- {
- str.replace(startPos, fromLen, _to);
- startPos += toLen;
- }
-
- return str;
- }
-
inline StringView::StringView()
{
clear();
@@ -75,21 +59,11 @@ namespace bx
return *this;
}
- inline StringView::StringView(char* _ptr)
- {
- set(_ptr, INT32_MAX);
- }
-
inline StringView::StringView(const char* _ptr)
{
set(_ptr, INT32_MAX);
}
- inline StringView::StringView(char* _ptr, int32_t _len)
- {
- set(_ptr, _len);
- }
-
inline StringView::StringView(const char* _ptr, int32_t _len)
{
set(_ptr, _len);
@@ -100,17 +74,6 @@ namespace bx
set(_ptr, _term);
}
- template<typename Ty>
- inline StringView::StringView(const Ty& _container)
- {
- set(_container);
- }
-
- inline void StringView::set(char* _ptr)
- {
- set(_ptr, INT32_MAX);
- }
-
inline void StringView::set(const char* _ptr)
{
set(_ptr, INT32_MAX);
@@ -124,6 +87,7 @@ namespace bx
{
m_len = INT32_MAX == _len ? strLen(_ptr) : _len;
m_ptr = _ptr;
+ m_0terminated = INT32_MAX == _len;
}
}
@@ -132,12 +96,6 @@ namespace bx
set(_ptr, int32_t(_term-_ptr) );
}
- template<typename Ty>
- inline void StringView::set(const Ty& _container)
- {
- set(_container.data(), int32_t(_container.length() ) );
- }
-
inline void StringView::set(const StringView& _str, int32_t _start, int32_t _len)
{
const int32_t start = min(_start, _str.m_len);
@@ -149,6 +107,7 @@ namespace bx
{
m_ptr = "";
m_len = 0;
+ m_0terminated = true;
}
inline const char* StringView::getPtr() const
@@ -171,36 +130,46 @@ namespace bx
return m_len;
}
+ inline bool StringView::is0Terminated() const
+ {
+ return m_0terminated;
+ }
+
template<bx::AllocatorI** AllocatorT>
inline StringT<AllocatorT>::StringT()
: StringView()
+ , m_capacity(0)
{
+ clear();
}
template<bx::AllocatorI** AllocatorT>
inline StringT<AllocatorT>::StringT(const StringT<AllocatorT>& _rhs)
: StringView()
+ , m_capacity(0)
{
set(_rhs);
}
template<bx::AllocatorI** AllocatorT>
- inline StringT<AllocatorT>& StringT<AllocatorT>::operator=(const StringT<AllocatorT>& _rhs)
+ inline StringT<AllocatorT>::StringT(const StringView& _rhs)
+ : StringView()
+ , m_capacity(0)
{
set(_rhs);
- return *this;
}
template<bx::AllocatorI** AllocatorT>
- inline StringT<AllocatorT>::StringT(const StringView& _rhs)
+ inline StringT<AllocatorT>::~StringT()
{
- set(_rhs);
+ clear();
}
template<bx::AllocatorI** AllocatorT>
- inline StringT<AllocatorT>::~StringT()
+ inline StringT<AllocatorT>& StringT<AllocatorT>::operator=(const StringT<AllocatorT>& _rhs)
{
- clear();
+ set(_rhs);
+ return *this;
}
template<bx::AllocatorI** AllocatorT>
@@ -215,30 +184,129 @@ namespace bx
{
if (0 != _str.getLength() )
{
- int32_t old = m_len;
- int32_t len = m_len + strLen(_str);
- char* ptr = (char*)BX_REALLOC(*AllocatorT, 0 != m_len ? const_cast<char*>(m_ptr) : NULL, len+1);
+ const int32_t old = m_len;
+ const int32_t len = m_len + _str.getLength();
+
+ char* ptr = const_cast<char*>(m_ptr);
+
+ if (len+1 > m_capacity)
+ {
+ const int32_t capacity = alignUp(len+1, 256);
+ ptr = (char*)BX_REALLOC(*AllocatorT, 0 != m_capacity ? ptr : NULL, capacity);
+
+ *const_cast<char**>(&m_ptr) = ptr;
+ m_capacity = capacity;
+ }
+
m_len = len;
strCopy(ptr + old, len-old+1, _str);
-
- *const_cast<char**>(&m_ptr) = ptr;
}
}
template<bx::AllocatorI** AllocatorT>
+ inline void StringT<AllocatorT>::append(const char* _ptr, const char* _term)
+ {
+ append(StringView(_ptr, _term) );
+ }
+
+ template<bx::AllocatorI** AllocatorT>
inline void StringT<AllocatorT>::clear()
{
- if (0 != m_len)
+ m_0terminated = true;
+
+ if (0 != m_capacity)
{
BX_FREE(*AllocatorT, const_cast<char*>(m_ptr) );
StringView::clear();
+ m_capacity = 0;
}
}
+ template<bx::AllocatorI** AllocatorT>
+ inline const char* StringT<AllocatorT>::getCPtr() const
+ {
+ return getPtr();
+ }
+
inline StringView strSubstr(const StringView& _str, int32_t _start, int32_t _len)
{
return StringView(_str, _start, _len);
}
+ inline LineReader::LineReader(const bx::StringView& _str)
+ : m_str(_str)
+ {
+ reset();
+ }
+
+ inline void LineReader::reset()
+ {
+ m_curr = m_str;
+ m_line = 0;
+ }
+
+ inline StringView LineReader::next()
+ {
+ if (m_curr.getPtr() != m_str.getTerm() )
+ {
+ ++m_line;
+
+ StringView curr(m_curr);
+ m_curr = bx::strFindNl(m_curr);
+
+ StringView line(curr.getPtr(), m_curr.getPtr() );
+
+ return strRTrim(strRTrim(line, "\n"), "\r");
+ }
+
+ return m_curr;
+ }
+
+ inline bool LineReader::isDone() const
+ {
+ return m_curr.getPtr() == m_str.getTerm();
+ }
+
+ inline uint32_t LineReader::getLine() const
+ {
+ return m_line;
+ }
+
+ inline bool hasPrefix(const StringView& _str, const StringView& _prefix)
+ {
+ const int32_t len = _prefix.getLength();
+ return _str.getLength() >= len
+ && 0 == strCmp(_str, _prefix, len)
+ ;
+ }
+
+ inline bool hasSuffix(const StringView& _str, const StringView& _suffix)
+ {
+ const int32_t len = _suffix.getLength();
+ return _str.getLength() >= len
+ && 0 == strCmp(StringView(_str.getTerm() - len, _str.getTerm() ), _suffix, len)
+ ;
+ }
+
+ inline StringView strTrimPrefix(const StringView& _str, const StringView& _prefix)
+ {
+ if (hasPrefix(_str, _prefix) )
+ {
+ return StringView(_str.getPtr() + _prefix.getLength(), _str.getTerm() );
+ }
+
+ return _str;
+ }
+
+ inline StringView strTrimSuffix(const StringView& _str, const StringView& _suffix)
+ {
+ if (hasSuffix(_str, _suffix) )
+ {
+ return StringView(_str.getPtr(), _str.getTerm() - _suffix.getLength() );
+ }
+
+ return _str;
+ }
+
} // namespace bx
diff --git a/3rdparty/bx/include/bx/inline/typetraits.inl b/3rdparty/bx/include/bx/inline/typetraits.inl
new file mode 100644
index 00000000000..3af6a05143b
--- /dev/null
+++ b/3rdparty/bx/include/bx/inline/typetraits.inl
@@ -0,0 +1,462 @@
+/*
+ * Copyright 2010-2022 Branimir Karadzic. All rights reserved.
+ * License: https://github.com/bkaradzic/bx/blob/master/LICENSE
+ */
+
+#ifndef BX_TYPETRAITS_H_HEADER_GUARD
+# error "Must be included from bx/typetraits.h!"
+#endif // BX_TYPETRAITS_H_HEADER_GUARD
+
+namespace bx
+{
+ // Reference(s):
+ //
+ // - GCC type traits compiler intrisics
+ // https://gcc.gnu.org/onlinedocs/gcc-11.1.0/gcc/Type-Traits.html
+ //
+ // - Clang type trait primitives
+ // https://clang.llvm.org/docs/LanguageExtensions.html#type-trait-primitives
+
+ //---
+ template<typename Ty, Ty ValueT>
+ struct IntegralConstantT
+ {
+ using ValueType = Ty;
+ static constexpr Ty value = ValueT;
+ };
+
+ template<bool BoolT>
+ using BoolConstantT = IntegralConstantT<bool, BoolT>;
+ using FalseConstant = BoolConstantT<false>;
+ using TrueConstant = BoolConstantT<true >;
+
+ //---
+ template<typename Ty> struct TypeIdentityT { using Type = Ty; };
+ template<typename Ty> using TypeIdentityType = typename TypeIdentityT<Ty>::Type;
+
+ //---
+ template<bool BoolT, typename Ty, typename Uy> struct ConditionalT { using Type = Ty; };
+ template< typename Ty, typename Uy> struct ConditionalT<false, Ty, Uy> { using Type = Uy; };
+ template<bool BoolT, typename Ty, typename Uy> using ConditionalType = typename ConditionalT<BoolT, Ty, Uy>::Type;
+
+ //---
+ template<bool BoolT, typename Ty = void> struct EnableIfT { };
+ template< typename Ty > struct EnableIfT<true, Ty> { using Type = Ty; };
+ template<bool BoolT, typename Ty > using EnableIfType = typename EnableIfT<BoolT, Ty>::Type;
+
+ //---
+ template<typename Ty> struct AddLvalueReferenceT { using Type = Ty&; };
+ template<typename Ty> struct AddLvalueReferenceT<Ty&> { using Type = Ty&; };
+ template<> struct AddLvalueReferenceT< void> { using Type = void; };
+ template<> struct AddLvalueReferenceT<const void> { using Type = const void; };
+ template<> struct AddLvalueReferenceT<volatile void> { using Type = volatile void; };
+ template<> struct AddLvalueReferenceT<const volatile void> { using Type = const volatile void; };
+ template<typename Ty> using AddLvalueReferenceType = typename AddLvalueReferenceT<Ty>::Type;
+
+ //---
+ template<typename Ty> struct AddRvalueReferenceT { using Type = Ty&&; };
+ template<typename Ty> struct AddRvalueReferenceT<Ty&> { using Type = Ty&; };
+ template<> struct AddRvalueReferenceT< void> { using Type = void; };
+ template<> struct AddRvalueReferenceT<const void> { using Type = const void; };
+ template<> struct AddRvalueReferenceT<volatile void> { using Type = volatile void; };
+ template<> struct AddRvalueReferenceT<const volatile void> { using Type = const volatile void; };
+ template<typename Ty> using AddRvalueReferenceType = typename AddRvalueReferenceT<Ty>::Type;
+
+ //---
+ template<typename Ty> struct RemoveReferenceT { using Type = Ty; };
+ template<typename Ty> struct RemoveReferenceT<Ty&> { using Type = Ty; };
+ template<typename Ty> struct RemoveReferenceT<Ty&&> { using Type = Ty; };
+ template<typename Ty> using RemoveReferenceType = typename RemoveReferenceT<Ty>::Type;
+
+ //---
+ template<typename Ty> struct AddPointerT { using Type = TypeIdentityType<RemoveReferenceType<Ty>*>; };
+ template<typename Ty> using AddPointerType = typename AddPointerT<Ty>::Type;
+
+ //---
+ template<typename Ty> struct RemovePointerT { using Type = Ty; };
+ template<typename Ty> struct RemovePointerT< Ty* > { using Type = Ty; };
+ template<typename Ty> struct RemovePointerT< const Ty* > { using Type = Ty; };
+ template<typename Ty> struct RemovePointerT< volatile Ty* > { using Type = Ty; };
+ template<typename Ty> struct RemovePointerT<const volatile Ty* > { using Type = Ty; };
+ template<typename Ty> struct RemovePointerT<const volatile Ty* const > { using Type = Ty; };
+ template<typename Ty> struct RemovePointerT< Ty* const > { using Type = Ty; };
+ template<typename Ty> struct RemovePointerT< Ty* volatile> { using Type = Ty; };
+ template<typename Ty> struct RemovePointerT< Ty* const volatile> { using Type = Ty; };
+ template<typename Ty> using RemovePointerType = typename RemovePointerT<Ty>::Type;
+
+ //---
+ template<typename Ty> struct AddCvT { using Type = const volatile Ty; };
+ template<typename Ty> using AddCvType = typename AddCvT<Ty>::Type;
+
+ //---
+ template<typename Ty> struct RemoveCvT { using Type = Ty; };
+ template<typename Ty> struct RemoveCvT<const Ty> { using Type = Ty; };
+ template<typename Ty> struct RemoveCvT<volatile Ty> { using Type = Ty; };
+ template<typename Ty> struct RemoveCvT<const volatile Ty> { using Type = Ty; };
+ template<typename Ty> using RemoveCvType = typename RemoveCvT<Ty>::Type;
+
+ //---
+ template<typename Ty> struct AddConstT { using Type = const Ty; };
+ template<typename Ty> using AddConstType = typename AddConstT<Ty>::Type;
+
+ //---
+ template<typename Ty> struct RemoveConstT { using Type = Ty; };
+ template<typename Ty> struct RemoveConstT<const Ty> { using Type = Ty; };
+ template<typename Ty> using RemoveConstType = typename RemoveConstT<Ty>::Type;
+
+ //---
+ template<typename Ty> struct AddVolatileT { using Type = volatile Ty; };
+ template<typename Ty> using AddVolatileType = typename AddVolatileT<Ty>::Type;
+
+ //---
+ template<typename Ty> struct RemoveVolatileT { using Type = Ty; };
+ template<typename Ty> struct RemoveVolatileT<volatile Ty> { using Type = Ty; };
+ template<typename Ty> using RemoveVolatileType = typename RemoveVolatileT<Ty>::Type;
+
+ //---
+
+ template<typename Ty> struct IsBoundedArrayT : FalseConstant {};
+ template<typename Ty, size_t SizeT> struct IsBoundedArrayT<Ty[SizeT]> : TrueConstant {};
+
+ template<typename Ty>
+ inline constexpr bool isBoundedArray()
+ {
+ return IsBoundedArrayT<Ty>::value;
+ }
+
+ template<typename Ty> struct IsUnboundedArrayT : FalseConstant {};
+ template<typename Ty> struct IsUnboundedArrayT<Ty[]> : TrueConstant {};
+
+ template<typename Ty>
+ inline constexpr bool isUnboundedArray()
+ {
+ return IsUnboundedArrayT<Ty>::value;
+ }
+
+ template<typename Ty>
+ inline constexpr bool isArray()
+ {
+ return isBoundedArray<Ty>()
+ || isUnboundedArray<Ty>()
+ ;
+ }
+
+ template<typename Ty>
+ inline constexpr bool isEnum()
+ {
+ return !!__is_enum(Ty);
+ }
+
+ template<typename Ty>
+ inline constexpr bool isUnion()
+ {
+ return !!__is_union(Ty);
+ }
+
+ template<typename Ty>
+ inline constexpr bool isAbstract()
+ {
+ return !!__is_abstract(Ty);
+ }
+
+ template<typename Ty>
+ inline constexpr bool isAggregate()
+ {
+ return !!__is_aggregate(Ty);
+ }
+
+ template<typename BaseT, typename DerivedT>
+ inline constexpr bool isBaseOf()
+ {
+ return !!__is_base_of(BaseT, DerivedT);
+ }
+
+ template<typename Ty>
+ inline constexpr bool isPolymorphic()
+ {
+ return !!__is_polymorphic(Ty);
+ }
+
+ template<typename Ty>
+ inline constexpr bool isDestructorVirtual()
+ {
+ return __has_virtual_destructor(Ty);
+ }
+
+ template<typename Ty>
+ inline constexpr bool isClass()
+ {
+ return !!__is_class(Ty);
+ }
+
+ template<typename Ty>
+ inline constexpr bool isFinal()
+ {
+ return !!__is_final(Ty);
+ }
+
+ template<typename Ty>
+ inline constexpr bool isEmpty()
+ {
+ return !!__is_empty(Ty);
+ }
+
+ template<typename Ty>
+ inline constexpr bool isStandardLayout()
+ {
+ return !!__is_standard_layout(Ty);
+ }
+
+ template<typename Ty>
+ inline constexpr bool isTrivial()
+ {
+ return !!__is_trivial(Ty);
+ }
+
+ template<typename Ty>
+ inline constexpr bool isPod()
+ {
+ return isStandardLayout<Ty>()
+ && isTrivial<Ty>()
+ ;
+ }
+
+ template<typename Ty, typename FromT>
+ inline constexpr bool isAssignable()
+ {
+ return !!__is_assignable(Ty, FromT);
+ }
+
+ template<typename Ty>
+ inline constexpr bool isCopyAssignable()
+ {
+ return isAssignable<
+ AddLvalueReferenceType<Ty>
+ , AddLvalueReferenceType<const Ty>
+ >();
+ }
+
+ template<typename Ty>
+ inline constexpr bool isMoveAssignable()
+ {
+ return isAssignable<
+ AddLvalueReferenceType<Ty>
+ , AddRvalueReferenceType<Ty>
+ >();
+ }
+
+ template<typename Ty, typename FromT>
+ inline constexpr bool isTriviallyAssignable()
+ {
+ return !!__is_trivially_assignable(Ty, FromT);
+ }
+
+ template<typename Ty>
+ inline constexpr bool isTriviallyCopyAssignable()
+ {
+ return isTriviallyAssignable<
+ AddLvalueReferenceType<Ty>
+ , AddRvalueReferenceType<const Ty>
+ >();
+ }
+
+ template<typename Ty>
+ inline constexpr bool isTriviallyMoveAssignable()
+ {
+ return isTriviallyAssignable<
+ AddLvalueReferenceType<Ty>
+ , AddRvalueReferenceType<Ty>
+ >();
+ }
+
+ template<typename Ty, typename... ArgsT>
+ inline constexpr bool isConstructible()
+ {
+ return !!__is_constructible(Ty, ArgsT...);
+ }
+
+ template<typename Ty>
+ inline constexpr bool isCopyConstructible()
+ {
+ return isConstructible<Ty, AddLvalueReferenceType<Ty>>();
+ }
+
+ template<typename Ty>
+ inline constexpr bool isMoveConstructible()
+ {
+ return isConstructible<Ty, AddRvalueReferenceType<Ty>>();
+ }
+
+ template<typename Ty, typename... ArgsT>
+ inline constexpr bool isTriviallyConstructible()
+ {
+ return !!__is_trivially_constructible(Ty, ArgsT...);
+ }
+
+ template<typename Ty>
+ inline constexpr bool isTriviallyCopyConstructible()
+ {
+ return isTriviallyConstructible<Ty, AddLvalueReferenceType<Ty>>();
+ }
+
+ template<typename Ty>
+ inline constexpr bool isTriviallyMoveConstructible()
+ {
+ return isTriviallyConstructible<Ty, AddRvalueReferenceType<Ty>>();
+ }
+
+ template<typename Ty>
+ inline constexpr bool isTriviallyCopyable()
+ {
+ return !!__is_trivially_copyable(Ty);
+ }
+
+ template<typename Ty>
+ inline constexpr bool isTriviallyDestructible()
+ {
+#if BX_COMPILER_GCC
+ return !!__has_trivial_destructor(Ty);
+#else
+ return !!__is_trivially_destructible(Ty);
+#endif // BX_COMPILER_GCC
+ }
+
+ template<typename Ty> struct IsConstT : FalseConstant {};
+ template<typename Ty> struct IsConstT<const Ty> : TrueConstant {};
+
+ template<typename Ty>
+ inline constexpr bool isConst()
+ {
+ return IsConstT<Ty>::value;
+ }
+
+ template<typename Ty> struct IsVolatileT : FalseConstant {};
+ template<typename Ty> struct IsVolatileT<volatile Ty> : TrueConstant {};
+
+ template<typename Ty>
+ inline constexpr bool isVolatile()
+ {
+ return IsVolatileT<Ty>::value;
+ }
+
+ template<typename Ty> struct IsLvalueReferenceT : FalseConstant {};
+ template<typename Ty> struct IsLvalueReferenceT<Ty&> : TrueConstant {};
+
+ template<typename Ty>
+ inline constexpr bool isLvalueReference()
+ {
+ return IsLvalueReferenceT<Ty>::value;
+ }
+
+ template<typename Ty> struct IsRvalueReferenceT : FalseConstant {};
+ template<typename Ty> struct IsRvalueReferenceT<Ty&&> : TrueConstant {};
+
+ template<typename Ty>
+ inline constexpr bool isRvalueReference()
+ {
+ return IsRvalueReferenceT<Ty>::value;
+ }
+
+ template<typename Ty>
+ inline constexpr bool isReference()
+ {
+ return isLvalueReference<Ty>()
+ || isRvalueReference<Ty>()
+ ;
+ }
+
+ template<typename Ty> struct IsPointerT : FalseConstant {};
+ template<typename Ty> struct IsPointerT<Ty*> : TrueConstant {};
+ template<typename Ty> struct IsPointerT<Ty* const> : TrueConstant {};
+ template<typename Ty> struct IsPointerT<Ty* volatile> : TrueConstant {};
+ template<typename Ty> struct IsPointerT<Ty* const volatile> : TrueConstant {};
+
+ template<typename Ty>
+ inline constexpr bool isPointer()
+ {
+ return IsPointerT<Ty>::value;
+ }
+
+ template<typename Ty>
+ inline constexpr bool isSigned()
+ {
+ return Ty(-1) < Ty(0);
+ }
+
+ template<typename Ty>
+ inline constexpr bool isUnsigned()
+ {
+ return Ty(-1) > Ty(0);
+ }
+
+ template<typename Ty> struct IsIntegerT : FalseConstant {};
+ template<> struct IsIntegerT<bool > : TrueConstant {};
+ template<> struct IsIntegerT<char > : TrueConstant {};
+ template<> struct IsIntegerT<char16_t > : TrueConstant {};
+ template<> struct IsIntegerT<char32_t > : TrueConstant {};
+ template<> struct IsIntegerT<wchar_t > : TrueConstant {};
+ template<> struct IsIntegerT< signed char > : TrueConstant {};
+ template<> struct IsIntegerT<unsigned char > : TrueConstant {};
+ template<> struct IsIntegerT< short > : TrueConstant {};
+ template<> struct IsIntegerT<unsigned short > : TrueConstant {};
+ template<> struct IsIntegerT< int > : TrueConstant {};
+ template<> struct IsIntegerT<unsigned int > : TrueConstant {};
+ template<> struct IsIntegerT< long > : TrueConstant {};
+ template<> struct IsIntegerT<unsigned long > : TrueConstant {};
+ template<> struct IsIntegerT< long long> : TrueConstant {};
+ template<> struct IsIntegerT<unsigned long long> : TrueConstant {};
+
+ template<typename Ty>
+ inline constexpr bool isInteger()
+ {
+ return IsIntegerT<Ty>::value;
+ }
+
+ template<typename Ty> struct IsFloatingPointT : FalseConstant {};
+ template<> struct IsFloatingPointT<float > : TrueConstant {};
+ template<> struct IsFloatingPointT< double> : TrueConstant {};
+ template<> struct IsFloatingPointT<long double> : TrueConstant {};
+
+ template<typename Ty>
+ inline constexpr bool isFloatingPoint()
+ {
+ return IsFloatingPointT<Ty>::value;
+ }
+
+ template<typename Ty>
+ inline constexpr bool isArithmetic()
+ {
+ return isInteger<Ty>()
+ || isFloatingPoint<Ty>()
+ ;
+ }
+
+ template<typename Ty, typename Uy> struct IsSameT : FalseConstant {};
+ template<typename Ty> struct IsSameT<Ty, Ty> : TrueConstant {};
+
+ template<typename Ty, typename Uy>
+ inline constexpr bool isSame()
+ {
+ return IsSameT<Ty, Uy>::value;
+ }
+
+ template<typename Ty>
+ inline constexpr RemoveReferenceType<Ty>&& move(Ty&& _a)
+ {
+ return static_cast<RemoveReferenceType<Ty>&&>(_a);
+ }
+
+ template<typename Ty>
+ inline constexpr Ty&& forward(RemoveReferenceType<Ty>& _a)
+ {
+ return static_cast<Ty&&>(_a);
+ }
+
+ template<typename Ty>
+ inline constexpr Ty&& forward(RemoveReferenceType<Ty>&& _a)
+ {
+ BX_STATIC_ASSERT(!isLvalueReference<Ty>(), "Can not forward an Rvalue as an Lvalue.");
+ return static_cast<Ty&&>(_a);
+ }
+
+} // namespace bx
diff --git a/3rdparty/bx/include/bx/inline/uint32_t.inl b/3rdparty/bx/include/bx/inline/uint32_t.inl
index 2a17582b0db..5cd3c2103ba 100644
--- a/3rdparty/bx/include/bx/inline/uint32_t.inl
+++ b/3rdparty/bx/include/bx/inline/uint32_t.inl
@@ -1,6 +1,6 @@
/*
- * Copyright 2010-2018 Branimir Karadzic. All rights reserved.
- * License: https://github.com/bkaradzic/bx#license-bsd-2-clause
+ * Copyright 2010-2022 Branimir Karadzic. All rights reserved.
+ * License: https://github.com/bkaradzic/bx/blob/master/LICENSE
*/
// Copyright 2006 Mike Acton <macton@gmail.com>
@@ -307,8 +307,12 @@ namespace bx
return result;
}
+ template<>
inline BX_CONSTEXPR_FUNC uint32_t uint32_cntbits(uint32_t _val)
{
+#if BX_COMPILER_GCC || BX_COMPILER_CLANG
+ return __builtin_popcount(_val);
+#else
const uint32_t tmp0 = uint32_srl(_val, 1);
const uint32_t tmp1 = uint32_and(tmp0, 0x55555555);
const uint32_t tmp2 = uint32_sub(_val, tmp1);
@@ -328,10 +332,43 @@ namespace bx
const uint32_t result = uint32_and(tmpF, 0x3f);
return result;
+#endif // BX_COMPILER_*
}
+ template<>
+ inline BX_CONSTEXPR_FUNC uint32_t uint32_cntbits(unsigned long long _val)
+ {
+#if BX_COMPILER_GCC || BX_COMPILER_CLANG
+ return __builtin_popcountll(_val);
+#else
+ const uint32_t lo = uint32_t(_val&UINT32_MAX);
+ const uint32_t hi = uint32_t(_val>>32);
+
+ return uint32_cntbits(lo)
+ + uint32_cntbits(hi)
+ ;
+#endif // BX_COMPILER_*
+ }
+
+ template<>
+ inline BX_CONSTEXPR_FUNC uint32_t uint32_cntbits(unsigned long _val)
+ {
+ return uint32_cntbits<unsigned long long>(_val);
+ }
+
+ template<> inline BX_CONSTEXPR_FUNC uint32_t uint32_cntbits(uint8_t _val) { return uint32_cntbits<uint32_t>(_val); }
+ template<> inline BX_CONSTEXPR_FUNC uint32_t uint32_cntbits(int8_t _val) { return uint32_cntbits<uint8_t >(_val); }
+ template<> inline BX_CONSTEXPR_FUNC uint32_t uint32_cntbits(uint16_t _val) { return uint32_cntbits<uint32_t>(_val); }
+ template<> inline BX_CONSTEXPR_FUNC uint32_t uint32_cntbits(int16_t _val) { return uint32_cntbits<uint16_t>(_val); }
+ template<> inline BX_CONSTEXPR_FUNC uint32_t uint32_cntbits(int32_t _val) { return uint32_cntbits<uint32_t>(_val); }
+ template<> inline BX_CONSTEXPR_FUNC uint32_t uint32_cntbits(int64_t _val) { return uint32_cntbits<uint64_t>(_val); }
+
+ template<>
inline BX_CONSTEXPR_FUNC uint32_t uint32_cntlz(uint32_t _val)
{
+#if BX_COMPILER_GCC || BX_COMPILER_CLANG
+ return 0 == _val ? 32 : __builtin_clz(_val);
+#else
const uint32_t tmp0 = uint32_srl(_val, 1);
const uint32_t tmp1 = uint32_or(tmp0, _val);
const uint32_t tmp2 = uint32_srl(tmp1, 2);
@@ -346,18 +383,76 @@ namespace bx
const uint32_t result = uint32_cntbits(tmpA);
return result;
+#endif // BX_COMPILER_*
+ }
+
+ template<>
+ inline BX_CONSTEXPR_FUNC uint32_t uint32_cntlz(unsigned long long _val)
+ {
+#if BX_COMPILER_GCC || BX_COMPILER_CLANG
+ return 0 == _val ? 64 : __builtin_clzll(_val);
+#else
+ return _val & UINT64_C(0xffffffff00000000)
+ ? uint32_cntlz(uint32_t(_val>>32) )
+ : uint32_cntlz(uint32_t(_val) ) + 32
+ ;
+#endif // BX_COMPILER_*
+ }
+
+ template<>
+ inline BX_CONSTEXPR_FUNC uint32_t uint32_cntlz(unsigned long _val)
+ {
+ return uint32_cntlz<unsigned long long>(_val);
}
+ template<> inline BX_CONSTEXPR_FUNC uint32_t uint32_cntlz(uint8_t _val) { return uint32_cntlz<uint32_t>(_val)-24; }
+ template<> inline BX_CONSTEXPR_FUNC uint32_t uint32_cntlz(int8_t _val) { return uint32_cntlz<uint8_t >(_val); }
+ template<> inline BX_CONSTEXPR_FUNC uint32_t uint32_cntlz(uint16_t _val) { return uint32_cntlz<uint32_t>(_val)-16; }
+ template<> inline BX_CONSTEXPR_FUNC uint32_t uint32_cntlz(int16_t _val) { return uint32_cntlz<uint16_t>(_val); }
+ template<> inline BX_CONSTEXPR_FUNC uint32_t uint32_cntlz(int32_t _val) { return uint32_cntlz<uint32_t>(_val); }
+ template<> inline BX_CONSTEXPR_FUNC uint32_t uint32_cntlz(int64_t _val) { return uint32_cntlz<uint64_t>(_val); }
+
+ template<>
inline BX_CONSTEXPR_FUNC uint32_t uint32_cnttz(uint32_t _val)
{
+#if BX_COMPILER_GCC || BX_COMPILER_CLANG
+ return 0 == _val ? 32 : __builtin_ctz(_val);
+#else
const uint32_t tmp0 = uint32_not(_val);
const uint32_t tmp1 = uint32_dec(_val);
const uint32_t tmp2 = uint32_and(tmp0, tmp1);
const uint32_t result = uint32_cntbits(tmp2);
return result;
+#endif // BX_COMPILER_*
+ }
+
+ template<>
+ inline BX_CONSTEXPR_FUNC uint32_t uint32_cnttz(unsigned long long _val)
+ {
+#if BX_COMPILER_GCC || BX_COMPILER_CLANG
+ return 0 == _val ? 64 : __builtin_ctzll(_val);
+#else
+ return _val & UINT64_C(0xffffffff)
+ ? uint32_cnttz(uint32_t(_val) )
+ : uint32_cnttz(uint32_t(_val>>32) ) + 32
+ ;
+#endif // BX_COMPILER_*
+ }
+
+ template<>
+ inline BX_CONSTEXPR_FUNC uint32_t uint32_cnttz(unsigned long _val)
+ {
+ return uint32_cnttz<unsigned long long>(_val);
}
+ template<> inline BX_CONSTEXPR_FUNC uint32_t uint32_cnttz(uint8_t _val) { return bx::min(8u, uint32_cnttz<uint32_t>(_val) ); }
+ template<> inline BX_CONSTEXPR_FUNC uint32_t uint32_cnttz(int8_t _val) { return uint32_cnttz<uint8_t >(_val); }
+ template<> inline BX_CONSTEXPR_FUNC uint32_t uint32_cnttz(uint16_t _val) { return bx::min(16u, uint32_cnttz<uint32_t>(_val) ); }
+ template<> inline BX_CONSTEXPR_FUNC uint32_t uint32_cnttz(int16_t _val) { return uint32_cnttz<uint16_t>(_val); }
+ template<> inline BX_CONSTEXPR_FUNC uint32_t uint32_cnttz(int32_t _val) { return uint32_cnttz<uint32_t>(_val); }
+ template<> inline BX_CONSTEXPR_FUNC uint32_t uint32_cnttz(int64_t _val) { return uint32_cnttz<uint64_t>(_val); }
+
inline BX_CONSTEXPR_FUNC uint32_t uint32_part1by1(uint32_t _a)
{
// shuffle:
@@ -468,6 +563,66 @@ namespace bx
;
}
+ inline BX_CONSTEXPR_FUNC uint64_t uint64_li(uint64_t _a)
+ {
+ return _a;
+ }
+
+ inline BX_CONSTEXPR_FUNC uint64_t uint64_dec(uint64_t _a)
+ {
+ return _a - 1;
+ }
+
+ inline BX_CONSTEXPR_FUNC uint64_t uint64_inc(uint64_t _a)
+ {
+ return _a + 1;
+ }
+
+ inline BX_CONSTEXPR_FUNC uint64_t uint64_not(uint64_t _a)
+ {
+ return ~_a;
+ }
+
+ inline BX_CONSTEXPR_FUNC uint64_t uint64_neg(uint64_t _a)
+ {
+ return -(int32_t)_a;
+ }
+
+ inline BX_CONSTEXPR_FUNC uint64_t uint64_ext(uint64_t _a)
+ {
+ return ( (int32_t)_a)>>31;
+ }
+
+ inline BX_CONSTEXPR_FUNC uint64_t uint64_and(uint64_t _a, uint64_t _b)
+ {
+ return _a & _b;
+ }
+
+ inline BX_CONSTEXPR_FUNC uint64_t uint64_andc(uint64_t _a, uint64_t _b)
+ {
+ return _a & ~_b;
+ }
+
+ inline BX_CONSTEXPR_FUNC uint64_t uint64_xor(uint64_t _a, uint64_t _b)
+ {
+ return _a ^ _b;
+ }
+
+ inline BX_CONSTEXPR_FUNC uint64_t uint64_xorl(uint64_t _a, uint64_t _b)
+ {
+ return !_a != !_b;
+ }
+
+ inline BX_CONSTEXPR_FUNC uint64_t uint64_or(uint64_t _a, uint64_t _b)
+ {
+ return _a | _b;
+ }
+
+ inline BX_CONSTEXPR_FUNC uint64_t uint64_orc(uint64_t _a, uint64_t _b)
+ {
+ return _a | ~_b;
+ }
+
inline BX_CONSTEXPR_FUNC uint64_t uint64_sll(uint64_t _a, int32_t _sa)
{
return _a << _sa;
@@ -537,9 +692,10 @@ namespace bx
return result;
}
- inline BX_CONSTEXPR_FUNC uint32_t strideAlign16(uint32_t _offset, uint32_t _stride)
+ template<uint32_t Min>
+ inline BX_CONSTEXPR_FUNC uint32_t strideAlign(uint32_t _offset, uint32_t _stride)
{
- const uint32_t align = uint32_lcm(16, _stride);
+ const uint32_t align = uint32_lcm(Min, _stride);
const uint32_t mod = uint32_mod(_offset, align);
const uint32_t mask = uint32_cmpeq(mod, 0);
const uint32_t tmp0 = uint32_selb(mask, 0, align);
@@ -549,16 +705,71 @@ namespace bx
return result;
}
- inline BX_CONSTEXPR_FUNC uint32_t strideAlign256(uint32_t _offset, uint32_t _stride)
+ template<typename Ty>
+ inline BX_CONSTEXPR_FUNC bool isAligned(Ty _a, int32_t _align)
{
- const uint32_t align = uint32_lcm(256, _stride);
- const uint32_t mod = uint32_mod(_offset, align);
- const uint32_t mask = uint32_cmpeq(mod, 0);
- const uint32_t tmp0 = uint32_selb(mask, 0, align);
- const uint32_t tmp1 = uint32_add(_offset, tmp0);
- const uint32_t result = uint32_sub(tmp1, mod);
+ const Ty mask = Ty(_align - 1);
+ return 0 == (_a & mask);
+ }
- return result;
+ template<typename Ty>
+ inline BX_CONSTEXPR_FUNC bool isAligned(Ty* _ptr, int32_t _align)
+ {
+ union { const void* ptr; uintptr_t addr; } un = { _ptr };
+ return isAligned(un.addr, _align);
+ }
+
+ template<typename Ty>
+ inline BX_CONSTEXPR_FUNC bool isAligned(const Ty* _ptr, int32_t _align)
+ {
+ union { const void* ptr; uintptr_t addr; } un = { _ptr };
+ return isAligned(un.addr, _align);
+ }
+
+ template<typename Ty>
+ inline BX_CONSTEXPR_FUNC Ty alignDown(Ty _a, int32_t _align)
+ {
+ const Ty mask = Ty(_align - 1);
+ return Ty(_a & ~mask);
+ }
+
+ template<typename Ty>
+ inline BX_CONSTEXPR_FUNC Ty* alignDown(Ty* _ptr, int32_t _align)
+ {
+ union { Ty* ptr; uintptr_t addr; } un = { _ptr };
+ un.addr = alignDown(un.addr, _align);
+ return un.ptr;
+ }
+
+ template<typename Ty>
+ inline BX_CONSTEXPR_FUNC const Ty* alignDown(const Ty* _ptr, int32_t _align)
+ {
+ union { const Ty* ptr; uintptr_t addr; } un = { _ptr };
+ un.addr = alignDown(un.addr, _align);
+ return un.ptr;
+ }
+
+ template<typename Ty>
+ inline BX_CONSTEXPR_FUNC Ty alignUp(Ty _a, int32_t _align)
+ {
+ const Ty mask = Ty(_align - 1);
+ return Ty( (_a + mask) & ~mask);
+ }
+
+ template<typename Ty>
+ inline BX_CONSTEXPR_FUNC Ty* alignUp(Ty* _ptr, int32_t _align)
+ {
+ union { Ty* ptr; uintptr_t addr; } un = { _ptr };
+ un.addr = alignUp(un.addr, _align);
+ return un.ptr;
+ }
+
+ template<typename Ty>
+ inline BX_CONSTEXPR_FUNC const Ty* alignUp(const Ty* _ptr, int32_t _align)
+ {
+ union { const Ty* ptr; uintptr_t addr; } un = { _ptr };
+ un.addr = alignUp(un.addr, _align);
+ return un.ptr;
}
inline BX_CONST_FUNC uint16_t halfFromFloat(float _a)
diff --git a/3rdparty/bx/include/bx/macros.h b/3rdparty/bx/include/bx/macros.h
index 9c72182486b..61401af8650 100644
--- a/3rdparty/bx/include/bx/macros.h
+++ b/3rdparty/bx/include/bx/macros.h
@@ -1,15 +1,17 @@
/*
- * Copyright 2010-2018 Branimir Karadzic. All rights reserved.
- * License: https://github.com/bkaradzic/bx#license-bsd-2-clause
+ * Copyright 2010-2022 Branimir Karadzic. All rights reserved.
+ * License: https://github.com/bkaradzic/bx/blob/master/LICENSE
*/
+#ifndef BX_H_HEADER_GUARD
+# error "Do not include macros.h directly #include <bx/bx.h> instead."
+#endif // BX_H_HEADER_GUARD
+
#ifndef BX_MACROS_H_HEADER_GUARD
#define BX_MACROS_H_HEADER_GUARD
-#include "bx.h"
-
///
-#if BX_COMPILER_MSVC
+#if BX_COMPILER_MSVC && (!defined(_MSVC_TRADITIONAL) || _MSVC_TRADITIONAL)
// Workaround MSVS bug...
# define BX_VA_ARGS_PASS(...) BX_VA_ARGS_PASS_1_ __VA_ARGS__ BX_VA_ARGS_PASS_2_
# define BX_VA_ARGS_PASS_1_ (
@@ -41,12 +43,6 @@
#define BX_FILE_LINE_LITERAL "" __FILE__ "(" BX_STRINGIZE(__LINE__) "): "
///
-#define BX_ALIGN_MASK(_value, _mask) ( ( (_value)+(_mask) ) & ( (~0)&(~(_mask) ) ) )
-#define BX_ALIGN_16(_value) BX_ALIGN_MASK(_value, 0xf)
-#define BX_ALIGN_256(_value) BX_ALIGN_MASK(_value, 0xff)
-#define BX_ALIGN_4096(_value) BX_ALIGN_MASK(_value, 0xfff)
-
-///
#define BX_ALIGNOF(_type) __alignof(_type)
#if defined(__has_feature)
@@ -70,7 +66,7 @@
# define BX_UNLIKELY(_x) __builtin_expect(!!(_x), 0)
# define BX_NO_INLINE __attribute__( (noinline) )
# define BX_NO_RETURN __attribute__( (noreturn) )
-# define BX_CONST_FUNC __attribute__( (const) )
+# define BX_CONST_FUNC __attribute__( (pure) )
# if BX_COMPILER_GCC >= 70000
# define BX_FALLTHROUGH __attribute__( (fallthrough) )
@@ -81,11 +77,9 @@
# define BX_NO_VTABLE
# define BX_PRINTF_ARGS(_format, _args) __attribute__( (format(__printf__, _format, _args) ) )
-# if BX_CLANG_HAS_FEATURE(cxx_thread_local)
-# define BX_THREAD_LOCAL __thread
-# endif // BX_COMPILER_CLANG
-
-# if (!BX_PLATFORM_OSX && (BX_COMPILER_GCC >= 40200)) || (BX_COMPILER_GCC >= 40500)
+# if BX_CLANG_HAS_FEATURE(cxx_thread_local) \
+ || (!BX_PLATFORM_OSX && (BX_COMPILER_GCC >= 40200) ) \
+ || (BX_COMPILER_GCC >= 40500)
# define BX_THREAD_LOCAL __thread
# endif // BX_COMPILER_GCC
@@ -151,7 +145,7 @@
#define BX_UNUSED_11(_a1, _a2, _a3, _a4, _a5, _a6, _a7, _a8, _a9, _a10, _a11) BX_UNUSED_10(_a1, _a2, _a3, _a4, _a5, _a6, _a7, _a8, _a9, _a10); BX_UNUSED_1(_a11)
#define BX_UNUSED_12(_a1, _a2, _a3, _a4, _a5, _a6, _a7, _a8, _a9, _a10, _a11, _a12) BX_UNUSED_11(_a1, _a2, _a3, _a4, _a5, _a6, _a7, _a8, _a9, _a10, _a11); BX_UNUSED_1(_a12)
-#if BX_COMPILER_MSVC
+#if BX_COMPILER_MSVC && (!defined(_MSVC_TRADITIONAL) || _MSVC_TRADITIONAL)
// Workaround MSVS bug...
# define BX_UNUSED(...) BX_MACRO_DISPATCHER(BX_UNUSED_, __VA_ARGS__) BX_VA_ARGS_PASS(__VA_ARGS__)
#else
@@ -203,16 +197,24 @@
# define BX_PRAGMA_DIAGNOSTIC_IGNORED_CLANG_GCC(_x)
#endif // BX_COMPILER_
-///
+/// No default constructor.
#define BX_CLASS_NO_DEFAULT_CTOR(_class) \
- private: _class()
+ _class() = delete
-#define BX_CLASS_NO_COPY(_class) \
- private: _class(const _class& _rhs)
+/// No copy constructor.
+#define BX_CLASS_NO_COPY_CTOR(_class) \
+ _class(const _class& _rhs) = delete
-#define BX_CLASS_NO_ASSIGNMENT(_class) \
- private: _class& operator=(const _class& _rhs)
+/// No copy assignment operator.
+#define BX_CLASS_NO_COPY_ASSIGNMENT(_class) \
+ _class& operator=(const _class& _rhs) = delete
+/// No copy construcor, and copy assignment operator.
+#define BX_CLASS_NO_COPY(_class) \
+ BX_CLASS_NO_COPY_CTOR(_class); \
+ BX_CLASS_NO_COPY_ASSIGNMENT(_class)
+
+///
#define BX_CLASS_ALLOCATOR(_class) \
public: void* operator new(size_t _size); \
public: void operator delete(void* _ptr); \
@@ -224,23 +226,57 @@
#define BX_CLASS_3(_class, _a1, _a2, _a3) BX_CLASS_2(_class, _a1, _a2); BX_CLASS_1(_class, _a3)
#define BX_CLASS_4(_class, _a1, _a2, _a3, _a4) BX_CLASS_3(_class, _a1, _a2, _a3); BX_CLASS_1(_class, _a4)
-#if BX_COMPILER_MSVC
+#if BX_COMPILER_MSVC && (!defined(_MSVC_TRADITIONAL) || _MSVC_TRADITIONAL)
# define BX_CLASS(_class, ...) BX_MACRO_DISPATCHER(BX_CLASS_, __VA_ARGS__) BX_VA_ARGS_PASS(_class, __VA_ARGS__)
#else
# define BX_CLASS(_class, ...) BX_MACRO_DISPATCHER(BX_CLASS_, __VA_ARGS__)(_class, __VA_ARGS__)
#endif // BX_COMPILER_MSVC
-#ifndef BX_CHECK
-# define BX_CHECK(_condition, ...) BX_NOOP()
-#endif // BX_CHECK
+#ifndef BX_ASSERT
+# if BX_CONFIG_DEBUG
+# define BX_ASSERT _BX_ASSERT
+# else
+# define BX_ASSERT(_condition, ...) BX_NOOP()
+# endif // BX_CONFIG_DEBUG
+#endif // BX_ASSERT
#ifndef BX_TRACE
-# define BX_TRACE(...) BX_NOOP()
+# if BX_CONFIG_DEBUG
+# define BX_TRACE _BX_TRACE
+# else
+# define BX_TRACE(...) BX_NOOP()
+# endif // BX_CONFIG_DEBUG
#endif // BX_TRACE
#ifndef BX_WARN
-# define BX_WARN(_condition, ...) BX_NOOP()
-#endif // BX_CHECK
+# if BX_CONFIG_DEBUG
+# define BX_WARN _BX_WARN
+# else
+# define BX_WARN(_condition, ...) BX_NOOP()
+# endif // BX_CONFIG_DEBUG
+#endif // BX_ASSERT
+
+#define _BX_TRACE(_format, ...) \
+ BX_MACRO_BLOCK_BEGIN \
+ bx::debugPrintf(__FILE__ "(" BX_STRINGIZE(__LINE__) "): BX " _format "\n", ##__VA_ARGS__); \
+ BX_MACRO_BLOCK_END
+
+#define _BX_WARN(_condition, _format, ...) \
+ BX_MACRO_BLOCK_BEGIN \
+ if (!BX_IGNORE_C4127(_condition) ) \
+ { \
+ BX_TRACE("WARN " _format, ##__VA_ARGS__); \
+ } \
+ BX_MACRO_BLOCK_END
+
+#define _BX_ASSERT(_condition, _format, ...) \
+ BX_MACRO_BLOCK_BEGIN \
+ if (!BX_IGNORE_C4127(_condition) ) \
+ { \
+ BX_TRACE("ASSERT " _format, ##__VA_ARGS__); \
+ bx::debugBreak(); \
+ } \
+ BX_MACRO_BLOCK_END
// static_assert sometimes causes unused-local-typedef...
BX_PRAGMA_DIAGNOSTIC_IGNORED_CLANG("-Wunused-local-typedef")
diff --git a/3rdparty/bx/include/bx/maputil.h b/3rdparty/bx/include/bx/maputil.h
index 78ce6b6f84c..712e2331e0a 100644
--- a/3rdparty/bx/include/bx/maputil.h
+++ b/3rdparty/bx/include/bx/maputil.h
@@ -1,6 +1,6 @@
/*
- * Copyright 2010-2018 Branimir Karadzic. All rights reserved.
- * License: https://github.com/bkaradzic/bx#license-bsd-2-clause
+ * Copyright 2010-2022 Branimir Karadzic. All rights reserved.
+ * License: https://github.com/bkaradzic/bx/blob/master/LICENSE
*/
#ifndef BX_MAPUTIL_H_HEADER_GUARD
diff --git a/3rdparty/bx/include/bx/math.h b/3rdparty/bx/include/bx/math.h
index c751efad50b..a02549b5fe8 100644
--- a/3rdparty/bx/include/bx/math.h
+++ b/3rdparty/bx/include/bx/math.h
@@ -1,10 +1,8 @@
/*
- * Copyright 2011-2018 Branimir Karadzic. All rights reserved.
- * License: https://github.com/bkaradzic/bx#license-bsd-2-clause
+ * Copyright 2011-2022 Branimir Karadzic. All rights reserved.
+ * License: https://github.com/bkaradzic/bx/blob/master/LICENSE
*/
-// FPU math lib
-
#ifndef BX_MATH_H_HEADER_GUARD
#define BX_MATH_H_HEADER_GUARD
@@ -13,27 +11,11 @@
namespace bx
{
- constexpr float kPi = 3.1415926535897932384626433832795f;
- constexpr float kPi2 = 6.2831853071795864769252867665590f;
- constexpr float kInvPi = 1.0f/kPi;
- constexpr float kPiHalf = 1.5707963267948966192313216916398f;
- constexpr float kPiQuarter = 0.7853981633974483096156608458199f;
- constexpr float kSqrt2 = 1.4142135623730950488016887242097f;
- constexpr float kLogNat10 = 2.3025850929940456840179914546844f;
- constexpr float kInvLogNat2 = 1.4426950408889634073599246810019f;
- constexpr float kLogNat2Hi = 0.6931471805599453094172321214582f;
- constexpr float kLogNat2Lo = 1.90821492927058770002e-10f;
- constexpr float kE = 2.7182818284590452353602874713527f;
- constexpr float kNearZero = 1.0f/float(1 << 28);
- constexpr float kFloatMin = 1.175494e-38f;
- constexpr float kFloatMax = 3.402823e+38f;
- extern const float kInfinity;
-
///
typedef float (*LerpFn)(float _a, float _b, float _t);
///
- struct Handness
+ struct Handedness
{
enum Enum
{
@@ -52,12 +34,89 @@ namespace bx
};
};
+ /// Structure initializer types.
+ namespace init
+ {
+ /// Fields are left uninitialized.
+ ///
+ struct NoneTag {};
+ constexpr NoneTag None;
+
+ /// Fields are initialized to zero.
+ ///
+ struct ZeroTag {};
+ constexpr ZeroTag Zero;
+
+ /// Fields are initialized to identity value.
+ ///
+ struct IdentityTag {};
+ constexpr IdentityTag Identity;
+ }
+
///
struct Vec3
{
+ Vec3() = delete;
+
+ ///
+ Vec3(init::NoneTag);
+
+ ///
+ constexpr Vec3(init::ZeroTag);
+
+ ///
+ constexpr Vec3(init::IdentityTag);
+
+ ///
+ explicit constexpr Vec3(float _v);
+
+ ///
+ constexpr Vec3(float _x, float _y, float _z);
+
float x, y, z;
};
+ ///
+ struct Plane
+ {
+ Plane() = delete;
+
+ ///
+ Plane(init::NoneTag);
+
+ ///
+ constexpr Plane(init::ZeroTag);
+
+ ///
+ constexpr Plane(init::IdentityTag);
+
+ ///
+ constexpr Plane(Vec3 _normal, float _dist);
+
+ Vec3 normal;
+ float dist;
+ };
+
+ ///
+ struct Quaternion
+ {
+ Quaternion() = delete;
+
+ ///
+ Quaternion(init::NoneTag);
+
+ ///
+ constexpr Quaternion(init::ZeroTag);
+
+ ///
+ constexpr Quaternion(init::IdentityTag);
+
+ ///
+ constexpr Quaternion(float _x, float _y, float _z, float _w);
+
+ float x, y, z, w;
+ };
+
/// Returns converted the argument _deg to radians.
///
BX_CONST_FUNC float toRad(float _deg);
@@ -112,21 +171,29 @@ namespace bx
/// Returns the largest integer value not greater than _f.
///
- BX_CONST_FUNC float floor(float _f);
+ BX_CONSTEXPR_FUNC float floor(float _f);
/// Returns the smallest integer value not less than _f.
///
- BX_CONST_FUNC float ceil(float _f);
+ BX_CONSTEXPR_FUNC float ceil(float _f);
/// Returns the nearest integer value to _f, rounding halfway cases away from zero,
///
- BX_CONST_FUNC float round(float _f);
+ BX_CONSTEXPR_FUNC float round(float _f);
/// Returns linear interpolation between two values _a and _b.
///
BX_CONSTEXPR_FUNC float lerp(float _a, float _b, float _t);
- /// Returns the sign of _a.
+ /// Returns inverse linear interpolation of _value between two values _a and _b.
+ ///
+ BX_CONSTEXPR_FUNC float invLerp(float _a, float _b, float _value);
+
+ /// Extracts the sign of value `_a`.
+ ///
+ /// @param[in] _a Value.
+ ///
+ /// @returns -1 if `_a` less than zero, 0 if `_a` is equal to 0, or +1 if `_a` is greater than zero.
///
BX_CONSTEXPR_FUNC float sign(float _a);
@@ -174,7 +241,7 @@ namespace bx
///
BX_CONST_FUNC float atan(float _a);
- /// Retruns the inverse tangent of _y/_x.
+ /// Returns the inverse tangent of _y/_x.
///
BX_CONST_FUNC float atan2(float _y, float _x);
@@ -205,7 +272,8 @@ namespace bx
/// Returns the base 2 logarithm of _a.
///
- BX_CONST_FUNC float log2(float _a);
+ template<typename Ty>
+ BX_CONST_FUNC Ty log2(Ty _a);
/// Returns the square root of _a.
///
@@ -224,315 +292,360 @@ namespace bx
///
BX_CONSTEXPR_FUNC float fract(float _a);
- /// Returns result of multipla and add (_a * _b + _c).
- ///
- BX_CONSTEXPR_FUNC float mad(float _a, float _b, float _c);
-
- /// Returns the floating-point remainder of the division operation _a/_b.
- ///
- BX_CONST_FUNC float mod(float _a, float _b);
-
- ///
- BX_CONSTEXPR_FUNC bool equal(float _a, float _b, float _epsilon);
-
+ /// Returns result of negated multiply-sub operation -(_a * _b - _c) -> _c - _a * _b.
///
- BX_CONST_FUNC bool equal(const float* _a, const float* _b, uint32_t _num, float _epsilon);
+ BX_CONSTEXPR_FUNC float nms(float _a, float _b, float _c);
+ /// Returns result of addition (_a + _b).
///
- BX_CONST_FUNC float wrap(float _a, float _wrap);
+ BX_CONSTEXPR_FUNC float add(float _a, float _b);
+ /// Returns result of subtracion (_a - _b).
///
- BX_CONSTEXPR_FUNC float step(float _edge, float _a);
+ BX_CONSTEXPR_FUNC float sub(float _a, float _b);
+ /// Returns result of multiply (_a * _b).
///
- BX_CONSTEXPR_FUNC float pulse(float _a, float _start, float _end);
-
- ///
- BX_CONSTEXPR_FUNC float smoothStep(float _a);
-
- ///
- BX_CONSTEXPR_FUNC float bias(float _time, float _bias);
-
- ///
- BX_CONSTEXPR_FUNC float gain(float _time, float _gain);
-
- ///
- BX_CONST_FUNC float angleDiff(float _a, float _b);
-
- /// Returns shortest distance linear interpolation between two angles.
- ///
- BX_CONST_FUNC float angleLerp(float _a, float _b, float _t);
+ BX_CONSTEXPR_FUNC float mul(float _a, float _b);
+ /// Returns result of multiply and add (_a * _b + _c).
///
- Vec3 load(const void* _ptr);
-
- ///
- void store(void* _ptr, const Vec3& _a);
-
- ///
- BX_CONSTEXPR_FUNC Vec3 abs(const Vec3& _a);
-
- ///
- BX_CONSTEXPR_FUNC Vec3 neg(const Vec3& _a);
-
- ///
- BX_CONSTEXPR_FUNC Vec3 add(const Vec3& _a, const Vec3& _b);
-
- ///
- BX_CONSTEXPR_FUNC Vec3 add(const Vec3& _a, float _b);
-
- ///
- BX_CONSTEXPR_FUNC Vec3 sub(const Vec3& _a, const Vec3& _b);
-
- ///
- BX_CONSTEXPR_FUNC Vec3 sub(const Vec3& _a, float _b);
-
- ///
- BX_CONSTEXPR_FUNC Vec3 mul(const Vec3& _a, const Vec3& _b);
-
- ///
- BX_CONSTEXPR_FUNC Vec3 mul(const Vec3& _a, float _b);
-
- ///
- BX_CONSTEXPR_FUNC Vec3 mad(const Vec3& _a, const Vec3& _b, const Vec3& _c);
-
- ///
- BX_CONSTEXPR_FUNC float dot(const Vec3& _a, const Vec3& _b);
-
- ///
- BX_CONSTEXPR_FUNC Vec3 cross(const Vec3& _a, const Vec3& _b);
-
- ///
- BX_CONST_FUNC float length(const Vec3& _a);
-
- ///
- BX_CONSTEXPR_FUNC Vec3 lerp(const Vec3& _a, const Vec3& _b, float _t);
-
- ///
- BX_CONSTEXPR_FUNC Vec3 lerp(const Vec3& _a, const Vec3& _b, const Vec3& _t);
+ BX_CONSTEXPR_FUNC float mad(float _a, float _b, float _c);
+ /// Returns reciprocal of _a.
///
- BX_CONST_FUNC Vec3 normalize(const Vec3& _a);
+ BX_CONSTEXPR_FUNC float rcp(float _a);
+ /// Returns the floating-point remainder of the division operation _a/_b.
///
- BX_CONSTEXPR_FUNC Vec3 min(const Vec3& _a, const Vec3& _b);
+ BX_CONST_FUNC float mod(float _a, float _b);
///
- BX_CONSTEXPR_FUNC Vec3 max(const Vec3& _a, const Vec3& _b);
+ BX_CONSTEXPR_FUNC bool isEqual(float _a, float _b, float _epsilon);
///
- BX_CONSTEXPR_FUNC Vec3 rcp(const Vec3& _a);
+ BX_CONST_FUNC bool isEqual(const float* _a, const float* _b, uint32_t _num, float _epsilon);
///
- void calcTangentFrame(Vec3& _outT, Vec3& _outB, const Vec3& _n);
+ BX_CONST_FUNC float wrap(float _a, float _wrap);
///
- void calcTangentFrame(Vec3& _outT, Vec3& _outB, const Vec3& _n, float _angle);
+ BX_CONSTEXPR_FUNC float step(float _edge, float _a);
///
- BX_CONST_FUNC Vec3 fromLatLong(float _u, float _v);
+ BX_CONSTEXPR_FUNC float pulse(float _a, float _start, float _end);
///
- void toLatLong(float* _outU, float* _outV, const Vec3& _dir);
+ BX_CONSTEXPR_FUNC float smoothStep(float _a);
///
- void vec3Add(float* _result, const float* _a, const float* _b);
+ BX_CONST_FUNC float invSmoothStep(float _a);
///
- void vec3Sub(float* _result, const float* _a, const float* _b);
+ BX_CONSTEXPR_FUNC float bias(float _time, float _bias);
///
- void vec3Mul(float* _result, const float* _a, const float* _b);
+ BX_CONSTEXPR_FUNC float gain(float _time, float _gain);
///
- void vec3Mul(float* _result, const float* _a, float _b);
+ BX_CONST_FUNC float angleDiff(float _a, float _b);
+ /// Returns shortest distance linear interpolation between two angles.
///
- float vec3Dot(const float* _a, const float* _b);
+ BX_CONST_FUNC float angleLerp(float _a, float _b, float _t);
///
- void vec3Cross(float* _result, const float* _a, const float* _b);
+ template<typename Ty>
+ Ty load(const void* _ptr);
///
- float vec3Length(const float* _a);
+ template<typename Ty>
+ void store(void* _ptr, const Ty& _a);
///
- float vec3Norm(float* _result, const float* _a);
+ BX_CONSTEXPR_FUNC Vec3 round(const Vec3 _a);
- /// Calculate tangent frame from normal.
///
- void vec3TangentFrame(const float* _n, float* _t, float* _b);
+ BX_CONSTEXPR_FUNC Vec3 abs(const Vec3 _a);
- /// Calculate tangent frame from normal and angle.
///
- void vec3TangentFrame(const float* _n, float* _t, float* _b, float _angle);
+ BX_CONSTEXPR_FUNC Vec3 neg(const Vec3 _a);
///
- void vec3FromLatLong(float* _vec, float _u, float _v);
+ BX_CONSTEXPR_FUNC Vec3 add(const Vec3 _a, const Vec3 _b);
- /// Convert direction to 2D latitude and longitude.
///
- /// @param[out] _outU U-coordinate.
- /// @param[out] _outV V-coordinate.
- /// @param[in] _dir Normalized direction vector.
- ///
- void vec3ToLatLong(float* _outU, float* _outV, const float* _dir);
+ BX_CONSTEXPR_FUNC Vec3 add(const Vec3 _a, float _b);
///
- void quatIdentity(float* _result);
+ BX_CONSTEXPR_FUNC Vec3 sub(const Vec3 _a, const Vec3 _b);
///
- void quatMove(float* _result, const float* _a);
+ BX_CONSTEXPR_FUNC Vec3 sub(const Vec3 _a, float _b);
///
- void quatMulXYZ(float* _result, const float* _qa, const float* _qb);
+ BX_CONSTEXPR_FUNC Vec3 mul(const Vec3 _a, const Vec3 _b);
///
- void quatMul(float* _result, const float* _qa, const float* _qb);
+ BX_CONSTEXPR_FUNC Vec3 mul(const Vec3 _a, float _b);
///
- void quatInvert(float* _result, const float* _quat);
+ BX_CONSTEXPR_FUNC Vec3 div(const Vec3 _a, const Vec3 _b);
///
- float quatDot(const float* _a, const float* _b);
+ BX_CONSTEXPR_FUNC Vec3 div(const Vec3 _a, float _b);
+ /// Returns result of negated multiply-sub operation -(_a * _b - _c) -> _c - _a * _b.
///
- void quatNorm(float* _result, const float* _quat);
+ BX_CONSTEXPR_FUNC Vec3 nms(const Vec3 _a, const float _b, const Vec3 _c);
+ /// Returns result of negated multiply-sub operation -(_a * _b - _c) -> _c - _a * _b.
///
- void quatToEuler(float* _result, const float* _quat);
+ BX_CONSTEXPR_FUNC Vec3 nms(const Vec3 _a, const Vec3 _b, const Vec3 _c);
///
- void quatRotateAxis(float* _result, const float* _axis, float _angle);
+ BX_CONSTEXPR_FUNC Vec3 mad(const Vec3 _a, const float _b, const Vec3 _c);
///
- void quatRotateX(float* _result, float _ax);
+ BX_CONSTEXPR_FUNC Vec3 mad(const Vec3 _a, const Vec3 _b, const Vec3 _c);
///
- void quatRotateY(float* _result, float _ay);
+ BX_CONSTEXPR_FUNC float dot(const Vec3 _a, const Vec3 _b);
///
- void quatRotateZ(float* _result, float _az);
+ BX_CONSTEXPR_FUNC Vec3 cross(const Vec3 _a, const Vec3 _b);
///
- void vec3MulQuat(float* _result, const float* _vec, const float* _quat);
+ BX_CONST_FUNC float length(const Vec3 _a);
///
- void mtxIdentity(float* _result);
+ BX_CONST_FUNC float distanceSq(const Vec3 _a, const Vec3 _b);
///
- void mtxTranslate(float* _result, float _tx, float _ty, float _tz);
+ BX_CONST_FUNC float distance(const Vec3 _a, const Vec3 _b);
///
- void mtxScale(float* _result, float _sx, float _sy, float _sz);
+ BX_CONSTEXPR_FUNC Vec3 lerp(const Vec3 _a, const Vec3 _b, float _t);
///
- void mtxScale(float* _result, float _scale);
+ BX_CONSTEXPR_FUNC Vec3 lerp(const Vec3 _a, const Vec3 _b, const Vec3 _t);
///
- void mtxFromNormal(float* _result, const float* _normal, float _scale, const float* _pos);
+ BX_CONST_FUNC Vec3 normalize(const Vec3 _a);
///
- void mtxFromNormal(float* _result, const float* _normal, float _scale, const float* _pos, float _angle);
+ BX_CONSTEXPR_FUNC Vec3 min(const Vec3 _a, const Vec3 _b);
///
- void mtxQuat(float* _result, const float* _quat);
+ BX_CONSTEXPR_FUNC Vec3 max(const Vec3 _a, const Vec3 _b);
+ /// Returns component wise reciprocal of _a.
///
- void mtxQuatTranslation(float* _result, const float* _quat, const float* _translation);
+ BX_CONSTEXPR_FUNC Vec3 rcp(const Vec3 _a);
///
- void mtxQuatTranslationHMD(float* _result, const float* _quat, const float* _translation);
+ BX_CONSTEXPR_FUNC bool isEqual(const Vec3 _a, const Vec3 _b, float _epsilon);
///
- void mtxLookAtLh(float* _result, const Vec3& _eye, const Vec3& _at, const Vec3& _up = { 0.0f, 1.0f, 0.0f });
+ void calcTangentFrame(Vec3& _outT, Vec3& _outB, const Vec3 _n);
///
- void mtxLookAtRh(float* _result, const Vec3& _eye, const Vec3& _at, const Vec3& _up = { 0.0f, 1.0f, 0.0f });
+ void calcTangentFrame(Vec3& _outT, Vec3& _outB, const Vec3 _n, float _angle);
///
- void mtxLookAt(float* _result, const Vec3& _eye, const Vec3& _at, const Vec3& _up = { 0.0f, 1.0f, 0.0f });
+ BX_CONST_FUNC Vec3 fromLatLong(float _u, float _v);
///
- void mtxProj(float* _result, float _ut, float _dt, float _lt, float _rt, float _near, float _far, bool _oglNdc);
+ void toLatLong(float* _outU, float* _outV, const Vec3 _dir);
///
- void mtxProj(float* _result, const float _fov[4], float _near, float _far, bool _oglNdc);
+ BX_CONSTEXPR_FUNC Quaternion invert(const Quaternion _a);
///
- void mtxProj(float* _result, float _fovy, float _aspect, float _near, float _far, bool _oglNdc);
+ BX_CONSTEXPR_FUNC Vec3 mulXyz(const Quaternion _a, const Quaternion _b);
///
- void mtxProjLh(float* _result, float _ut, float _dt, float _lt, float _rt, float _near, float _far, bool _oglNdc);
+ BX_CONSTEXPR_FUNC Quaternion add(const Quaternion _a, const Quaternion _b);
///
- void mtxProjLh(float* _result, const float _fov[4], float _near, float _far, bool _oglNdc);
+ BX_CONSTEXPR_FUNC Quaternion sub(const Quaternion _a, const Quaternion _b);
///
- void mtxProjLh(float* _result, float _fovy, float _aspect, float _near, float _far, bool _oglNdc);
+ BX_CONSTEXPR_FUNC Quaternion mul(const Quaternion _a, float _b);
///
- void mtxProjRh(float* _result, float _ut, float _dt, float _lt, float _rt, float _near, float _far, bool _oglNdc);
+ BX_CONSTEXPR_FUNC Quaternion mul(const Quaternion _a, const Quaternion _b);
///
- void mtxProjRh(float* _result, const float _fov[4], float _near, float _far, bool _oglNdc);
+ BX_CONSTEXPR_FUNC Vec3 mul(const Vec3 _v, const Quaternion _q);
///
- void mtxProjRh(float* _result, float _fovy, float _aspect, float _near, float _far, bool _oglNdc);
+ BX_CONSTEXPR_FUNC float dot(const Quaternion _a, const Quaternion _b);
///
- void mtxProjInf(float* _result, const float _fov[4], float _near, bool _oglNdc);
+ BX_CONSTEXPR_FUNC Quaternion normalize(const Quaternion _a);
///
- void mtxProjInf(float* _result, float _ut, float _dt, float _lt, float _rt, float _near, bool _oglNdc);
+ BX_CONSTEXPR_FUNC Quaternion lerp(const Quaternion _a, const Quaternion _b, float _t);
///
- void mtxProjInf(float* _result, float _fovy, float _aspect, float _near, bool _oglNdc);
+ BX_CONST_FUNC Quaternion fromEuler(const Vec3 _euler);
///
- void mtxProjInfLh(float* _result, float _ut, float _dt, float _lt, float _rt, float _near, bool _oglNdc);
+ BX_CONST_FUNC Vec3 toEuler(const Quaternion _a);
///
- void mtxProjInfLh(float* _result, const float _fov[4], float _near, bool _oglNdc);
+ BX_CONST_FUNC Vec3 toXAxis(const Quaternion _a);
///
- void mtxProjInfLh(float* _result, float _fovy, float _aspect, float _near, bool _oglNdc);
+ BX_CONST_FUNC Vec3 toYAxis(const Quaternion _a);
///
- void mtxProjInfRh(float* _result, float _ut, float _dt, float _lt, float _rt, float _near, bool _oglNdc);
+ BX_CONST_FUNC Vec3 toZAxis(const Quaternion _a);
///
- void mtxProjInfRh(float* _result, const float _fov[4], float _near, bool _oglNdc);
+ BX_CONST_FUNC Quaternion fromAxisAngle(const Vec3 _axis, float _angle);
///
- void mtxProjInfRh(float* _result, float _fovy, float _aspect, float _near, bool _oglNdc);
+ void toAxisAngle(Vec3& _outAxis, float& _outAngle, const Quaternion _a);
///
- void mtxProjRevInfLh(float* _result, float _ut, float _dt, float _lt, float _rt, float _near, bool _oglNdc);
+ BX_CONST_FUNC Quaternion rotateX(float _ax);
///
- void mtxProjRevInfLh(float* _result, const float _fov[4], float _near, bool _oglNdc);
+ BX_CONST_FUNC Quaternion rotateY(float _ay);
///
- void mtxProjRevInfLh(float* _result, float _fovy, float _aspect, float _near, bool _oglNdc);
+ BX_CONST_FUNC Quaternion rotateZ(float _az);
///
- void mtxProjRevInfRh(float* _result, float _ut, float _dt, float _lt, float _rt, float _near, bool _oglNdc);
+ BX_CONSTEXPR_FUNC bool isEqual(const Quaternion _a, const Quaternion _b, float _epsilon);
///
- void mtxProjRevInfRh(float* _result, const float _fov[4], float _near, bool _oglNdc);
+ void mtxIdentity(float* _result);
///
- void mtxProjRevInfRh(float* _result, float _fovy, float _aspect, float _near, bool _oglNdc);
+ void mtxTranslate(float* _result, float _tx, float _ty, float _tz);
///
- void mtxOrtho(float* _result, float _left, float _right, float _bottom, float _top, float _near, float _far, float _offset, bool _oglNdc);
+ void mtxScale(float* _result, float _sx, float _sy, float _sz);
///
- void mtxOrthoLh(float* _result, float _left, float _right, float _bottom, float _top, float _near, float _far, float _offset, bool _oglNdc);
+ void mtxScale(float* _result, float _scale);
///
- void mtxOrthoRh(float* _result, float _left, float _right, float _bottom, float _top, float _near, float _far, float _offset, bool _oglNdc);
+ void mtxFromNormal(
+ float* _result
+ , const Vec3& _normal
+ , float _scale
+ , const Vec3& _pos
+ );
+
+ ///
+ void mtxFromNormal(
+ float* _result
+ , const Vec3& _normal
+ , float _scale
+ , const Vec3& _pos
+ , float _angle
+ );
+
+ ///
+ void mtxFromQuaternion(float* _result, const Quaternion& _rotation);
+
+ ///
+ void mtxFromQuaternion(float* _result, const Quaternion& _rotation, const Vec3& _translation);
+
+ ///
+ void mtxLookAt(
+ float* _result
+ , const Vec3& _eye
+ , const Vec3& _at
+ , const Vec3& _up = { 0.0f, 1.0f, 0.0f }
+ , Handedness::Enum _handedness = Handedness::Left
+ );
+
+ ///
+ void mtxProj(
+ float* _result
+ , float _ut
+ , float _dt
+ , float _lt
+ , float _rt
+ , float _near
+ , float _far
+ , bool _homogeneousNdc
+ , Handedness::Enum _handedness = Handedness::Left
+ );
+
+ ///
+ void mtxProj(
+ float* _result
+ , const float _fov[4]
+ , float _near
+ , float _far
+ , bool _homogeneousNdc
+ , Handedness::Enum _handedness = Handedness::Left
+ );
+
+ ///
+ void mtxProj(
+ float* _result
+ , float _fovy
+ , float _aspect
+ , float _near
+ , float _far
+ , bool _homogeneousNdc
+ , Handedness::Enum _handedness = Handedness::Left
+ );
+
+ ///
+ void mtxProjInf(
+ float* _result
+ , const float _fov[4]
+ , float _near
+ , bool _homogeneousNdc
+ , Handedness::Enum _handedness = Handedness::Left
+ , NearFar::Enum _nearFar = NearFar::Default
+ );
+
+ ///
+ void mtxProjInf(
+ float* _result
+ , float _ut
+ , float _dt
+ , float _lt
+ , float _rt
+ , float _near
+ , bool _homogeneousNdc
+ , Handedness::Enum _handedness = Handedness::Left
+ , NearFar::Enum _nearFar = NearFar::Default
+ );
+
+ ///
+ void mtxProjInf(
+ float* _result
+ , float _fovy
+ , float _aspect
+ , float _near
+ , bool _homogeneousNdc
+ , Handedness::Enum _handedness = Handedness::Left
+ , NearFar::Enum _nearFar = NearFar::Default
+ );
+
+ ///
+ void mtxOrtho(
+ float* _result
+ , float _left
+ , float _right
+ , float _bottom
+ , float _top
+ , float _near
+ , float _far
+ , float _offset
+ , bool _homogeneousNdc
+ , Handedness::Enum _handedness = Handedness::Left
+ );
///
void mtxRotateX(float* _result, float _ax);
@@ -553,22 +666,27 @@ namespace bx
void mtxRotateZYX(float* _result, float _ax, float _ay, float _az);
///
- void mtxSRT(float* _result, float _sx, float _sy, float _sz, float _ax, float _ay, float _az, float _tx, float _ty, float _tz);
+ void mtxSRT(
+ float* _result
+ , float _sx
+ , float _sy
+ , float _sz
+ , float _ax
+ , float _ay
+ , float _az
+ , float _tx
+ , float _ty
+ , float _tz
+ );
///
- void vec3MulMtx(float* _result, const float* _vec, const float* _mat);
+ Vec3 mul(const Vec3& _vec, const float* _mat);
///
- void vec3MulMtxXyz0(float* _result, const float* _vec, const float* _mat);
+ Vec3 mulXyz0(const Vec3& _vec, const float* _mat);
///
- void vec3MulMtxH(float* _result, const float* _vec, const float* _mat);
-
- ///
- void vec4Mul(float* _result, const float* _a, const float* _b);
-
- ///
- void vec4Mul(float* _result, const float* _a, float _b);
+ Vec3 mulH(const Vec3& _vec, const float* _mat);
///
void vec4MulMtx(float* _result, const float* _vec, const float* _mat);
@@ -585,22 +703,26 @@ namespace bx
///
void mtxInverse(float* _result, const float* _a);
- /// Convert LH to RH projection matrix and vice versa.
///
- void mtxProjFlipHandedness(float* _dst, const float* _src);
+ void mtx3Cofactor(float* _result, const float* _a);
+
+ ///
+ void mtxCofactor(float* _result, const float* _a);
+
+ ///
+ Vec3 calcNormal(const Vec3& _va, const Vec3& _vb, const Vec3& _vc);
- /// Convert LH to RH view matrix and vice versa.
///
- void mtxViewFlipHandedness(float* _dst, const float* _src);
+ void calcPlane(Plane& _outPlane, const Vec3& _va, const Vec3& _vb, const Vec3& _vc);
///
- void calcNormal(float _result[3], const float _va[3], const float _vb[3], const float _vc[3]);
+ void calcPlane(Plane& _outPlane, const Vec3& _normal, const Vec3& _pos);
///
- void calcPlane(float _result[4], const float _va[3], const float _vb[3], const float _vc[3]);
+ BX_CONSTEXPR_FUNC float distance(const Plane& _plane, const Vec3& _pos);
///
- void calcPlane(float _result[4], const float _normal[3], const float _pos[3]);
+ BX_CONSTEXPR_FUNC bool isEqual(const Plane& _a, const Plane& _b, float _epsilon);
///
void calcLinearFit2D(float _result[2], const void* _points, uint32_t _stride, uint32_t _numPoints);
diff --git a/3rdparty/bx/include/bx/mpscqueue.h b/3rdparty/bx/include/bx/mpscqueue.h
index 003dfe8f4f8..7bb083b173e 100644
--- a/3rdparty/bx/include/bx/mpscqueue.h
+++ b/3rdparty/bx/include/bx/mpscqueue.h
@@ -1,6 +1,6 @@
/*
- * Copyright 2010-2018 Branimir Karadzic. All rights reserved.
- * License: https://github.com/bkaradzic/bx#license-bsd-2-clause
+ * Copyright 2010-2022 Branimir Karadzic. All rights reserved.
+ * License: https://github.com/bkaradzic/bx/blob/master/LICENSE
*/
#ifndef BX_MPSCQUEUE_H_HEADER_GUARD
@@ -17,8 +17,8 @@ namespace bx
class MpScUnboundedQueueT
{
BX_CLASS(MpScUnboundedQueueT
+ , NO_DEFAULT_CTOR
, NO_COPY
- , NO_ASSIGNMENT
);
public:
@@ -47,8 +47,8 @@ namespace bx
class MpScUnboundedBlockingQueue
{
BX_CLASS(MpScUnboundedBlockingQueue
+ , NO_DEFAULT_CTOR
, NO_COPY
- , NO_ASSIGNMENT
);
public:
diff --git a/3rdparty/bx/include/bx/mutex.h b/3rdparty/bx/include/bx/mutex.h
index 213fc68c70e..4713b5da500 100644
--- a/3rdparty/bx/include/bx/mutex.h
+++ b/3rdparty/bx/include/bx/mutex.h
@@ -1,6 +1,6 @@
/*
- * Copyright 2010-2018 Branimir Karadzic. All rights reserved.
- * License: https://github.com/bkaradzic/bx#license-bsd-2-clause
+ * Copyright 2010-2022 Branimir Karadzic. All rights reserved.
+ * License: https://github.com/bkaradzic/bx/blob/master/LICENSE
*/
#ifndef BX_MUTEX_H_HEADER_GUARD
@@ -15,7 +15,6 @@ namespace bx
{
BX_CLASS(Mutex
, NO_COPY
- , NO_ASSIGNMENT
);
public:
@@ -41,7 +40,6 @@ namespace bx
BX_CLASS(MutexScope
, NO_DEFAULT_CTOR
, NO_COPY
- , NO_ASSIGNMENT
);
public:
diff --git a/3rdparty/bx/include/bx/os.h b/3rdparty/bx/include/bx/os.h
index 92edacd21d1..4de2f6d8b8d 100644
--- a/3rdparty/bx/include/bx/os.h
+++ b/3rdparty/bx/include/bx/os.h
@@ -1,12 +1,11 @@
/*
- * Copyright 2010-2018 Branimir Karadzic. All rights reserved.
- * License: https://github.com/bkaradzic/bx#license-bsd-2-clause
+ * Copyright 2010-2022 Branimir Karadzic. All rights reserved.
+ * License: https://github.com/bkaradzic/bx/blob/master/LICENSE
*/
#ifndef BX_OS_H_HEADER_GUARD
#define BX_OS_H_HEADER_GUARD
-#include "debug.h"
#include "filepath.h"
#if BX_PLATFORM_OSX
@@ -41,6 +40,10 @@ namespace bx
void* dlsym(void* _handle, const StringView& _symbol);
///
+ template<typename ProtoT>
+ ProtoT dlsym(void* _handle, const StringView& _symbol);
+
+ ///
bool getEnv(char* _out, uint32_t* _inOutSize, const StringView& _name);
///
@@ -52,6 +55,11 @@ namespace bx
///
void* exec(const char* const* _argv);
+ ///
+ BX_NO_RETURN void exit(int32_t _exitCode);
+
} // namespace bx
+#include "inline/os.inl"
+
#endif // BX_OS_H_HEADER_GUARD
diff --git a/3rdparty/bx/include/bx/pixelformat.h b/3rdparty/bx/include/bx/pixelformat.h
index c75b39836d5..c556b014e56 100644
--- a/3rdparty/bx/include/bx/pixelformat.h
+++ b/3rdparty/bx/include/bx/pixelformat.h
@@ -1,6 +1,6 @@
/*
- * Copyright 2011-2018 Branimir Karadzic. All rights reserved.
- * License: https://github.com/bkaradzic/bx#license-bsd-2-clause
+ * Copyright 2011-2022 Branimir Karadzic. All rights reserved.
+ * License: https://github.com/bkaradzic/bx/blob/master/LICENSE
*/
#ifndef BX_PIXEL_FORMAT_H_HEADER_GUARD
@@ -41,6 +41,10 @@ namespace bx
///
float fromSnorm(int32_t _value, float _scale);
+ // A8
+ void packA8(void* _dst, const float* _src);
+ void unpackA8(float* _dst, const void* _src);
+
// R8
void packR8(void* _dst, const float* _src);
void unpackR8(float* _dst, const void* _src);
@@ -205,6 +209,10 @@ namespace bx
void packRgba32F(void* _dst, const float* _src);
void unpackRgba32F(float* _dst, const void* _src);
+ // B5G6R5
+ void packB5G6R5(void* _dst, const float* _src);
+ void unpackB5G6R5(float* _dst, const void* _src);
+
// R5G6B5
void packR5G6B5(void* _dst, const float* _src);
void unpackR5G6B5(float* _dst, const void* _src);
@@ -213,7 +221,7 @@ namespace bx
void packRgba4(void* _dst, const float* _src);
void unpackRgba4(float* _dst, const void* _src);
- // RGBA4
+ // BGRA4
void packBgra4(void* _dst, const float* _src);
void unpackBgra4(float* _dst, const void* _src);
diff --git a/3rdparty/bx/include/bx/platform.h b/3rdparty/bx/include/bx/platform.h
index e0031ec2c38..f14f9b680bf 100644
--- a/3rdparty/bx/include/bx/platform.h
+++ b/3rdparty/bx/include/bx/platform.h
@@ -1,6 +1,6 @@
/*
- * Copyright 2010-2018 Branimir Karadzic. All rights reserved.
- * License: https://github.com/bkaradzic/bx#license-bsd-2-clause
+ * Copyright 2010-2022 Branimir Karadzic. All rights reserved.
+ * License: https://github.com/bkaradzic/bx/blob/master/LICENSE
*/
#ifndef BX_PLATFORM_H_HEADER_GUARD
@@ -16,7 +16,7 @@
#define BX_COMPILER_GCC 0
#define BX_COMPILER_MSVC 0
-// Endianess
+// Endianness
#define BX_CPU_ENDIAN_BIG 0
#define BX_CPU_ENDIAN_LITTLE 0
@@ -30,32 +30,36 @@
// C Runtime
#define BX_CRT_BIONIC 0
+#define BX_CRT_BSD 0
#define BX_CRT_GLIBC 0
#define BX_CRT_LIBCXX 0
#define BX_CRT_MINGW 0
#define BX_CRT_MSVC 0
#define BX_CRT_NEWLIB 0
-#ifndef BX_CRT_MUSL
-# define BX_CRT_MUSL 0
-#endif // BX_CRT_MUSL
-
#ifndef BX_CRT_NONE
# define BX_CRT_NONE 0
#endif // BX_CRT_NONE
+// Language standard version
+#define BX_LANGUAGE_CPP14 201402L
+#define BX_LANGUAGE_CPP17 201703L
+#define BX_LANGUAGE_CPP20 202002L
+#define BX_LANGUAGE_CPP23 202207L
+
// Platform
#define BX_PLATFORM_ANDROID 0
#define BX_PLATFORM_BSD 0
#define BX_PLATFORM_EMSCRIPTEN 0
+#define BX_PLATFORM_HAIKU 0
#define BX_PLATFORM_HURD 0
#define BX_PLATFORM_IOS 0
#define BX_PLATFORM_LINUX 0
#define BX_PLATFORM_NX 0
#define BX_PLATFORM_OSX 0
#define BX_PLATFORM_PS4 0
+#define BX_PLATFORM_PS5 0
#define BX_PLATFORM_RPI 0
-#define BX_PLATFORM_STEAMLINK 0
#define BX_PLATFORM_WINDOWS 0
#define BX_PLATFORM_WINRT 0
#define BX_PLATFORM_XBOXONE 0
@@ -133,12 +137,18 @@
#endif //
#if BX_CPU_PPC
-# undef BX_CPU_ENDIAN_BIG
-# define BX_CPU_ENDIAN_BIG 1
+// __BIG_ENDIAN__ is gcc predefined macro
+# if defined(__BIG_ENDIAN__)
+# undef BX_CPU_ENDIAN_BIG
+# define BX_CPU_ENDIAN_BIG 1
+# else
+# undef BX_CPU_ENDIAN_LITTLE
+# define BX_CPU_ENDIAN_LITTLE 1
+# endif
#else
# undef BX_CPU_ENDIAN_LITTLE
# define BX_CPU_ENDIAN_LITTLE 1
-#endif // BX_PLATFORM_
+#endif // BX_CPU_PPC
// http://sourceforge.net/apps/mediawiki/predef/index.php?title=Operating_Systems
#if defined(_DURANGO) || defined(_XBOX_ONE)
@@ -176,10 +186,6 @@
# include <sys/cdefs.h> // Defines __BIONIC__ and includes android/api-level.h
# undef BX_PLATFORM_ANDROID
# define BX_PLATFORM_ANDROID __ANDROID_API__
-#elif defined(__STEAMLINK__)
-// SteamLink compiler defines __linux__
-# undef BX_PLATFORM_STEAMLINK
-# define BX_PLATFORM_STEAMLINK 1
#elif defined(__VCCOREVER__)
// RaspberryPi compiler defines __linux__
# undef BX_PLATFORM_RPI
@@ -200,6 +206,9 @@
#elif defined(__ORBIS__)
# undef BX_PLATFORM_PS4
# define BX_PLATFORM_PS4 1
+#elif defined(__PROSPERO__)
+# undef BX_PLATFORM_PS5
+# define BX_PLATFORM_PS5 1
#elif defined(__FreeBSD__) \
|| defined(__FreeBSD_kernel__) \
|| defined(__NetBSD__) \
@@ -213,6 +222,9 @@
#elif defined(__NX__)
# undef BX_PLATFORM_NX
# define BX_PLATFORM_NX 1
+#elif defined(__HAIKU__)
+# undef BX_PLATFORM_HAIKU
+# define BX_PLATFORM_HAIKU 1
#endif //
#if !BX_CRT_NONE
@@ -229,54 +241,97 @@
# elif defined(__MINGW32__) || defined(__MINGW64__)
# undef BX_CRT_MINGW
# define BX_CRT_MINGW 1
-# elif defined(__apple_build_version__) || defined(__ORBIS__) || defined(__EMSCRIPTEN__) || defined(__llvm__)
+# elif defined(__apple_build_version__) || defined(__ORBIS__) || defined(__EMSCRIPTEN__) || defined(__llvm__) || defined(__HAIKU__)
# undef BX_CRT_LIBCXX
# define BX_CRT_LIBCXX 1
+# elif BX_PLATFORM_BSD
+# undef BX_CRT_BSD
+# define BX_CRT_BSD 1
# endif //
# if !BX_CRT_BIONIC \
+ && !BX_CRT_BSD \
&& !BX_CRT_GLIBC \
&& !BX_CRT_LIBCXX \
&& !BX_CRT_MINGW \
&& !BX_CRT_MSVC \
- && !BX_CRT_MUSL \
&& !BX_CRT_NEWLIB
# undef BX_CRT_NONE
# define BX_CRT_NONE 1
# endif // BX_CRT_*
#endif // !BX_CRT_NONE
+///
#define BX_PLATFORM_POSIX (0 \
|| BX_PLATFORM_ANDROID \
|| BX_PLATFORM_BSD \
|| BX_PLATFORM_EMSCRIPTEN \
+ || BX_PLATFORM_HAIKU \
|| BX_PLATFORM_HURD \
|| BX_PLATFORM_IOS \
|| BX_PLATFORM_LINUX \
|| BX_PLATFORM_NX \
|| BX_PLATFORM_OSX \
|| BX_PLATFORM_PS4 \
+ || BX_PLATFORM_PS5 \
|| BX_PLATFORM_RPI \
- || BX_PLATFORM_STEAMLINK \
)
+///
#define BX_PLATFORM_NONE !(0 \
|| BX_PLATFORM_ANDROID \
|| BX_PLATFORM_BSD \
|| BX_PLATFORM_EMSCRIPTEN \
+ || BX_PLATFORM_HAIKU \
|| BX_PLATFORM_HURD \
|| BX_PLATFORM_IOS \
|| BX_PLATFORM_LINUX \
|| BX_PLATFORM_NX \
|| BX_PLATFORM_OSX \
|| BX_PLATFORM_PS4 \
+ || BX_PLATFORM_PS5 \
|| BX_PLATFORM_RPI \
- || BX_PLATFORM_STEAMLINK \
|| BX_PLATFORM_WINDOWS \
|| BX_PLATFORM_WINRT \
|| BX_PLATFORM_XBOXONE \
)
+///
+#define BX_PLATFORM_OS_CONSOLE (0 \
+ || BX_PLATFORM_NX \
+ || BX_PLATFORM_PS4 \
+ || BX_PLATFORM_PS5 \
+ || BX_PLATFORM_WINRT \
+ || BX_PLATFORM_XBOXONE \
+ )
+
+///
+#define BX_PLATFORM_OS_DESKTOP (0 \
+ || BX_PLATFORM_BSD \
+ || BX_PLATFORM_HAIKU \
+ || BX_PLATFORM_HURD \
+ || BX_PLATFORM_LINUX \
+ || BX_PLATFORM_OSX \
+ || BX_PLATFORM_WINDOWS \
+ )
+
+///
+#define BX_PLATFORM_OS_EMBEDDED (0 \
+ || BX_PLATFORM_RPI \
+ )
+
+///
+#define BX_PLATFORM_OS_MOBILE (0 \
+ || BX_PLATFORM_ANDROID \
+ || BX_PLATFORM_IOS \
+ )
+
+///
+#define BX_PLATFORM_OS_WEB (0 \
+ || BX_PLATFORM_EMSCRIPTEN \
+ )
+
+///
#if BX_COMPILER_GCC
# define BX_COMPILER_NAME "GCC " \
BX_STRINGIZE(__GNUC__) "." \
@@ -288,7 +343,11 @@
BX_STRINGIZE(__clang_minor__) "." \
BX_STRINGIZE(__clang_patchlevel__)
#elif BX_COMPILER_MSVC
-# if BX_COMPILER_MSVC >= 1910 // Visual Studio 2017
+# if BX_COMPILER_MSVC >= 1930 // Visual Studio 2022
+# define BX_COMPILER_NAME "MSVC 17.0"
+# elif BX_COMPILER_MSVC >= 1920 // Visual Studio 2019
+# define BX_COMPILER_NAME "MSVC 16.0"
+# elif BX_COMPILER_MSVC >= 1910 // Visual Studio 2017
# define BX_COMPILER_NAME "MSVC 15.0"
# elif BX_COMPILER_MSVC >= 1900 // Visual Studio 2015
# define BX_COMPILER_NAME "MSVC 14.0"
@@ -315,6 +374,8 @@
BX_STRINGIZE(__EMSCRIPTEN_major__) "." \
BX_STRINGIZE(__EMSCRIPTEN_minor__) "." \
BX_STRINGIZE(__EMSCRIPTEN_tiny__)
+#elif BX_PLATFORM_HAIKU
+# define BX_PLATFORM_NAME "Haiku"
#elif BX_PLATFORM_HURD
# define BX_PLATFORM_NAME "Hurd"
#elif BX_PLATFORM_IOS
@@ -329,10 +390,10 @@
# define BX_PLATFORM_NAME "OSX"
#elif BX_PLATFORM_PS4
# define BX_PLATFORM_NAME "PlayStation 4"
+#elif BX_PLATFORM_PS5
+# define BX_PLATFORM_NAME "PlayStation 5"
#elif BX_PLATFORM_RPI
# define BX_PLATFORM_NAME "RaspberryPi"
-#elif BX_PLATFORM_STEAMLINK
-# define BX_PLATFORM_NAME "SteamLink"
#elif BX_PLATFORM_WINDOWS
# define BX_PLATFORM_NAME "Windows"
#elif BX_PLATFORM_WINRT
@@ -359,6 +420,8 @@
#if BX_CRT_BIONIC
# define BX_CRT_NAME "Bionic libc"
+#elif BX_CRT_BSD
+# define BX_CRT_NAME "BSD libc"
#elif BX_CRT_GLIBC
# define BX_CRT_NAME "GNU C Library"
#elif BX_CRT_MSVC
@@ -369,8 +432,6 @@
# define BX_CRT_NAME "Clang C Library"
#elif BX_CRT_NEWLIB
# define BX_CRT_NAME "Newlib"
-#elif BX_CRT_MUSL
-# define BX_CRT_NAME "musl libc"
#elif BX_CRT_NONE
# define BX_CRT_NAME "None"
#else
@@ -383,4 +444,21 @@
# define BX_ARCH_NAME "64-bit"
#endif // BX_ARCH_
+#if defined(__cplusplus)
+# if __cplusplus < BX_LANGUAGE_CPP14
+# error "C++14 standard support is required to build."
+# elif __cplusplus < BX_LANGUAGE_CPP17
+# define BX_CPP_NAME "C++14"
+# elif __cplusplus < BX_LANGUAGE_CPP20
+# define BX_CPP_NAME "C++17"
+# elif __cplusplus < BX_LANGUAGE_CPP23
+# define BX_CPP_NAME "C++20"
+# else
+// See: https://gist.github.com/bkaradzic/2e39896bc7d8c34e042b#orthodox-c
+# define BX_CPP_NAME "C++WayTooModern"
+# endif // BX_CPP_NAME
+#else
+# define BX_CPP_NAME "C++Unknown"
+#endif // defined(__cplusplus)
+
#endif // BX_PLATFORM_H_HEADER_GUARD
diff --git a/3rdparty/bx/include/bx/process.h b/3rdparty/bx/include/bx/process.h
index 8369829527b..e963b90e309 100644
--- a/3rdparty/bx/include/bx/process.h
+++ b/3rdparty/bx/include/bx/process.h
@@ -1,6 +1,6 @@
/*
- * Copyright 2010-2018 Branimir Karadzic. All rights reserved.
- * License: https://github.com/bkaradzic/bx#license-bsd-2-clause
+ * Copyright 2010-2022 Branimir Karadzic. All rights reserved.
+ * License: https://github.com/bkaradzic/bx/blob/master/LICENSE
*/
#ifndef BX_PROCESS_H_HEADER_GUARD
diff --git a/3rdparty/bx/include/bx/readerwriter.h b/3rdparty/bx/include/bx/readerwriter.h
index 0d8e13545a8..01e1d1ca2a8 100644
--- a/3rdparty/bx/include/bx/readerwriter.h
+++ b/3rdparty/bx/include/bx/readerwriter.h
@@ -1,6 +1,6 @@
/*
- * Copyright 2010-2018 Branimir Karadzic. All rights reserved.
- * License: https://github.com/bkaradzic/bx#license-bsd-2-clause
+ * Copyright 2010-2022 Branimir Karadzic. All rights reserved.
+ * License: https://github.com/bkaradzic/bx/blob/master/LICENSE
*/
#ifndef BX_READERWRITER_H_HEADER_GUARD
@@ -10,105 +10,128 @@
#include "endian.h"
#include "error.h"
#include "filepath.h"
+#include "math.h"
#include "string.h"
#include "uint32_t.h"
-BX_ERROR_RESULT(BX_ERROR_READERWRITER_OPEN, BX_MAKEFOURCC('R', 'W', 0, 1) );
-BX_ERROR_RESULT(BX_ERROR_READERWRITER_READ, BX_MAKEFOURCC('R', 'W', 0, 2) );
-BX_ERROR_RESULT(BX_ERROR_READERWRITER_WRITE, BX_MAKEFOURCC('R', 'W', 0, 3) );
-BX_ERROR_RESULT(BX_ERROR_READERWRITER_EOF, BX_MAKEFOURCC('R', 'W', 0, 4) );
-BX_ERROR_RESULT(BX_ERROR_READERWRITER_ALREADY_OPEN, BX_MAKEFOURCC('R', 'W', 0, 5) );
-
namespace bx
{
- ///
+ BX_ERROR_RESULT(kErrorReaderWriterOpen, BX_MAKEFOURCC('b', 'x', 2, 1) );
+ BX_ERROR_RESULT(kErrorReaderWriterRead, BX_MAKEFOURCC('b', 'x', 2, 2) );
+ BX_ERROR_RESULT(kErrorReaderWriterWrite, BX_MAKEFOURCC('b', 'x', 2, 3) );
+ BX_ERROR_RESULT(kErrorReaderWriterEof, BX_MAKEFOURCC('b', 'x', 2, 4) );
+ BX_ERROR_RESULT(kErrorReaderWriterAlreadyOpen, BX_MAKEFOURCC('b', 'x', 2, 5) );
+
+ /// The position from where offset is added.
struct Whence
{
+ /// Whence values:
enum Enum
{
- Begin,
- Current,
- End,
+ Begin, //!< From beginning of file.
+ Current, //!< From current position of file.
+ End, //!< From end of file.
};
};
- ///
+ /// Reader interface.
struct BX_NO_VTABLE ReaderI
{
+ ///
virtual ~ReaderI() = 0;
+
+ ///
virtual int32_t read(void* _data, int32_t _size, Error* _err) = 0;
};
- ///
+ /// Writer interface.
struct BX_NO_VTABLE WriterI
{
+ ///
virtual ~WriterI() = 0;
+
+ ///
virtual int32_t write(const void* _data, int32_t _size, Error* _err) = 0;
};
- ///
+ /// Seeker interface.
struct BX_NO_VTABLE SeekerI
{
+ ///
virtual ~SeekerI() = 0;
+
+ ///
virtual int64_t seek(int64_t _offset = 0, Whence::Enum _whence = Whence::Current) = 0;
};
- ///
+ /// Reader seeker interface.
struct BX_NO_VTABLE ReaderSeekerI : public ReaderI, public SeekerI
{
};
- ///
+ /// Writer seeker interface.
struct BX_NO_VTABLE WriterSeekerI : public WriterI, public SeekerI
{
};
- ///
+ /// Open for reading interface.
struct BX_NO_VTABLE ReaderOpenI
{
+ ///
virtual ~ReaderOpenI() = 0;
- virtual bool open(const FilePath& _filePath, Error* _err) = 0;
+
+ ///
+ virtual bool open(const FilePath& _filePath, Error* _err = ErrorIgnore{}) = 0;
};
- ///
+ /// Open for writing interface.
struct BX_NO_VTABLE WriterOpenI
{
+ ///
virtual ~WriterOpenI() = 0;
- virtual bool open(const FilePath& _filePath, bool _append, Error* _err) = 0;
+
+ ///
+ virtual bool open(const FilePath& _filePath, bool _append = false, Error* _err = ErrorIgnore{}) = 0;
};
- ///
+ /// Open process interface.
struct BX_NO_VTABLE ProcessOpenI
{
+ ///
virtual ~ProcessOpenI() = 0;
- virtual bool open(const FilePath& _filePath, const StringView& _args, Error* _err) = 0;
+
+ ///
+ virtual bool open(const FilePath& _filePath, const StringView& _args, Error* _err = ErrorIgnore{}) = 0;
};
- ///
+ /// Closer interface.
struct BX_NO_VTABLE CloserI
{
+ ///
virtual ~CloserI() = 0;
+
+ ///
virtual void close() = 0;
};
- ///
+ /// File reader interface.
struct BX_NO_VTABLE FileReaderI : public ReaderOpenI, public CloserI, public ReaderSeekerI
{
};
- ///
+ /// File writer interface.
struct BX_NO_VTABLE FileWriterI : public WriterOpenI, public CloserI, public WriterSeekerI
{
};
- ///
+ /// Memory block interface.
struct BX_NO_VTABLE MemoryBlockI
{
virtual void* more(uint32_t _size = 0) = 0;
virtual uint32_t getSize() = 0;
};
- ///
+ /// Static memory block interface.
class StaticMemoryBlock : public MemoryBlockI
{
public:
@@ -125,11 +148,11 @@ namespace bx
virtual uint32_t getSize() override;
private:
- void* m_data;
+ void* m_data;
uint32_t m_size;
};
- ///
+ /// Memory block.
class MemoryBlock : public MemoryBlockI
{
public:
@@ -147,11 +170,11 @@ namespace bx
private:
AllocatorI* m_allocator;
- void* m_data;
- uint32_t m_size;
+ void* m_data;
+ uint32_t m_size;
};
- /// Sizer writer. Dummy writter that only counts number of bytes written into it.
+ /// Sizer writer. Dummy writer that only counts number of bytes written into it.
class SizerWriter : public WriterSeekerI
{
public:
@@ -172,7 +195,7 @@ namespace bx
int64_t m_top;
};
- ///
+ /// Memory reader.
class MemoryReader : public ReaderSeekerI
{
public:
@@ -203,7 +226,7 @@ namespace bx
int64_t m_top;
};
- ///
+ /// Memory writer.
class MemoryWriter : public WriterSeekerI
{
public:
@@ -222,9 +245,9 @@ namespace bx
private:
MemoryBlockI* m_memBlock;
uint8_t* m_data;
- int64_t m_pos;
- int64_t m_top;
- int64_t m_size;
+ int64_t m_pos;
+ int64_t m_top;
+ int64_t m_size;
};
/// Static (fixed size) memory block writer.
@@ -242,49 +265,49 @@ namespace bx
};
/// Read data.
- int32_t read(ReaderI* _reader, void* _data, int32_t _size, Error* _err = NULL);
+ int32_t read(ReaderI* _reader, void* _data, int32_t _size, Error* _err);
/// Read value.
template<typename Ty>
- int32_t read(ReaderI* _reader, Ty& _value, Error* _err = NULL);
+ int32_t read(ReaderI* _reader, Ty& _value, Error* _err);
- /// Read value and converts it to host endianess. _fromLittleEndian specifies
- /// underlying stream endianess.
+ /// Read value and converts it to host endianness. _fromLittleEndian specifies
+ /// underlying stream endianness.
template<typename Ty>
- int32_t readHE(ReaderI* _reader, Ty& _value, bool _fromLittleEndian, Error* _err = NULL);
+ int32_t readHE(ReaderI* _reader, Ty& _value, bool _fromLittleEndian, Error* _err);
/// Write data.
- int32_t write(WriterI* _writer, const void* _data, int32_t _size, Error* _err = NULL);
+ int32_t write(WriterI* _writer, const void* _data, int32_t _size, Error* _err);
/// Write C string.
- int32_t write(WriterI* _writer, const char* _str, Error* _err = NULL);
+ int32_t write(WriterI* _writer, const char* _str, Error* _err);
/// Write string view.
- int32_t write(WriterI* _writer, const StringView& _str, Error* _err = NULL);
+ int32_t write(WriterI* _writer, const StringView& _str, Error* _err);
- /// Write formated string.
+ /// Write formatted string.
int32_t write(WriterI* _writer, const StringView& _format, va_list _argList, Error* _err);
- /// Write formated string.
+ /// Write formatted string.
int32_t write(WriterI* _writer, Error* _err, const StringView* _format, ...);
- /// Write formated string.
+ /// Write formatted string.
int32_t write(WriterI* _writer, Error* _err, const char* _format, ...);
/// Write repeat the same value.
- int32_t writeRep(WriterI* _writer, uint8_t _byte, int32_t _size, Error* _err = NULL);
+ int32_t writeRep(WriterI* _writer, uint8_t _byte, int32_t _size, Error* _err);
/// Write value.
template<typename Ty>
- int32_t write(WriterI* _writer, const Ty& _value, Error* _err = NULL);
+ int32_t write(WriterI* _writer, const Ty& _value, Error* _err);
/// Write value as little endian.
template<typename Ty>
- int32_t writeLE(WriterI* _writer, const Ty& _value, Error* _err = NULL);
+ int32_t writeLE(WriterI* _writer, const Ty& _value, Error* _err);
/// Write value as big endian.
template<typename Ty>
- int32_t writeBE(WriterI* _writer, const Ty& _value, Error* _err = NULL);
+ int32_t writeBE(WriterI* _writer, const Ty& _value, Error* _err);
/// Skip _offset bytes forward.
int64_t skip(SeekerI* _seeker, int64_t _offset);
@@ -299,26 +322,26 @@ namespace bx
int64_t getRemain(SeekerI* _seeker);
/// Peek data.
- int32_t peek(ReaderSeekerI* _reader, void* _data, int32_t _size, Error* _err = NULL);
+ int32_t peek(ReaderSeekerI* _reader, void* _data, int32_t _size, Error* _err);
/// Peek value.
template<typename Ty>
- int32_t peek(ReaderSeekerI* _reader, Ty& _value, Error* _err = NULL);
+ int32_t peek(ReaderSeekerI* _reader, Ty& _value, Error* _err);
/// Align reader stream.
- int32_t align(ReaderSeekerI* _reader, uint32_t _alignment, Error* _err = NULL);
+ int32_t align(ReaderSeekerI* _reader, uint32_t _alignment, Error* _err);
/// Align writer stream (pads stream with zeros).
- int32_t align(WriterSeekerI* _writer, uint32_t _alignment, Error* _err = NULL);
+ int32_t align(WriterSeekerI* _writer, uint32_t _alignment, Error* _err);
/// Open for read.
- bool open(ReaderOpenI* _reader, const FilePath& _filePath, Error* _err = NULL);
+ bool open(ReaderOpenI* _reader, const FilePath& _filePath, Error* _err = ErrorIgnore{});
- /// Open fro write.
- bool open(WriterOpenI* _writer, const FilePath& _filePath, bool _append = false, Error* _err = NULL);
+ /// Open for write.
+ bool open(WriterOpenI* _writer, const FilePath& _filePath, bool _append = false, Error* _err = ErrorIgnore{});
/// Open process.
- bool open(ProcessOpenI* _process, const FilePath& _filePath, const StringView& _args, Error* _err = NULL);
+ bool open(ProcessOpenI* _process, const FilePath& _filePath, const StringView& _args, Error* _err = ErrorIgnore{});
/// Close.
void close(CloserI* _reader);
diff --git a/3rdparty/bx/include/bx/ringbuffer.h b/3rdparty/bx/include/bx/ringbuffer.h
index db44da8432e..84eefddc85f 100644
--- a/3rdparty/bx/include/bx/ringbuffer.h
+++ b/3rdparty/bx/include/bx/ringbuffer.h
@@ -1,6 +1,6 @@
/*
- * Copyright 2010-2018 Branimir Karadzic. All rights reserved.
- * License: https://github.com/bkaradzic/bx#license-bsd-2-clause
+ * Copyright 2010-2022 Branimir Karadzic. All rights reserved.
+ * License: https://github.com/bkaradzic/bx/blob/master/LICENSE
*/
#ifndef BX_RINGBUFFER_H_HEADER_GUARD
@@ -16,8 +16,8 @@ namespace bx
class RingBufferControl
{
BX_CLASS(RingBufferControl
+ , NO_DEFAULT_CTOR
, NO_COPY
- , NO_ASSIGNMENT
);
public:
@@ -55,8 +55,8 @@ namespace bx
class SpScRingBufferControl
{
BX_CLASS(SpScRingBufferControl
+ , NO_DEFAULT_CTOR
, NO_COPY
- , NO_ASSIGNMENT
);
public:
@@ -97,7 +97,6 @@ namespace bx
BX_CLASS(ReadRingBufferT
, NO_DEFAULT_CTOR
, NO_COPY
- , NO_ASSIGNMENT
);
public:
@@ -140,7 +139,6 @@ namespace bx
BX_CLASS(WriteRingBufferT
, NO_DEFAULT_CTOR
, NO_COPY
- , NO_ASSIGNMENT
);
public:
diff --git a/3rdparty/bx/include/bx/rng.h b/3rdparty/bx/include/bx/rng.h
index 87ba511e513..0266eff8326 100644
--- a/3rdparty/bx/include/bx/rng.h
+++ b/3rdparty/bx/include/bx/rng.h
@@ -1,6 +1,6 @@
/*
- * Copyright 2010-2018 Branimir Karadzic. All rights reserved.
- * License: https://github.com/bkaradzic/bx#license-bsd-2-clause
+ * Copyright 2010-2022 Branimir Karadzic. All rights reserved.
+ * License: https://github.com/bkaradzic/bx/blob/master/LICENSE
*/
#ifndef BX_RNG_H_HEADER_GUARD
@@ -67,9 +67,7 @@ namespace bx
template <typename Ty>
bx::Vec3 randUnitHemisphere(Ty* _rng, const bx::Vec3& _normal);
- /// Sampling with Hammersley and Halton Points
- /// http://www.cse.cuhk.edu.hk/~ttwong/papers/udpoint/udpoints.html
- ///
+ /// Sampling with Hammersley and Halton Points.
void generateSphereHammersley(void* _data, uint32_t _stride, uint32_t _num, float _scale = 1.0f);
/// Fisher-Yates shuffle.
diff --git a/3rdparty/bx/include/bx/semaphore.h b/3rdparty/bx/include/bx/semaphore.h
index 6d944ed2919..7748bc8e289 100644
--- a/3rdparty/bx/include/bx/semaphore.h
+++ b/3rdparty/bx/include/bx/semaphore.h
@@ -1,6 +1,6 @@
/*
- * Copyright 2010-2018 Branimir Karadzic. All rights reserved.
- * License: https://github.com/bkaradzic/bx#license-bsd-2-clause
+ * Copyright 2010-2022 Branimir Karadzic. All rights reserved.
+ * License: https://github.com/bkaradzic/bx/blob/master/LICENSE
*/
#ifndef BX_SEM_H_HEADER_GUARD
@@ -15,7 +15,6 @@ namespace bx
{
BX_CLASS(Semaphore
, NO_COPY
- , NO_ASSIGNMENT
);
public:
diff --git a/3rdparty/bx/include/bx/settings.h b/3rdparty/bx/include/bx/settings.h
index 7797cfac2bf..76e4fc3901d 100644
--- a/3rdparty/bx/include/bx/settings.h
+++ b/3rdparty/bx/include/bx/settings.h
@@ -1,6 +1,6 @@
/*
- * Copyright 2011-2018 Branimir Karadzic. All rights reserved.
- * License: https://github.com/bkaradzic/bx#license-bsd-2-clause
+ * Copyright 2011-2022 Branimir Karadzic. All rights reserved.
+ * License: https://github.com/bkaradzic/bx/blob/master/LICENSE
*/
#ifndef BX_SETTINGS_H_HEADER_GUARD
@@ -51,10 +51,10 @@ namespace bx
};
///
- int32_t read(ReaderSeekerI* _reader, Settings& _settings, Error* _err = NULL);
+ int32_t read(ReaderSeekerI* _reader, Settings& _settings, Error* _err);
///
- int32_t write(WriterI* _writer, const Settings& _settings, Error* _err = NULL);
+ int32_t write(WriterI* _writer, const Settings& _settings, Error* _err);
} // namespace bx
diff --git a/3rdparty/bx/include/bx/simd_t.h b/3rdparty/bx/include/bx/simd_t.h
index 33c3f48a954..f2be8f6d0ae 100644
--- a/3rdparty/bx/include/bx/simd_t.h
+++ b/3rdparty/bx/include/bx/simd_t.h
@@ -1,6 +1,6 @@
/*
- * Copyright 2010-2018 Branimir Karadzic. All rights reserved.
- * License: https://github.com/bkaradzic/bx#license-bsd-2-clause
+ * Copyright 2010-2022 Branimir Karadzic. All rights reserved.
+ * License: https://github.com/bkaradzic/bx/blob/master/LICENSE
*/
#ifndef BX_SIMD_T_H_HEADER_GUARD
@@ -32,7 +32,7 @@
# include <xmmintrin.h> // __m128
# undef BX_SIMD_SSE
# define BX_SIMD_SSE 1
-#elif defined(__ARM_NEON__) && !BX_COMPILER_CLANG
+#elif defined(__ARM_NEON__) && (!BX_COMPILER_CLANG || BX_CLANG_HAS_EXTENSION(attribute_ext_vector_type) )
# include <arm_neon.h>
# undef BX_SIMD_NEON
# define BX_SIMD_NEON 1
@@ -197,6 +197,9 @@ BX_SIMD128_IMPLEMENT_TEST(xyzw);
Ty simd_cmpeq(Ty _a, Ty _b);
template<typename Ty>
+ Ty simd_cmpneq(Ty _a, Ty _b);
+
+ template<typename Ty>
Ty simd_cmplt(Ty _a, Ty _b);
template<typename Ty>
@@ -371,6 +374,9 @@ BX_SIMD128_IMPLEMENT_TEST(xyzw);
Ty simd_not_ni(Ty _a);
template<typename Ty>
+ Ty simd_cmpneq_ni(Ty _a, Ty _b);
+
+ template<typename Ty>
Ty simd_min_ni(Ty _a, Ty _b);
template<typename Ty>
diff --git a/3rdparty/bx/include/bx/sort.h b/3rdparty/bx/include/bx/sort.h
index 1506fb8307b..cee84bfdb63 100644
--- a/3rdparty/bx/include/bx/sort.h
+++ b/3rdparty/bx/include/bx/sort.h
@@ -1,18 +1,52 @@
/*
- * Copyright 2010-2018 Branimir Karadzic. All rights reserved.
- * License: https://github.com/bkaradzic/bx#license-bsd-2-clause
+ * Copyright 2010-2022 Branimir Karadzic. All rights reserved.
+ * License: https://github.com/bkaradzic/bx/blob/master/LICENSE
*/
#ifndef BX_SORT_H_HEADER_GUARD
#define BX_SORT_H_HEADER_GUARD
#include "bx.h"
+#include "math.h"
+#include "string.h"
namespace bx
{
+ /// The function compares the `_lhs` and `_rhs` values.
+ ///
+ /// @returns Returns value:
+ /// - less than zero if `_lhs` is less than `_rhs`
+ /// - zero if `_lhs` is equivalent to `_rhs`
+ /// - greater than zero if `_lhs` is greater than `_rhs`
///
typedef int32_t (*ComparisonFn)(const void* _lhs, const void* _rhs);
+ /// The function compares the `_lhs` and `_rhs` values.
+ ///
+ /// @returns Returns value:
+ /// - less than zero if `_lhs` is less than `_rhs`
+ /// - zero if `_lhs` is equivalent to `_rhs`
+ /// - greater than zero if `_lhs` is greater than `_rhs`
+ ///
+ template<typename Ty>
+ int32_t compareAscending(const void* _lhs, const void* _rhs);
+
+ /// The function compares the `_lhs` and `_rhs` values.
+ ///
+ /// @returns Returns value:
+ /// - less than zero if `_lhs` is greated than `_rhs`
+ /// - zero if `_lhs` is equivalent to `_rhs`
+ /// - greater than zero if `_lhs` is less than `_rhs`
+ ///
+ template<typename Ty>
+ int32_t compareDescending(const void* _lhs, const void* _rhs);
+
+ /// Performs sort (Quick Sort algorithm).
+ ///
+ /// @param _data Pointer to array data.
+ /// @param _num Number of elements.
+ /// @param _stride Element stride in bytes.
+ /// @param _fn Comparison function.
///
void quickSort(
void* _data
@@ -21,6 +55,245 @@ namespace bx
, const ComparisonFn _fn
);
+ /// Performs sort (Quick Sort algorithm).
+ ///
+ /// @param _data Pointer to array data.
+ /// @param _num Number of elements.
+ /// @param _stride Element stride in bytes.
+ /// @param _fn Comparison function.
+ ///
+ template<typename Ty>
+ void quickSort(void* _data, uint32_t _num, uint32_t _stride, const ComparisonFn _fn = compareAscending<Ty>);
+
+ /// Performs sort (Quick Sort algorithm).
+ ///
+ /// @param _data Pointer to array data.
+ /// @param _num Number of elements.
+ /// @param _fn Comparison function.
+ ///
+ template<typename Ty>
+ void quickSort(Ty* _data, uint32_t _num, const ComparisonFn _fn = compareAscending<Ty>);
+
+ /// Performs reordering of duplicate elements in the array in the way that unique elements
+ /// are sorted to the front of array, and duplicates are after the return value index.
+ ///
+ /// @param _data Pointer to sorted array data.
+ /// @param _num Number of elements.
+ /// @param _stride Element stride in bytes.
+ /// @param _fn Comparison function.
+ ///
+ /// @remarks Array must be sorted!
+ ///
+ /// @returns Returns the count of unique elements.
+ ///
+ uint32_t unique(void* _data, uint32_t _num, uint32_t _stride, const ComparisonFn _fn);
+
+ /// Performs reordering of duplicate elements in the array in the way that unique elements
+ /// are sorted to the front of array, and duplicates are after the return value index.
+ ///
+ /// @param _data Pointer to sorted array data.
+ /// @param _num Number of elements.
+ /// @param _stride Element stride in bytes.
+ /// @param _fn Comparison function.
+ ///
+ /// @remarks Array must be sorted!
+ ///
+ /// @returns Returns the count of unique elements.
+ ///
+ template<typename Ty>
+ uint32_t unique(void* _data, uint32_t _num, uint32_t _stride, const ComparisonFn _fn = compareAscending<Ty>);
+
+ /// Performs reordering of duplicate elements in the array in the way that unique elements
+ /// are sorted to the front of array, and duplicates are after the return value index.
+ ///
+ /// @param _data Pointer to sorted array data.
+ /// @param _num Number of elements.
+ /// @param _fn Comparison function.
+ ///
+ /// @remarks Array must be sorted!
+ ///
+ /// @returns Returns the count of unique elements.
+ ///
+ template<typename Ty>
+ uint32_t unique(Ty* _data, uint32_t _num, const ComparisonFn _fn = compareAscending<Ty>);
+
+ /// Performs check if array is sorted.
+ ///
+ /// @param _data Pointer to sorted array data.
+ /// @param _num Number of elements.
+ /// @param _stride Element stride in bytes.
+ /// @param _fn Comparison function.
+ ///
+ /// @returns Returns `true` if array is sorted, otherwise returns `false`.
+ ///
+ bool isSorted(
+ const void* _data
+ , uint32_t _num
+ , uint32_t _stride
+ , const ComparisonFn _fn
+ );
+
+ /// Performs check if array is sorted.
+ ///
+ /// @param _data Pointer to sorted array data.
+ /// @param _num Number of elements.
+ /// @param _stride Element stride in bytes.
+ /// @param _fn Comparison function.
+ ///
+ /// @returns Returns `true` if array is sorted, otherwise returns `false`.
+ ///
+ template<typename Ty>
+ bool isSorted(const void* _data, uint32_t _num, uint32_t _stride, const ComparisonFn _fn = compareAscending<Ty>);
+
+ /// Performs check if array is sorted.
+ ///
+ /// @param _data Pointer to sorted array data.
+ /// @param _num Number of elements.
+ /// @param _fn Comparison function.
+ ///
+ /// @returns Returns `true` if array is sorted, otherwise returns `false`.
+ ///
+ template<typename Ty>
+ bool isSorted(const Ty* _data, uint32_t _num, const ComparisonFn _fn = compareAscending<Ty>);
+
+ /// Returns an index to the first element greater or equal than the `_key` value.
+ ///
+ /// @param _key Pointer to the key to search for.
+ /// @param _data Pointer to sorted array data.
+ /// @param _num Number of elements.
+ /// @param _stride Element stride in bytes.
+ /// @param _fn Comparison function.
+ ///
+ /// @remarks Array must be sorted!
+ ///
+ /// @returns Returns an index to the first element greater or equal than the `_key` value.
+ ///
+ uint32_t lowerBound(const void* _key, const void* _data, uint32_t _num, uint32_t _stride, const ComparisonFn _fn);
+
+ /// Returns an index to the first element greater or equal than the `_key` value.
+ ///
+ /// @param _key Pointer to the key to search for.
+ /// @param _data Pointer to sorted array data.
+ /// @param _num Number of elements.
+ /// @param _fn Comparison function.
+ ///
+ /// @remarks Array must be sorted!
+ ///
+ /// @returns Returns an index to the first element greater or equal than the `_key` value.
+ ///
+ template<typename Ty>
+ uint32_t lowerBound(const Ty& _key, const Ty* _data, uint32_t _num, const ComparisonFn _fn = compareAscending<Ty>);
+
+ /// Returns an index to the first element greater or equal than the `_key` value.
+ ///
+ /// @param _key Pointer to the key to search for.
+ /// @param _data Pointer to sorted array data.
+ /// @param _num Number of elements.
+ /// @param _stride Element stride in bytes.
+ /// @param _fn Comparison function.
+ ///
+ /// @remarks Array must be sorted!
+ ///
+ /// @returns Returns an index to the first element greater or equal than the `_key` value.
+ ///
+ template<typename Ty>
+ uint32_t lowerBound(const Ty& _key, const void* _data, uint32_t _num, uint32_t _stride, const ComparisonFn _fn = compareAscending<Ty>);
+
+ /// Returns an index to the first element greater than the `_key` value.
+ ///
+ /// @param _key Pointer to the key to search for.
+ /// @param _data Pointer to sorted array data.
+ /// @param _num Number of elements.
+ /// @param _stride Element stride in bytes.
+ /// @param _fn Comparison function.
+ ///
+ /// @remarks Array must be sorted!
+ ///
+ /// @returns Returns an index to the first element greater than the `_key` value.
+ ///
+ uint32_t upperBound(const void* _key, const void* _data, uint32_t _num, uint32_t _stride, const ComparisonFn _fn);
+
+ /// Returns an index to the first element greater than the `_key` value.
+ ///
+ /// @param _key Pointer to the key to search for.
+ /// @param _data Pointer to sorted array data.
+ /// @param _num Number of elements.
+ /// @param _fn Comparison function.
+ ///
+ /// @remarks Array must be sorted!
+ ///
+ /// @returns Returns an index to the first element greater than the `_key` value.
+ ///
+ template<typename Ty>
+ uint32_t upperBound(const Ty& _key, const Ty* _data, uint32_t _num, const ComparisonFn _fn = compareAscending<Ty>);
+
+ /// Returns an index to the first element greater than the `_key` value.
+ ///
+ /// @param _key Pointer to the key to search for.
+ /// @param _data Pointer to sorted array data.
+ /// @param _num Number of elements.
+ /// @param _stride Element stride in bytes.
+ /// @param _fn Comparison function.
+ ///
+ /// @remarks Array must be sorted!
+ ///
+ /// @returns Returns an index to the first element greater than the `_key` value.
+ ///
+ template<typename Ty>
+ uint32_t upperBound(const Ty& _key, const void* _data, uint32_t _num, uint32_t _stride, const ComparisonFn _fn = compareAscending<Ty>);
+
+ /// Performs binary search of a sorted array.
+ ///
+ /// @param _key Pointer to the key to search for.
+ /// @param _data Pointer to sorted array data.
+ /// @param _num Number of elements.
+ /// @param _stride Element stride in bytes.
+ /// @param _fn Comparison function.
+ ///
+ /// @remarks Array must be sorted!
+ ///
+ /// @returns Returns positive value index of element if found, or negative number that is bitwise
+ /// complement (~) of the index of the next element that's larger than item.
+ ///
+ int32_t binarySearch(
+ const void* _key
+ , const void* _data
+ , uint32_t _num
+ , uint32_t _stride
+ , const ComparisonFn _fn
+ );
+
+ /// Performs binary search of a sorted array.
+ ///
+ /// @param _key Pointer to the key to search for.
+ /// @param _data Pointer to sorted array data.
+ /// @param _num Number of elements.
+ /// @param _fn Comparison function.
+ ///
+ /// @remarks Array must be sorted!
+ ///
+ /// @returns Returns positive value index of element if found, or negative number that is bitwise
+ /// complement (~) of the index of the next element that's larger than item.
+ ///
+ template<typename Ty>
+ int32_t binarySearch(const Ty& _key, const Ty* _data, uint32_t _num, const ComparisonFn _fn = compareAscending<Ty>);
+
+ /// Performs binary search of a sorted array.
+ ///
+ /// @param _key Pointer to the key to search for.
+ /// @param _data Pointer to sorted array data.
+ /// @param _num Number of elements.
+ /// @param _stride Element stride in bytes.
+ /// @param _fn Comparison function.
+ ///
+ /// @remarks Array must be sorted!
+ ///
+ /// @returns Returns positive value index of element if found, or negative number that is bitwise
+ /// complement (~) of the index of the next element that's larger than item.
+ ///
+ template<typename Ty>
+ int32_t binarySearch(const Ty& _key, const void* _data, uint32_t _num, uint32_t _stride = sizeof(Ty), const ComparisonFn _fn = compareAscending<Ty>);
+
///
void radixSort(
uint32_t* _keys
diff --git a/3rdparty/bx/include/bx/spscqueue.h b/3rdparty/bx/include/bx/spscqueue.h
index f34b65dfada..eaa8cd23b91 100644
--- a/3rdparty/bx/include/bx/spscqueue.h
+++ b/3rdparty/bx/include/bx/spscqueue.h
@@ -1,6 +1,6 @@
/*
- * Copyright 2010-2018 Branimir Karadzic. All rights reserved.
- * License: https://github.com/bkaradzic/bx#license-bsd-2-clause
+ * Copyright 2010-2022 Branimir Karadzic. All rights reserved.
+ * License: https://github.com/bkaradzic/bx/blob/master/LICENSE
*/
#ifndef BX_SPSCQUEUE_H_HEADER_GUARD
@@ -16,8 +16,8 @@ namespace bx
class SpScUnboundedQueue
{
BX_CLASS(SpScUnboundedQueue
+ , NO_DEFAULT_CTOR
, NO_COPY
- , NO_ASSIGNMENT
);
public:
@@ -57,8 +57,8 @@ namespace bx
class SpScUnboundedQueueT
{
BX_CLASS(SpScUnboundedQueueT
+ , NO_DEFAULT_CTOR
, NO_COPY
- , NO_ASSIGNMENT
);
public:
@@ -86,8 +86,8 @@ namespace bx
class SpScBlockingUnboundedQueue
{
BX_CLASS(SpScBlockingUnboundedQueue
+ , NO_DEFAULT_CTOR
, NO_COPY
- , NO_ASSIGNMENT
);
public:
@@ -116,8 +116,8 @@ namespace bx
class SpScBlockingUnboundedQueueT
{
BX_CLASS(SpScBlockingUnboundedQueueT
+ , NO_DEFAULT_CTOR
, NO_COPY
- , NO_ASSIGNMENT
);
public:
diff --git a/3rdparty/bx/include/bx/string.h b/3rdparty/bx/include/bx/string.h
index e0800562d71..d6629dc31eb 100644
--- a/3rdparty/bx/include/bx/string.h
+++ b/3rdparty/bx/include/bx/string.h
@@ -1,6 +1,6 @@
/*
- * Copyright 2010-2018 Branimir Karadzic. All rights reserved.
- * License: https://github.com/bkaradzic/bx#license-bsd-2-clause
+ * Copyright 2010-2022 Branimir Karadzic. All rights reserved.
+ * License: https://github.com/bkaradzic/bx/blob/master/LICENSE
*/
#ifndef BX_STRING_H_HEADER_GUARD
@@ -21,6 +21,7 @@ namespace bx
};
/// Non-zero-terminated string view.
+ ///
class StringView
{
public:
@@ -37,28 +38,15 @@ namespace bx
StringView& operator=(const StringView& _rhs);
///
- StringView(char* _ptr);
-
- ///
StringView(const char* _ptr);
///
- StringView(char* _ptr, int32_t _len);
-
- ///
StringView(const char* _ptr, int32_t _len);
///
StringView(const char* _ptr, const char* _term);
///
- template<typename Ty>
- explicit StringView(const Ty& _container);
-
- ///
- void set(char* _ptr);
-
- ///
void set(const char* _ptr);
///
@@ -71,27 +59,34 @@ namespace bx
void set(const StringView& _str, int32_t _start = 0, int32_t _len = INT32_MAX);
///
- template<typename Ty>
- void set(const Ty& _container);
-
- ///
void clear();
+ /// Returns pointer to non-terminated string.
+ ///
+ /// @attention Use of this pointer in standard C/C++ functions is not safe. You must use it
+ /// in conjunction with `getTerm()` or getLength()`.
///
const char* getPtr() const;
+ /// Returns pointer past last character in string view.
+ ///
+ /// @attention Dereferencing this pointer is not safe.
///
const char* getTerm() const;
- ///
+ /// Returns `true` if string is empty.
bool isEmpty() const;
- ///
+ /// Returns string length.
int32_t getLength() const;
+ /// Returns `true` if string is zero terminated.
+ bool is0Terminated() const;
+
protected:
const char* m_ptr;
int32_t m_len;
+ bool m_0terminated;
};
/// ASCII string
@@ -106,37 +101,47 @@ namespace bx
StringT(const StringT<AllocatorT>& _rhs);
///
- StringT<AllocatorT>& operator=(const StringT<AllocatorT>& _rhs);
-
- ///
StringT(const StringView& _rhs);
///
~StringT();
///
+ StringT<AllocatorT>& operator=(const StringT<AllocatorT>& _rhs);
+
+ ///
void set(const StringView& _str);
///
void append(const StringView& _str);
///
+ void append(const char* _ptr, const char* _term);
+
+ ///
void clear();
+
+ /// Returns zero-terminated C string pointer.
+ ///
+ const char* getCPtr() const;
+
+ protected:
+ int32_t m_capacity;
};
- /// Retruns true if character is part of space set.
+ /// Returns true if character is part of space set.
bool isSpace(char _ch);
/// Returns true if string view contains only space characters.
bool isSpace(const StringView& _str);
- /// Retruns true if character is uppercase.
+ /// Returns true if character is uppercase.
bool isUpper(char _ch);
/// Returns true if string view contains only uppercase characters.
bool isUpper(const StringView& _str);
- /// Retruns true if character is lowercase.
+ /// Returns true if character is lowercase.
bool isLower(char _ch);
/// Returns true if string view contains only lowercase characters.
@@ -145,19 +150,19 @@ namespace bx
/// Returns true if character is part of alphabet set.
bool isAlpha(char _ch);
- /// Retruns true if string view contains only alphabet characters.
+ /// Returns true if string view contains only alphabet characters.
bool isAlpha(const StringView& _str);
/// Returns true if character is part of numeric set.
bool isNumeric(char _ch);
- /// Retruns true if string view contains only numeric characters.
+ /// Returns true if string view contains only numeric characters.
bool isNumeric(const StringView& _str);
/// Returns true if character is part of alpha numeric set.
bool isAlphaNum(char _ch);
- /// Returns true if string view contains only alpha-numeric characters.
+ /// Returns true if string view contains only alphanumeric characters.
bool isAlphaNum(const StringView& _str);
/// Returns true if character is part of hexadecimal set.
@@ -172,7 +177,7 @@ namespace bx
/// Returns true if string vieww contains only printable characters.
bool isPrint(const StringView& _str);
- /// Retruns lower case character representing _ch.
+ /// Returns lower case character representing _ch.
char toLower(char _ch);
/// Lower case string in place assuming length passed is valid.
@@ -209,9 +214,15 @@ namespace bx
/// including zero terminator. Copy will be terminated with '\0'.
int32_t strCopy(char* _dst, int32_t _dstSize, const StringView& _str, int32_t _num = INT32_MAX);
- /// Concatinate string.
+ /// Concatenate string.
int32_t strCat(char* _dst, int32_t _dstSize, const StringView& _str, int32_t _num = INT32_MAX);
+ /// Test whether the string _str begins with prefix.
+ bool hasPrefix(const StringView& _str, const StringView& _prefix);
+
+ /// Test whether the string _str ends with suffix.
+ bool hasSuffix(const StringView& _str, const StringView& _suffix);
+
/// Find character in string. Limit search to _max characters.
StringView strFind(const StringView& _str, char _ch);
@@ -236,13 +247,25 @@ namespace bx
/// Returns string view with characters _chars trimmed from right.
StringView strRTrim(const StringView& _str, const StringView& _chars);
+ /// Returns string view with whitespace characters trimmed from right.
+ StringView strRTrimSpace(const StringView& _str);
+
/// Returns string view with characters _chars trimmed from left and right.
StringView strTrim(const StringView& _str, const StringView& _chars);
+ /// Returns string view with whitespace characters trimmed from left and right.
+ StringView strTrimSpace(const StringView& _str);
+
+ /// Returns string view with prefix trimmed.
+ StringView strTrimPrefix(const StringView& _str, const StringView& _prefix);
+
+ /// Returns string view with suffix trimmed.
+ StringView strTrimSuffix(const StringView& _str, const StringView& _suffix);
+
/// Find new line. Returns pointer after new line terminator.
StringView strFindNl(const StringView& _str);
- /// Find end of line. Retuns pointer to new line terminator.
+ /// Find end of line. Returns pointer to new line terminator.
StringView strFindEol(const StringView& _str);
/// Returns StringView of word or empty.
@@ -261,7 +284,7 @@ namespace bx
StringView findIdentifierMatch(const StringView& _str, const StringView& _word);
/// Finds any identifier from NULL terminated array of identifiers.
- StringView findIdentifierMatch(const StringView& _str, const char** _words);
+ StringView findIdentifierMatch(const StringView& _str, const char** _words, int32_t _num = INT32_MAX);
/// Cross platform implementation of vsnprintf that returns number of
/// characters which would have been written to the final string if
@@ -273,6 +296,12 @@ namespace bx
/// enough space had been available.
int32_t snprintf(char* _out, int32_t _max, const char* _format, ...);
+ ///
+ int32_t vprintf(const char* _format, va_list _argList);
+
+ ///
+ int32_t printf(const char* _format, ...);
+
/// Templatized snprintf.
template <typename Ty>
void stringPrintfVargs(Ty& _out, const char* _format, va_list _argList);
@@ -281,10 +310,6 @@ namespace bx
template <typename Ty>
void stringPrintf(Ty& _out, const char* _format, ...);
- /// Replace all instances of substring.
- template <typename Ty>
- Ty replaceAll(const Ty& _str, const char* _from, const char* _to);
-
/// Convert size in bytes to human readable string kibi units.
int32_t prettify(char* _out, int32_t _count, uint64_t _value, Units::Enum _units = Units::Kibi);
@@ -321,6 +346,31 @@ namespace bx
/// Converts string to 32-bit unsigned integer value.
bool fromString(uint32_t* _out, const StringView& _str);
+ ///
+ class LineReader
+ {
+ public:
+ ///
+ LineReader(const StringView& _str);
+
+ ///
+ void reset();
+
+ ///
+ StringView next();
+
+ ///
+ bool isDone() const;
+
+ ///
+ uint32_t getLine() const;
+
+ private:
+ const StringView m_str;
+ StringView m_curr;
+ uint32_t m_line;
+ };
+
} // namespace bx
#include "inline/string.inl"
diff --git a/3rdparty/bx/include/bx/thread.h b/3rdparty/bx/include/bx/thread.h
index 087bd3d4a57..25a18070b24 100644
--- a/3rdparty/bx/include/bx/thread.h
+++ b/3rdparty/bx/include/bx/thread.h
@@ -1,6 +1,6 @@
/*
- * Copyright 2010-2018 Branimir Karadzic. All rights reserved.
- * License: https://github.com/bkaradzic/bx#license-bsd-2-clause
+ * Copyright 2010-2022 Branimir Karadzic. All rights reserved.
+ * License: https://github.com/bkaradzic/bx/blob/master/LICENSE
*/
#ifndef BX_THREAD_H_HEADER_GUARD
@@ -9,6 +9,8 @@
#include "allocator.h"
#include "mpscqueue.h"
+#if BX_CONFIG_SUPPORTS_THREADING
+
namespace bx
{
///
@@ -19,7 +21,6 @@ namespace bx
{
BX_CLASS(Thread
, NO_COPY
- , NO_ASSIGNMENT
);
public:
@@ -29,8 +30,16 @@ namespace bx
///
virtual ~Thread();
+ /// Create and initialize thread.
+ ///
+ /// @param[in] _fn Thread function.
+ /// @param[in] _userData User data passed to thread function.
+ /// @param[in] _stackSize Stack size, if zero is passed it will use OS default thread stack
+ /// size.
+ /// @param[in] _name Thread name used by debugger.
+ /// @returns True if thread is created, otherwise returns false.
///
- void init(ThreadFn _fn, void* _userData = NULL, uint32_t _stackSize = 0, const char* _name = NULL);
+ bool init(ThreadFn _fn, void* _userData = NULL, uint32_t _stackSize = 0, const char* _name = NULL);
///
void shutdown();
@@ -87,4 +96,6 @@ namespace bx
} // namespace bx
+#endif
+
#endif // BX_THREAD_H_HEADER_GUARD
diff --git a/3rdparty/bx/include/bx/timer.h b/3rdparty/bx/include/bx/timer.h
index b0b0b403a8b..c860777c510 100644
--- a/3rdparty/bx/include/bx/timer.h
+++ b/3rdparty/bx/include/bx/timer.h
@@ -1,6 +1,6 @@
/*
- * Copyright 2010-2018 Branimir Karadzic. All rights reserved.
- * License: https://github.com/bkaradzic/bx#license-bsd-2-clause
+ * Copyright 2010-2022 Branimir Karadzic. All rights reserved.
+ * License: https://github.com/bkaradzic/bx/blob/master/LICENSE
*/
#ifndef BX_TIMER_H_HEADER_GUARD
diff --git a/3rdparty/bx/include/bx/typetraits.h b/3rdparty/bx/include/bx/typetraits.h
new file mode 100644
index 00000000000..9c301f617ea
--- /dev/null
+++ b/3rdparty/bx/include/bx/typetraits.h
@@ -0,0 +1,285 @@
+/*
+ * Copyright 2010-2022 Branimir Karadzic. All rights reserved.
+ * License: https://github.com/bkaradzic/bx/blob/master/LICENSE
+ */
+
+#ifndef BX_TYPETRAITS_H_HEADER_GUARD
+#define BX_TYPETRAITS_H_HEADER_GUARD
+
+namespace bx
+{
+ /// Returns true if type `Ty` is array type with known bound, otherwise returns false.
+ template<typename Ty>
+ constexpr bool isBoundedArray();
+
+ /// Returns true if type `Ty` is array type with unknown bound, otherwise returns false.
+ template<typename Ty>
+ constexpr bool isUnboundedArray();
+
+ /// Returns true if type `Ty` is array type (bounded, or unbounded array), otherwise returns false.
+ template<typename Ty>
+ constexpr bool isArray();
+
+ /// Returns true if type `Ty` is enumeration type, otherwise returns false.
+ template<typename Ty>
+ constexpr bool isEnum();
+
+ /// Returns true if type `Ty` is union type, otherwise returns false.
+ template<typename Ty>
+ constexpr bool isUnion();
+
+ /// Returns true if type `Ty` is non-union class type, otherwise returns false.
+ template<typename Ty>
+ constexpr bool isClass();
+
+ /// Returns true if type `Ty` is abstract class type, otherwise returns false.
+ template<typename Ty>
+ constexpr bool isAbstract();
+
+ /// Returns true if type `Ty` is aggregate class type, otherwise returns false.
+ template<typename Ty>
+ constexpr bool isAggregate();
+
+ /// Returns true if type `DerivedT` is derived from `BaseT` type, or if both are the same
+ /// non-union type, otherwise returns false.
+ template<typename BaseT, typename DerivedT>
+ constexpr bool isBaseOf();
+
+ /// Returns true if type `Ty` is polymorphic class (if it has virtual function table) type,
+ /// otherwise returns false.
+ template<typename Ty>
+ constexpr bool isPolymorphic();
+
+ /// Returns true if type `Ty` has virtual destructor, otherwise returns false.
+ template<typename Ty>
+ constexpr bool isDestructorVirtual();
+
+ /// Returns true if type `Ty` is class type with final specifier, otherwise returns false.
+ template<typename Ty>
+ constexpr bool isFinal();
+
+ /// Returns true if type `Ty` is non-union class type with no non-static
+ /// members (a.k.a. sizeof(Ty) is zero), otherwise returns false.
+ template<typename Ty>
+ constexpr bool isEmpty();
+
+ /// Returns true if type `Ty` is standard-layout type, otherwise returns false.
+ template<typename Ty>
+ constexpr bool isStandardLayout();
+
+ /// Returns true if type `Ty` is trivial type, otherwise returns false.
+ template<typename Ty>
+ constexpr bool isTrivial();
+
+ /// Returns true if type `Ty` is POD (standard-layout, and trivial type), otherwise returns false.
+ template<typename Ty>
+ constexpr bool isPod();
+
+ /// Returns true if type `FromT` can be assigned to type `Ty`, otherwise returns false.
+ template<typename Ty, typename FromT>
+ constexpr bool isAssignable();
+
+ /// Returns true if type `Ty` has copy assignment operator, otherwise returns false.
+ template<typename Ty, typename Uy>
+ constexpr bool isCopyAssignable();
+
+ /// Returns true if type `Ty` has move assignment operator, otherwise returns false.
+ template<typename Ty, typename Uy>
+ constexpr bool isMoveAssignable();
+
+ /// Returns true if type `FromT` can be trivially assigned to type `Ty`, otherwise returns false.
+ template<typename Ty, typename FromT>
+ constexpr bool isTriviallyAssignable();
+
+ /// Returns true if type `Ty` is trivially copy-assignable type, otherwise returns false.
+ template<typename Ty>
+ constexpr bool isTriviallyCopyAssignable();
+
+ /// Returns true if type `Ty` is trivially move-assignable type, otherwise returns false.
+ template<typename Ty>
+ constexpr bool isTriviallyMoveAssignable();
+
+ /// Returns true if type `Ty` is constructible when the specified argument types are used,
+ /// otherwise returns false.
+ template<typename Ty, typename... ArgsT>
+ constexpr bool isConstructible();
+
+ /// Returns true if type `Ty` has copy constructor, otherwise returns false.
+ template<typename Ty>
+ constexpr bool isCopyConstructible();
+
+ /// Returns true if type `Ty` has move constructor, otherwise returns false.
+ template<typename Ty>
+ constexpr bool isMoveConstructible();
+
+ /// Returns true if type `Ty` is trivially constructible when the specified argument types are used,
+ /// otherwise returns false.
+ template<typename T, typename... ArgsT>
+ constexpr bool isTriviallyConstructible();
+
+ /// Returns true if type `Ty` has trivial copy constructor, otherwise returns false.
+ template<typename Ty>
+ constexpr bool isTriviallyCopyConstructible();
+
+ /// Returns true if type `Ty` has trivial move constructor, otherwise returns false.
+ template<typename Ty>
+ constexpr bool isTriviallyMoveConstructible();
+
+ /// Returns true if type `Ty` is trivially copyable / POD type, otherwise returns false.
+ template<typename Ty>
+ constexpr bool isTriviallyCopyable();
+
+ /// Returns true if type `Ty` has trivial destructor, otherwise returns false.
+ template<typename Ty>
+ constexpr bool isTriviallyDestructible();
+
+ /// Returns true if type `Ty` is const-qualified type, otherwise returns false.
+ template<typename Ty>
+ constexpr bool isConst();
+
+ /// Returns true if type `Ty` is volatile-qualified type, otherwise returns false.
+ template<typename Ty>
+ constexpr bool isVolatile();
+
+ /// Returns true if type `Ty` is an reference type, otherwise returns false.
+ template<typename Ty>
+ constexpr bool isReference();
+
+ /// Returns true if type `Ty` is an Lvalue reference type, otherwise returns false.
+ template<typename Ty>
+ constexpr bool isLvalueReference();
+
+ /// Returns true if type `Ty` is an Rvalue reference type, otherwise returns false.
+ template<typename Ty>
+ constexpr bool isRvalueReference();
+
+ /// Returns true if type `Ty` is an pointer type, otherwise returns false.
+ template<typename Ty>
+ constexpr bool isPointer();
+
+ /// Returns true if type `Ty` is signed integer or floating-point type, otherwise returns false.
+ template<typename Ty>
+ constexpr bool isSigned();
+
+ /// Returns true if type `Ty` is unsigned integer type, otherwise returns false.
+ template<typename Ty>
+ constexpr bool isUnsigned();
+
+ /// Returns true if type `Ty` is integer type, otherwise returns false.
+ template<typename Ty>
+ constexpr bool isInteger();
+
+ /// Returns true if type `Ty` is floating-point type, otherwise returns false.
+ template<typename Ty>
+ constexpr bool isFloatingPoint();
+
+ /// Returns true if type `Ty` is arithmetic type, otherwise returns false.
+ template<typename Ty>
+ constexpr bool isArithmetic();
+
+ /// Returns true if type `Ty` and type `Uy` are the same type, otherwise returns false.
+ template<typename Ty, typename Uy>
+ constexpr bool isSame();
+
+} // namespace bx
+
+#include "inline/typetraits.inl"
+
+namespace bx
+{
+ /// Compile-time constant of specified type `Ty` with specified value `ValueT`.
+ template<typename Ty, Ty ValueT>
+ struct IntegralConstantT;
+
+ /// Alias of IntegralConstantT<bool, bool ValueT>.
+ template<bool BoolT>
+ using BoolConstantT = IntegralConstantT<bool, BoolT>;
+
+ /// Alias of BoolConstantT<bool, false>.
+ using FalseConstant = BoolConstantT<false>;
+
+ /// Alias of BoolConstantT<bool, true>.
+ using TrueConstant = BoolConstantT<true>;
+
+ /// Provides the member `Type` that names `Ty`.
+ template<typename Ty>
+ using TypeIdentityType = typename TypeIdentityT<Ty>::Type;
+
+ /// Conditionally selects `Ty` if `BoolT` is true, otherwise selects `Uy` type.
+ template<bool BoolT, typename Ty, typename Uy>
+ using ConditionalType = typename ConditionalT<BoolT, Ty, Uy>::Type;
+
+ /// If `BoolT` condition is true it provides `Ty` as `Type`, otherwise `Type` is undefined.
+ template<bool BoolT, typename Ty>
+ using EnableIfType = typename EnableIfT<BoolT, Ty>::Type;
+
+ /// If `Ty` is an object type or a function type that has no cv- or ref- qualifier, provides
+ /// a member `Type` which is `Ty&`. If `Ty` is an Rvalue reference to some type `Uy`, then
+ /// type is `Uy&`, otherwise type is `Ty`.
+ template<typename Ty>
+ using AddLvalueReferenceType = typename AddLvalueReferenceT<Ty>::Type;
+
+ /// If `Ty` is an object type or a function type that has no cv- or ref- qualifier, provides
+ /// a member `Type` which is `Ty&&`, otherwise type is `Ty`.
+ template<typename Ty>
+ using AddRvalueReferenceType = typename AddRvalueReferenceT<Ty>::Type;
+
+ /// If the type `Ty` is a reference type, provides the member typedef `Type`
+ /// which is the type referred to by `Ty`, otherwise type is `Ty`.
+ template<typename Ty>
+ using RemoveReferenceType = typename RemoveReferenceT<Ty>::Type;
+
+ /// If the type `Ty` is a reference type, provides the member typedef `Type`
+ /// which is a pointer to the referred type.
+ template<typename Ty>
+ using AddPointerType = typename AddPointerT<Ty>::Type;
+
+ /// If the type `Ty` is a pointer type, provides the member typedef `Type`
+ /// which is the type pointed to by `Ty`, otherwise type is `Ty`.
+ template<typename Ty>
+ using RemovePointerType = typename RemovePointerT<Ty>::Type;
+
+ /// Adds both `const`, and `volatile` to type `Ty`.
+ template<typename Ty>
+ using AddCvType = typename AddCvT<Ty>::Type;
+
+ /// Removes the topmost `const`, or the topmost `volatile`, or both, from type `Ty` if present.
+ template<typename Ty>
+ using RemoveCvType = typename RemoveCvT<Ty>::Type;
+
+ /// Adds `const` to type `Ty`.
+ template<typename Ty>
+ using AddConstType = typename AddConstT<Ty>::Type;
+
+ /// Removes the topmost `const` from type `Ty` if present.
+ template<typename Ty>
+ using RemoveConstType = typename RemoveConstT<Ty>::Type;
+
+ /// Adds `volatile` to type `Ty`.
+ template<typename Ty>
+ using AddVolatileType = typename AddVolatileT<Ty>::Type;
+
+ /// Removes the topmost `volatile` from type `Ty` if present.
+ template<typename Ty>
+ using RemoveVolatileType = typename RemoveVolatileT<Ty>::Type;
+
+ /// Removes reference from type `Ty` if present.
+ template<typename Ty>
+ constexpr RemoveReferenceType<Ty>&& move(Ty&& _a);
+
+ /// Forwards Lvalues as either Lvalues or as Rvalues.
+ template<typename Ty>
+ constexpr Ty&& forward(RemoveReferenceType<Ty>& _type);
+
+ /// Forwards Rvalues as Rvalues and prohibits forwarding of Rvalues as Lvalues.
+ template<typename Ty>
+ constexpr Ty&& forward(RemoveReferenceT<Ty>&& _type);
+
+ /// Converts any type `Ty` to a reference type, making it possible to use member functions
+ /// in decltype expressions without the need to go through constructors.
+ template<typename Ty>
+ AddRvalueReferenceType<Ty> declVal();
+
+} // namespace bx
+
+#endif // BX_TYPETRAITS_H_HEADER_GUARD
diff --git a/3rdparty/bx/include/bx/uint32_t.h b/3rdparty/bx/include/bx/uint32_t.h
index 3d0afcb7124..cff793e0d2c 100644
--- a/3rdparty/bx/include/bx/uint32_t.h
+++ b/3rdparty/bx/include/bx/uint32_t.h
@@ -1,6 +1,6 @@
/*
- * Copyright 2010-2018 Branimir Karadzic. All rights reserved.
- * License: https://github.com/bkaradzic/bx#license-bsd-2-clause
+ * Copyright 2010-2022 Branimir Karadzic. All rights reserved.
+ * License: https://github.com/bkaradzic/bx/blob/master/LICENSE
*/
#ifndef BX_UINT32_T_H_HEADER_GUARD
@@ -149,14 +149,18 @@ namespace bx
/// Count number of bits set.
///
- BX_CONSTEXPR_FUNC uint32_t uint32_cntbits(uint32_t _val);
+ template<typename Ty>
+ BX_CONSTEXPR_FUNC uint32_t uint32_cntbits(Ty _val);
/// Count number of leading zeros.
///
- BX_CONSTEXPR_FUNC uint32_t uint32_cntlz(uint32_t _val);
+ template<typename Ty>
+ BX_CONSTEXPR_FUNC uint32_t uint32_cntlz(Ty _val);
+ /// Count number of trailing zeros.
///
- BX_CONSTEXPR_FUNC uint32_t uint32_cnttz(uint32_t _val);
+ template<typename Ty>
+ BX_CONSTEXPR_FUNC uint32_t uint32_cnttz(Ty _val);
///
BX_CONSTEXPR_FUNC uint32_t uint32_part1by1(uint32_t _a);
@@ -170,16 +174,41 @@ namespace bx
///
BX_CONSTEXPR_FUNC uint32_t uint32_nextpow2(uint32_t _a);
- /// Count number of bits set.
///
- BX_CONSTEXPR_FUNC uint32_t uint64_cntbits(uint64_t _val);
+ BX_CONSTEXPR_FUNC uint64_t uint64_li(uint64_t _a);
+
+ ///
+ BX_CONSTEXPR_FUNC uint64_t uint64_dec(uint64_t _a);
+
+ ///
+ BX_CONSTEXPR_FUNC uint64_t uint64_inc(uint64_t _a);
+
+ ///
+ BX_CONSTEXPR_FUNC uint64_t uint64_not(uint64_t _a);
+
+ ///
+ BX_CONSTEXPR_FUNC uint64_t uint64_neg(uint64_t _a);
- /// Count number of leading zeros.
///
- BX_CONSTEXPR_FUNC uint32_t uint64_cntlz(uint64_t _val);
+ BX_CONSTEXPR_FUNC uint64_t uint64_ext(uint64_t _a);
///
- BX_CONSTEXPR_FUNC uint32_t uint64_cnttz(uint64_t _val);
+ BX_CONSTEXPR_FUNC uint64_t uint64_and(uint64_t _a, uint64_t _b);
+
+ ///
+ BX_CONSTEXPR_FUNC uint64_t uint64_andc(uint64_t _a, uint64_t _b);
+
+ ///
+ BX_CONSTEXPR_FUNC uint64_t uint64_xor(uint64_t _a, uint64_t _b);
+
+ ///
+ BX_CONSTEXPR_FUNC uint64_t uint64_xorl(uint64_t _a, uint64_t _b);
+
+ ///
+ BX_CONSTEXPR_FUNC uint64_t uint64_or(uint64_t _a, uint64_t _b);
+
+ ///
+ BX_CONSTEXPR_FUNC uint64_t uint64_orc(uint64_t _a, uint64_t _b);
///
BX_CONSTEXPR_FUNC uint64_t uint64_sll(uint64_t _a, int32_t _sa);
@@ -217,13 +246,46 @@ namespace bx
///
BX_CONSTEXPR_FUNC uint32_t strideAlign(uint32_t _offset, uint32_t _stride);
- /// Align to arbitrary stride and 16-bytes.
+ /// Align to arbitrary stride and Min bytes.
+ ///
+ template<uint32_t Min>
+ BX_CONSTEXPR_FUNC uint32_t strideAlign(uint32_t _offset, uint32_t _stride);
+
+ ///
+ template<typename Ty>
+ BX_CONSTEXPR_FUNC bool isAligned(Ty _a, int32_t _align);
+
+ ///
+ template<typename Ty>
+ BX_CONSTEXPR_FUNC bool isAligned(Ty* _ptr, int32_t _align);
+
+ ///
+ template<typename Ty>
+ BX_CONSTEXPR_FUNC bool isAligned(const Ty* _ptr, int32_t _align);
+
+ ///
+ template<typename Ty>
+ BX_CONSTEXPR_FUNC Ty alignDown(Ty _a, int32_t _align);
+
+ ///
+ template<typename Ty>
+ BX_CONSTEXPR_FUNC Ty* alignDown(Ty* _ptr, int32_t _align);
+
+ ///
+ template<typename Ty>
+ BX_CONSTEXPR_FUNC const Ty* alignDown(const Ty* _ptr, int32_t _align);
+
+ ///
+ template<typename Ty>
+ BX_CONSTEXPR_FUNC Ty alignUp(Ty _a, int32_t _align);
+
///
- BX_CONSTEXPR_FUNC uint32_t strideAlign16(uint32_t _offset, uint32_t _stride);
+ template<typename Ty>
+ BX_CONSTEXPR_FUNC Ty* alignUp(Ty* _ptr, int32_t _align);
- /// Align to arbitrary stride and 256-bytes.
///
- BX_CONSTEXPR_FUNC uint32_t strideAlign256(uint32_t _offset, uint32_t _stride);
+ template<typename Ty>
+ BX_CONSTEXPR_FUNC const Ty* alignUp(const Ty* _ptr, int32_t _align);
/// Convert float to half-float.
///
diff --git a/3rdparty/bx/include/bx/url.h b/3rdparty/bx/include/bx/url.h
index 9e00d8348b4..b2b45405fe3 100644
--- a/3rdparty/bx/include/bx/url.h
+++ b/3rdparty/bx/include/bx/url.h
@@ -1,6 +1,6 @@
/*
- * Copyright 2010-2018 Branimir Karadzic. All rights reserved.
- * License: https://github.com/bkaradzic/bx#license-bsd-2-clause
+ * Copyright 2010-2022 Branimir Karadzic. All rights reserved.
+ * License: https://github.com/bkaradzic/bx/blob/master/LICENSE
*/
#ifndef BX_URL_H_HEADER_GUARD
diff --git a/3rdparty/bx/include/compat/linux/sal.h b/3rdparty/bx/include/compat/linux/sal.h
new file mode 100644
index 00000000000..23c9fc084c0
--- /dev/null
+++ b/3rdparty/bx/include/compat/linux/sal.h
@@ -0,0 +1 @@
+#include "../mingw/salieri.h"
diff --git a/3rdparty/bx/include/compat/mingw/salieri.h b/3rdparty/bx/include/compat/mingw/salieri.h
index 06d72075c3f..5942b397f32 100644
--- a/3rdparty/bx/include/compat/mingw/salieri.h
+++ b/3rdparty/bx/include/compat/mingw/salieri.h
@@ -1598,6 +1598,22 @@
# define SALIERI_DEFINED_String_length
#endif
+#if defined(_In_count_) && defined(SALIERI_DEFINED_In_count_)
+# undef _In_count_
+#endif
+#if !defined(_In_count_)
+# define _In_count_(param)
+# define SALIERI_DEFINED_In_count_
+#endif
+
+#if defined(_In_opt_count_) && defined(SALIERI_DEFINED_In_opt_count_)
+# undef _In_opt_count_
+#endif
+#if !defined(_In_opt_count_)
+# define _In_opt_count_(param)
+# define SALIERI_DEFINED_In_opt_count_
+#endif
+
#if defined(SALIERI_VERSION)
# undef SALIERI_VERSION
#endif
diff --git a/3rdparty/bx/include/compat/msvc/dirent.h b/3rdparty/bx/include/compat/msvc/dirent.h
index a08d0fa4df3..3177d335f75 100644
--- a/3rdparty/bx/include/compat/msvc/dirent.h
+++ b/3rdparty/bx/include/compat/msvc/dirent.h
@@ -1,28 +1,10 @@
/*
- * dirent.h - dirent API for Microsoft Visual Studio
+ * Dirent interface for Microsoft Visual Studio
*
- * Copyright (C) 2006-2012 Toni Ronkko
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * ``Software''), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice shall be included
- * in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS
- * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
- * IN NO EVENT SHALL TONI RONKKO BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * $Id: dirent.h,v 1.20 2014/03/19 17:52:23 tronkko Exp $
+ * Copyright (C) 1998-2019 Toni Ronkko
+ * This file is part of dirent. Dirent may be freely distributed
+ * under the MIT license. For all details and documentation, see
+ * https://github.com/tronkko/dirent
*/
#ifndef DIRENT_H
#define DIRENT_H
@@ -36,21 +18,16 @@
#endif // _MSC_VER
/*
- * Define architecture flags so we don't need to include windows.h.
- * Avoiding windows.h makes it simpler to use windows sockets in conjunction
- * with dirent.h.
+ * Include windows.h without Windows Sockets 1.1 to prevent conflicts with
+ * Windows Sockets 2.0.
*/
-#if !defined(_68K_) && !defined(_MPPC_) && !defined(_X86_) && !defined(_IA64_) && !defined(_AMD64_) && defined(_M_IX86)
-# define _X86_
-#endif
-#if !defined(_68K_) && !defined(_MPPC_) && !defined(_X86_) && !defined(_IA64_) && !defined(_AMD64_) && defined(_M_AMD64)
-#define _AMD64_
+#ifndef WIN32_LEAN_AND_MEAN
+# define WIN32_LEAN_AND_MEAN
#endif
+#include <windows.h>
#include <stdio.h>
#include <stdarg.h>
-#include <windef.h>
-#include <winbase.h>
#include <wchar.h>
#include <string.h>
#include <stdlib.h>
@@ -70,54 +47,109 @@
# define FILE_ATTRIBUTE_DEVICE 0x40
#endif
-/* File type and permission flags for stat() */
+/* File type and permission flags for stat(), general mask */
#if !defined(S_IFMT)
-# define S_IFMT _S_IFMT /* File type mask */
+# define S_IFMT _S_IFMT
#endif
+
+/* Directory bit */
#if !defined(S_IFDIR)
-# define S_IFDIR _S_IFDIR /* Directory */
+# define S_IFDIR _S_IFDIR
#endif
+
+/* Character device bit */
#if !defined(S_IFCHR)
-# define S_IFCHR _S_IFCHR /* Character device */
+# define S_IFCHR _S_IFCHR
#endif
+
+/* Pipe bit */
#if !defined(S_IFFIFO)
-# define S_IFFIFO _S_IFFIFO /* Pipe */
+# define S_IFFIFO _S_IFFIFO
#endif
+
+/* Regular file bit */
#if !defined(S_IFREG)
-# define S_IFREG _S_IFREG /* Regular file */
+# define S_IFREG _S_IFREG
#endif
+
+/* Read permission */
#if !defined(S_IREAD)
-# define S_IREAD _S_IREAD /* Read permission */
+# define S_IREAD _S_IREAD
#endif
+
+/* Write permission */
#if !defined(S_IWRITE)
-# define S_IWRITE _S_IWRITE /* Write permission */
+# define S_IWRITE _S_IWRITE
#endif
+
+/* Execute permission */
#if !defined(S_IEXEC)
-# define S_IEXEC _S_IEXEC /* Execute permission */
+# define S_IEXEC _S_IEXEC
#endif
+
+/* Pipe */
#if !defined(S_IFIFO)
-# define S_IFIFO _S_IFIFO /* Pipe */
+# define S_IFIFO _S_IFIFO
#endif
+
+/* Block device */
#if !defined(S_IFBLK)
-# define S_IFBLK 0 /* Block device */
+# define S_IFBLK 0
#endif
+
+/* Link */
#if !defined(S_IFLNK)
-# define S_IFLNK 0 /* Link */
+# define S_IFLNK 0
#endif
+
+/* Socket */
#if !defined(S_IFSOCK)
-# define S_IFSOCK 0 /* Socket */
+# define S_IFSOCK 0
+#endif
+
+/* Read user permission */
+#if !defined(S_IRUSR)
+# define S_IRUSR S_IREAD
+#endif
+
+/* Write user permission */
+#if !defined(S_IWUSR)
+# define S_IWUSR S_IWRITE
+#endif
+
+/* Execute user permission */
+#if !defined(S_IXUSR)
+# define S_IXUSR 0
+#endif
+
+/* Read group permission */
+#if !defined(S_IRGRP)
+# define S_IRGRP 0
+#endif
+
+/* Write group permission */
+#if !defined(S_IWGRP)
+# define S_IWGRP 0
#endif
-#if defined(_MSC_VER)
-# define S_IRUSR S_IREAD /* Read user */
-# define S_IWUSR S_IWRITE /* Write user */
-# define S_IXUSR 0 /* Execute user */
-# define S_IRGRP 0 /* Read group */
-# define S_IWGRP 0 /* Write group */
-# define S_IXGRP 0 /* Execute group */
-# define S_IROTH 0 /* Read others */
-# define S_IWOTH 0 /* Write others */
-# define S_IXOTH 0 /* Execute others */
+/* Execute group permission */
+#if !defined(S_IXGRP)
+# define S_IXGRP 0
+#endif
+
+/* Read others permission */
+#if !defined(S_IROTH)
+# define S_IROTH 0
+#endif
+
+/* Write others permission */
+#if !defined(S_IWOTH)
+# define S_IWOTH 0
+#endif
+
+/* Execute others permission */
+#if !defined(S_IXOTH)
+# define S_IXOTH 0
#endif
/* Maximum length of file name */
@@ -132,14 +164,14 @@
#endif
/* File type flags for d_type */
-#define DT_UNKNOWN 0
-#define DT_REG S_IFREG
-#define DT_DIR S_IFDIR
-#define DT_FIFO S_IFIFO
-#define DT_SOCK S_IFSOCK
-#define DT_CHR S_IFCHR
-#define DT_BLK S_IFBLK
-#define DT_LNK S_IFLNK
+#define DT_UNKNOWN 0
+#define DT_REG S_IFREG
+#define DT_DIR S_IFDIR
+#define DT_FIFO S_IFIFO
+#define DT_SOCK S_IFSOCK
+#define DT_CHR S_IFCHR
+#define DT_BLK S_IFBLK
+#define DT_LNK S_IFLNK
/* Macros for converting between st_mode and d_type */
#define IFTODT(mode) ((mode) & S_IFMT)
@@ -151,39 +183,33 @@
* only defined for compatibility. These macros should always return false
* on Windows.
*/
-#ifndef S_ISFIFO
+#if !defined(S_ISFIFO)
# define S_ISFIFO(mode) (((mode) & S_IFMT) == S_IFIFO)
#endif
-
-#ifndef S_ISDIR
-# define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR)
+#if !defined(S_ISDIR)
+# define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR)
#endif
-
-#ifndef S_ISREG
-# define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG)
+#if !defined(S_ISREG)
+# define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG)
#endif
-
-#ifndef S_ISLNK
-# define S_ISLNK(mode) (((mode) & S_IFMT) == S_IFLNK)
+#if !defined(S_ISLNK)
+# define S_ISLNK(mode) (((mode) & S_IFMT) == S_IFLNK)
#endif
-
-#ifndef S_ISSOCK
+#if !defined(S_ISSOCK)
# define S_ISSOCK(mode) (((mode) & S_IFMT) == S_IFSOCK)
#endif
-
-#ifndef S_ISCHR
-# define S_ISCHR(mode) (((mode) & S_IFMT) == S_IFCHR)
+#if !defined(S_ISCHR)
+# define S_ISCHR(mode) (((mode) & S_IFMT) == S_IFCHR)
#endif
-
-#ifndef S_ISBLK
-# define S_ISBLK(mode) (((mode) & S_IFMT) == S_IFBLK)
+#if !defined(S_ISBLK)
+# define S_ISBLK(mode) (((mode) & S_IFMT) == S_IFBLK)
#endif
-/* Return the exact length of d_namlen without zero terminator */
+/* Return the exact length of the file name without zero terminator */
#define _D_EXACT_NAMLEN(p) ((p)->d_namlen)
-/* Return number of bytes needed to store d_namlen */
-#define _D_ALLOC_NAMLEN(p) (PATH_MAX)
+/* Return the maximum size of a file name */
+#define _D_ALLOC_NAMLEN(p) ((PATH_MAX)+1)
#ifdef __cplusplus
@@ -193,45 +219,63 @@ extern "C" {
/* Wide-character version */
struct _wdirent {
- long d_ino; /* Always zero */
- unsigned short d_reclen; /* Structure size */
- size_t d_namlen; /* Length of name without \0 */
- int d_type; /* File type */
- wchar_t d_name[PATH_MAX]; /* File name */
+ /* Always zero */
+ long d_ino;
+
+ /* File position within stream */
+ long d_off;
+
+ /* Structure size */
+ unsigned short d_reclen;
+
+ /* Length of name without \0 */
+ size_t d_namlen;
+
+ /* File type */
+ int d_type;
+
+ /* File name */
+ wchar_t d_name[PATH_MAX+1];
};
typedef struct _wdirent _wdirent;
struct _WDIR {
- struct _wdirent ent; /* Current directory entry */
- WIN32_FIND_DATAW data; /* Private file data */
- int cached; /* True if data is valid */
- HANDLE handle; /* Win32 search handle */
- wchar_t *patt; /* Initial directory name */
+ /* Current directory entry */
+ struct _wdirent ent;
+
+ /* Private file data */
+ WIN32_FIND_DATAW data;
+
+ /* True if data is valid */
+ int cached;
+
+ /* Win32 search handle */
+ HANDLE handle;
+
+ /* Initial directory name */
+ wchar_t *patt;
};
typedef struct _WDIR _WDIR;
-static _WDIR *_wopendir (const wchar_t *dirname);
-static struct _wdirent *_wreaddir (_WDIR *dirp);
-static int _wclosedir (_WDIR *dirp);
-static void _wrewinddir (_WDIR* dirp);
+/* Multi-byte character version */
+struct dirent {
+ /* Always zero */
+ long d_ino;
+ /* File position within stream */
+ long d_off;
-/* For compatibility with Symbian */
-#define wdirent _wdirent
-#define WDIR _WDIR
-#define wopendir _wopendir
-#define wreaddir _wreaddir
-#define wclosedir _wclosedir
-#define wrewinddir _wrewinddir
+ /* Structure size */
+ unsigned short d_reclen;
+ /* Length of name without \0 */
+ size_t d_namlen;
-/* Multi-byte character versions */
-struct dirent {
- long d_ino; /* Always zero */
- unsigned short d_reclen; /* Structure size */
- size_t d_namlen; /* Length of name without \0 */
- int d_type; /* File type */
- char d_name[PATH_MAX]; /* File name */
+ /* File type */
+ int d_type;
+
+ /* File name */
+ char d_name[PATH_MAX+1];
};
typedef struct dirent dirent;
@@ -241,10 +285,41 @@ struct DIR {
};
typedef struct DIR DIR;
+
+/* Dirent functions */
static DIR *opendir (const char *dirname);
+static _WDIR *_wopendir (const wchar_t *dirname);
+
static struct dirent *readdir (DIR *dirp);
+static struct _wdirent *_wreaddir (_WDIR *dirp);
+
+static int readdir_r(
+ DIR *dirp, struct dirent *entry, struct dirent **result);
+static int _wreaddir_r(
+ _WDIR *dirp, struct _wdirent *entry, struct _wdirent **result);
+
static int closedir (DIR *dirp);
+static int _wclosedir (_WDIR *dirp);
+
static void rewinddir (DIR* dirp);
+static void _wrewinddir (_WDIR* dirp);
+
+static int scandir (const char *dirname, struct dirent ***namelist,
+ int (*filter)(const struct dirent*),
+ int (*compare)(const struct dirent**, const struct dirent**));
+
+static int alphasort (const struct dirent **a, const struct dirent **b);
+
+static int versionsort (const struct dirent **a, const struct dirent **b);
+
+
+/* For compatibility with Symbian */
+#define wdirent _wdirent
+#define WDIR _WDIR
+#define wopendir _wopendir
+#define wreaddir _wreaddir
+#define wclosedir _wclosedir
+#define wrewinddir _wrewinddir
/* Internal utility functions */
@@ -267,6 +342,7 @@ static int dirent_wcstombs_s(
static void dirent_set_errno (int error);
+
/*
* Open directory stream DIRNAME for read and return a pointer to the
* internal working area that is used to retrieve individual directory
@@ -277,7 +353,8 @@ _wopendir(
const wchar_t *dirname)
{
_WDIR *dirp = NULL;
- int error;
+ DWORD n;
+ wchar_t *p;
/* Must have directory name */
if (dirname == NULL || dirname[0] == '\0') {
@@ -287,96 +364,120 @@ _wopendir(
/* Allocate new _WDIR structure */
dirp = (_WDIR*) malloc (sizeof (struct _WDIR));
- if (dirp != NULL) {
- DWORD n;
-
- /* Reset _WDIR structure */
- dirp->handle = INVALID_HANDLE_VALUE;
- dirp->patt = NULL;
- dirp->cached = 0;
-
- /* Compute the length of full path plus zero terminator */
- n = GetFullPathNameW (dirname, 0, NULL, NULL);
-
- /* Allocate room for absolute directory name and search pattern */
- dirp->patt = (wchar_t*) malloc (sizeof (wchar_t) * n + 16);
- if (dirp->patt) {
-
- /*
- * Convert relative directory name to an absolute one. This
- * allows rewinddir() to function correctly even when current
- * working directory is changed between opendir() and rewinddir().
- */
- n = GetFullPathNameW (dirname, n, dirp->patt, NULL);
- if (n > 0) {
- wchar_t *p;
-
- /* Append search pattern \* to the directory name */
- p = dirp->patt + n;
- if (dirp->patt < p) {
- switch (p[-1]) {
- case '\\':
- case '/':
- case ':':
- /* Directory ends in path separator, e.g. c:\temp\ */
- /*NOP*/;
- break;
-
- default:
- /* Directory name doesn't end in path separator */
- *p++ = '\\';
- }
- }
- *p++ = '*';
- *p = '\0';
+ if (!dirp) {
+ return NULL;
+ }
- /* Open directory stream and retrieve the first entry */
- if (dirent_first (dirp)) {
- /* Directory stream opened successfully */
- error = 0;
- } else {
- /* Cannot retrieve first entry */
- error = 1;
- dirent_set_errno (ENOENT);
- }
+ /* Reset _WDIR structure */
+ dirp->handle = INVALID_HANDLE_VALUE;
+ dirp->patt = NULL;
+ dirp->cached = 0;
+
+ /*
+ * Compute the length of full path plus zero terminator
+ *
+ * Note that on WinRT there's no way to convert relative paths
+ * into absolute paths, so just assume it is an absolute path.
+ */
+#if defined(WINAPI_FAMILY) && defined(WINAPI_FAMILY_PHONE_APP) && (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP)
+ /* WinRT */
+ n = wcslen (dirname);
+#else
+ /* Regular Windows */
+ n = GetFullPathNameW (dirname, 0, NULL, NULL);
+#endif
- } else {
- /* Cannot retrieve full path name */
- dirent_set_errno (ENOENT);
- error = 1;
- }
+ /* Allocate room for absolute directory name and search pattern */
+ dirp->patt = (wchar_t*) malloc (sizeof (wchar_t) * n + 16);
+ if (dirp->patt == NULL) {
+ goto exit_closedir;
+ }
- } else {
- /* Cannot allocate memory for search pattern */
- error = 1;
- }
+ /*
+ * Convert relative directory name to an absolute one. This
+ * allows rewinddir() to function correctly even when current
+ * working directory is changed between opendir() and rewinddir().
+ *
+ * Note that on WinRT there's no way to convert relative paths
+ * into absolute paths, so just assume it is an absolute path.
+ */
+#if defined(WINAPI_FAMILY) && defined(WINAPI_FAMILY_PHONE_APP) && (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP)
+ /* WinRT */
+ wcsncpy_s (dirp->patt, n+1, dirname, n);
+#else
+ /* Regular Windows */
+ n = GetFullPathNameW (dirname, n, dirp->patt, NULL);
+ if (n <= 0) {
+ goto exit_closedir;
+ }
+#endif
- } else {
- /* Cannot allocate _WDIR structure */
- error = 1;
+ /* Append search pattern \* to the directory name */
+ p = dirp->patt + n;
+ switch (p[-1]) {
+ case '\\':
+ case '/':
+ case ':':
+ /* Directory ends in path separator, e.g. c:\temp\ */
+ /*NOP*/;
+ break;
+
+ default:
+ /* Directory name doesn't end in path separator */
+ *p++ = '\\';
}
+ *p++ = '*';
+ *p = '\0';
- /* Clean up in case of error */
- if (error && dirp) {
- _wclosedir (dirp);
- dirp = NULL;
+ /* Open directory stream and retrieve the first entry */
+ if (!dirent_first (dirp)) {
+ goto exit_closedir;
}
+ /* Success */
return dirp;
+
+ /* Failure */
+exit_closedir:
+ _wclosedir (dirp);
+ return NULL;
}
/*
- * Read next directory entry. The directory entry is returned in dirent
- * structure in the d_name field. Individual directory entries returned by
- * this function include regular files, sub-directories, pseudo-directories
- * "." and ".." as well as volume labels, hidden files and system files.
+ * Read next directory entry.
+ *
+ * Returns pointer to static directory entry which may be overwritten by
+ * subsequent calls to _wreaddir().
*/
static struct _wdirent*
_wreaddir(
_WDIR *dirp)
{
+ struct _wdirent *entry;
+
+ /*
+ * Read directory entry to buffer. We can safely ignore the return value
+ * as entry will be set to NULL in case of error.
+ */
+ (void) _wreaddir_r (dirp, &dirp->ent, &entry);
+
+ /* Return pointer to statically allocated directory entry */
+ return entry;
+}
+
+/*
+ * Read next directory entry.
+ *
+ * Returns zero on success. If end of directory stream is reached, then sets
+ * result to NULL and returns zero.
+ */
+static int
+_wreaddir_r(
+ _WDIR *dirp,
+ struct _wdirent *entry,
+ struct _wdirent **result)
+{
WIN32_FIND_DATAW *datap;
- struct _wdirent *entp;
/* Read next directory entry */
datap = dirent_next (dirp);
@@ -384,46 +485,47 @@ _wreaddir(
size_t n;
DWORD attr;
- /* Pointer to directory entry to return */
- entp = &dirp->ent;
-
/*
* Copy file name as wide-character string. If the file name is too
* long to fit in to the destination buffer, then truncate file name
* to PATH_MAX characters and zero-terminate the buffer.
*/
n = 0;
- while (n + 1 < PATH_MAX && datap->cFileName[n] != 0) {
- entp->d_name[n] = datap->cFileName[n];
+ while (n < PATH_MAX && datap->cFileName[n] != 0) {
+ entry->d_name[n] = datap->cFileName[n];
n++;
}
- dirp->ent.d_name[n] = 0;
+ entry->d_name[n] = 0;
/* Length of file name excluding zero terminator */
- entp->d_namlen = n;
+ entry->d_namlen = n;
/* File type */
attr = datap->dwFileAttributes;
if ((attr & FILE_ATTRIBUTE_DEVICE) != 0) {
- entp->d_type = DT_CHR;
+ entry->d_type = DT_CHR;
} else if ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0) {
- entp->d_type = DT_DIR;
+ entry->d_type = DT_DIR;
} else {
- entp->d_type = DT_REG;
+ entry->d_type = DT_REG;
}
/* Reset dummy fields */
- entp->d_ino = 0;
- entp->d_reclen = sizeof (struct _wdirent);
+ entry->d_ino = 0;
+ entry->d_off = 0;
+ entry->d_reclen = sizeof (struct _wdirent);
+
+ /* Set result address */
+ *result = entry;
} else {
- /* Last directory entry read */
- entp = NULL;
+ /* Return NULL to indicate end of directory */
+ *result = NULL;
}
- return entp;
+ return /*OK*/0;
}
/*
@@ -441,23 +543,21 @@ _wclosedir(
/* Release search handle */
if (dirp->handle != INVALID_HANDLE_VALUE) {
FindClose (dirp->handle);
- dirp->handle = INVALID_HANDLE_VALUE;
}
/* Release search pattern */
- if (dirp->patt) {
- free (dirp->patt);
- dirp->patt = NULL;
- }
+ free (dirp->patt);
/* Release directory structure */
free (dirp);
ok = /*success*/0;
} else {
+
/* Invalid directory stream */
dirent_set_errno (EBADF);
ok = /*failure*/-1;
+
}
return ok;
}
@@ -487,9 +587,12 @@ dirent_first(
_WDIR *dirp)
{
WIN32_FIND_DATAW *datap;
+ DWORD error;
/* Open directory and retrieve the first entry */
- dirp->handle = FindFirstFileW (dirp->patt, &dirp->data);
+ dirp->handle = FindFirstFileExW(
+ dirp->patt, FindExInfoStandard, &dirp->data,
+ FindExSearchNameMatch, NULL, 0);
if (dirp->handle != INVALID_HANDLE_VALUE) {
/* a directory entry is now waiting in memory */
@@ -498,15 +601,38 @@ dirent_first(
} else {
- /* Failed to re-open directory: no directory entry in memory */
+ /* Failed to open directory: no directory entry in memory */
dirp->cached = 0;
datap = NULL;
+ /* Set error code */
+ error = GetLastError ();
+ switch (error) {
+ case ERROR_ACCESS_DENIED:
+ /* No read access to directory */
+ dirent_set_errno (EACCES);
+ break;
+
+ case ERROR_DIRECTORY:
+ /* Directory name is invalid */
+ dirent_set_errno (ENOTDIR);
+ break;
+
+ case ERROR_PATH_NOT_FOUND:
+ default:
+ /* Cannot find the file */
+ dirent_set_errno (ENOENT);
+ }
+
}
return datap;
}
-/* Get next directory entry (internal) */
+/*
+ * Get next directory entry (internal).
+ *
+ * Returns
+ */
static WIN32_FIND_DATAW*
dirent_next(
_WDIR *dirp)
@@ -527,7 +653,7 @@ dirent_next(
/* Got a file */
p = &dirp->data;
} else {
- /* The very last entry has been processed or an error occured */
+ /* The very last entry has been processed or an error occurred */
FindClose (dirp->handle);
dirp->handle = INVALID_HANDLE_VALUE;
p = NULL;
@@ -552,6 +678,8 @@ opendir(
{
struct DIR *dirp;
int error;
+ wchar_t wname[PATH_MAX + 1];
+ size_t n;
/* Must have directory name */
if (dirname == NULL || dirname[0] == '\0') {
@@ -561,67 +689,71 @@ opendir(
/* Allocate memory for DIR structure */
dirp = (DIR*) malloc (sizeof (struct DIR));
- if (dirp) {
- wchar_t wname[PATH_MAX];
- size_t n;
-
- /* Convert directory name to wide-character string */
- error = dirent_mbstowcs_s (&n, wname, PATH_MAX, dirname, PATH_MAX);
- if (!error) {
-
- /* Open directory stream using wide-character name */
- dirp->wdirp = _wopendir (wname);
- if (dirp->wdirp) {
- /* Directory stream opened */
- error = 0;
- } else {
- /* Failed to open directory stream */
- error = 1;
- }
-
- } else {
- /*
- * Cannot convert file name to wide-character string. This
- * occurs if the string contains invalid multi-byte sequences or
- * the output buffer is too small to contain the resulting
- * string.
- */
- error = 1;
- }
+ if (!dirp) {
+ return NULL;
+ }
- } else {
- /* Cannot allocate DIR structure */
- error = 1;
+ /* Convert directory name to wide-character string */
+ error = dirent_mbstowcs_s(
+ &n, wname, PATH_MAX + 1, dirname, PATH_MAX + 1);
+ if (error) {
+ /*
+ * Cannot convert file name to wide-character string. This
+ * occurs if the string contains invalid multi-byte sequences or
+ * the output buffer is too small to contain the resulting
+ * string.
+ */
+ goto exit_free;
}
- /* Clean up in case of error */
- if (error && dirp) {
- free (dirp);
- dirp = NULL;
+
+ /* Open directory stream using wide-character name */
+ dirp->wdirp = _wopendir (wname);
+ if (!dirp->wdirp) {
+ goto exit_free;
}
+ /* Success */
return dirp;
+
+ /* Failure */
+exit_free:
+ free (dirp);
+ return NULL;
}
/*
* Read next directory entry.
- *
- * When working with text consoles, please note that file names returned by
- * readdir() are represented in the default ANSI code page while any output to
- * console is typically formatted on another code page. Thus, non-ASCII
- * characters in file names will not usually display correctly on console. The
- * problem can be fixed in two ways: (1) change the character set of console
- * to 1252 using chcp utility and use Lucida Console font, or (2) use
- * _cprintf function when writing to console. The _cprinf() will re-encode
- * ANSI strings to the console code page so many non-ASCII characters will
- * display correcly.
*/
static struct dirent*
readdir(
DIR *dirp)
{
+ struct dirent *entry;
+
+ /*
+ * Read directory entry to buffer. We can safely ignore the return value
+ * as entry will be set to NULL in case of error.
+ */
+ (void) readdir_r (dirp, &dirp->ent, &entry);
+
+ /* Return pointer to statically allocated directory entry */
+ return entry;
+}
+
+/*
+ * Read next directory entry into called-allocated buffer.
+ *
+ * Returns zero on success. If the end of directory stream is reached, then
+ * sets result to NULL and returns zero.
+ */
+static int
+readdir_r(
+ DIR *dirp,
+ struct dirent *entry,
+ struct dirent **result)
+{
WIN32_FIND_DATAW *datap;
- struct dirent *entp;
/* Read next directory entry */
datap = dirent_next (dirp->wdirp);
@@ -631,7 +763,7 @@ readdir(
/* Attempt to convert file name to multi-byte string */
error = dirent_wcstombs_s(
- &n, dirp->ent.d_name, PATH_MAX, datap->cFileName, PATH_MAX);
+ &n, entry->d_name, PATH_MAX + 1, datap->cFileName, PATH_MAX + 1);
/*
* If the file name cannot be represented by a multi-byte string,
@@ -645,55 +777,60 @@ readdir(
*/
if (error && datap->cAlternateFileName[0] != '\0') {
error = dirent_wcstombs_s(
- &n, dirp->ent.d_name, PATH_MAX,
- datap->cAlternateFileName, PATH_MAX);
+ &n, entry->d_name, PATH_MAX + 1,
+ datap->cAlternateFileName, PATH_MAX + 1);
}
if (!error) {
DWORD attr;
- /* Initialize directory entry for return */
- entp = &dirp->ent;
-
/* Length of file name excluding zero terminator */
- entp->d_namlen = n - 1;
+ entry->d_namlen = n - 1;
/* File attributes */
attr = datap->dwFileAttributes;
if ((attr & FILE_ATTRIBUTE_DEVICE) != 0) {
- entp->d_type = DT_CHR;
+ entry->d_type = DT_CHR;
} else if ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0) {
- entp->d_type = DT_DIR;
+ entry->d_type = DT_DIR;
} else {
- entp->d_type = DT_REG;
+ entry->d_type = DT_REG;
}
/* Reset dummy fields */
- entp->d_ino = 0;
- entp->d_reclen = sizeof (struct dirent);
+ entry->d_ino = 0;
+ entry->d_off = 0;
+ entry->d_reclen = sizeof (struct dirent);
} else {
+
/*
* Cannot convert file name to multi-byte string so construct
- * an errornous directory entry and return that. Note that
+ * an erroneous directory entry and return that. Note that
* we cannot return NULL as that would stop the processing
* of directory entries completely.
*/
- entp = &dirp->ent;
- entp->d_name[0] = '?';
- entp->d_name[1] = '\0';
- entp->d_namlen = 1;
- entp->d_type = DT_UNKNOWN;
- entp->d_ino = 0;
- entp->d_reclen = 0;
+ entry->d_name[0] = '?';
+ entry->d_name[1] = '\0';
+ entry->d_namlen = 1;
+ entry->d_type = DT_UNKNOWN;
+ entry->d_ino = 0;
+ entry->d_off = -1;
+ entry->d_reclen = 0;
+
}
+ /* Return pointer to directory entry */
+ *result = entry;
+
} else {
+
/* No more directory entries */
- entp = NULL;
+ *result = NULL;
+
}
- return entp;
+ return /*OK*/0;
}
/*
@@ -734,6 +871,162 @@ rewinddir(
_wrewinddir (dirp->wdirp);
}
+/*
+ * Scan directory for entries.
+ */
+static int
+scandir(
+ const char *dirname,
+ struct dirent ***namelist,
+ int (*filter)(const struct dirent*),
+ int (*compare)(const struct dirent**, const struct dirent**))
+{
+ struct dirent **files = NULL;
+ size_t size = 0;
+ size_t allocated = 0;
+ const size_t init_size = 1;
+ DIR *dir = NULL;
+ struct dirent *entry;
+ struct dirent *tmp = NULL;
+ size_t i;
+ int result = 0;
+
+ /* Open directory stream */
+ dir = opendir (dirname);
+ if (dir) {
+
+ /* Read directory entries to memory */
+ while (1) {
+
+ /* Enlarge pointer table to make room for another pointer */
+ if (size >= allocated) {
+ void *p;
+ size_t num_entries;
+
+ /* Compute number of entries in the enlarged pointer table */
+ if (size < init_size) {
+ /* Allocate initial pointer table */
+ num_entries = init_size;
+ } else {
+ /* Double the size */
+ num_entries = size * 2;
+ }
+
+ /* Allocate first pointer table or enlarge existing table */
+ p = realloc (files, sizeof (void*) * num_entries);
+ if (p != NULL) {
+ /* Got the memory */
+ files = (dirent**) p;
+ allocated = num_entries;
+ } else {
+ /* Out of memory */
+ result = -1;
+ break;
+ }
+
+ }
+
+ /* Allocate room for temporary directory entry */
+ if (tmp == NULL) {
+ tmp = (struct dirent*) malloc (sizeof (struct dirent));
+ if (tmp == NULL) {
+ /* Cannot allocate temporary directory entry */
+ result = -1;
+ break;
+ }
+ }
+
+ /* Read directory entry to temporary area */
+ if (readdir_r (dir, tmp, &entry) == /*OK*/0) {
+
+ /* Did we get an entry? */
+ if (entry != NULL) {
+ int pass;
+
+ /* Determine whether to include the entry in result */
+ if (filter) {
+ /* Let the filter function decide */
+ pass = filter (tmp);
+ } else {
+ /* No filter function, include everything */
+ pass = 1;
+ }
+
+ if (pass) {
+ /* Store the temporary entry to pointer table */
+ files[size++] = tmp;
+ tmp = NULL;
+
+ /* Keep up with the number of files */
+ result++;
+ }
+
+ } else {
+
+ /*
+ * End of directory stream reached => sort entries and
+ * exit.
+ */
+ qsort (files, size, sizeof (void*),
+ (int (*) (const void*, const void*)) compare);
+ break;
+
+ }
+
+ } else {
+ /* Error reading directory entry */
+ result = /*Error*/ -1;
+ break;
+ }
+
+ }
+
+ } else {
+ /* Cannot open directory */
+ result = /*Error*/ -1;
+ }
+
+ /* Release temporary directory entry */
+ free (tmp);
+
+ /* Release allocated memory on error */
+ if (result < 0) {
+ for (i = 0; i < size; i++) {
+ free (files[i]);
+ }
+ free (files);
+ files = NULL;
+ }
+
+ /* Close directory stream */
+ if (dir) {
+ closedir (dir);
+ }
+
+ /* Pass pointer table to caller */
+ if (namelist) {
+ *namelist = files;
+ }
+ return result;
+}
+
+/* Alphabetical sorting */
+static int
+alphasort(
+ const struct dirent **a, const struct dirent **b)
+{
+ return strcoll ((*a)->d_name, (*b)->d_name);
+}
+
+/* Sort versions */
+static int
+versionsort(
+ const struct dirent **a, const struct dirent **b)
+{
+ /* FIXME: implement strverscmp and use that */
+ return alphasort (a, b);
+}
+
/* Convert multi-byte string to wide character string */
static int
dirent_mbstowcs_s(
@@ -744,46 +1037,87 @@ dirent_mbstowcs_s(
size_t count)
{
int error;
-
-#if defined(_MSC_VER) && _MSC_VER >= 1400
-
- /* Microsoft Visual Studio 2005 or later */
- error = mbstowcs_s (pReturnValue, wcstr, sizeInWords, mbstr, count);
-
+ int n;
+ size_t len;
+ UINT cp;
+ DWORD flags;
+
+ /* Determine code page for multi-byte string */
+#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
+ if (AreFileApisANSI ()) {
+ /* Default ANSI code page */
+ cp = GetACP ();
+ } else {
+ /* Default OEM code page */
+ cp = GetOEMCP ();
+ }
#else
+ cp = CP_ACP;
+#endif // WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
+
+ /*
+ * Determine flags based on the character set. For more information,
+ * please see https://docs.microsoft.com/fi-fi/windows/desktop/api/stringapiset/nf-stringapiset-multibytetowidechar
+ */
+ switch (cp) {
+ case 42:
+ case 50220:
+ case 50221:
+ case 50222:
+ case 50225:
+ case 50227:
+ case 50229:
+ case 57002:
+ case 57003:
+ case 57004:
+ case 57005:
+ case 57006:
+ case 57007:
+ case 57008:
+ case 57009:
+ case 57010:
+ case 57011:
+ case 65000:
+ /* MultiByteToWideChar does not support MB_ERR_INVALID_CHARS */
+ flags = 0;
+ break;
+
+ default:
+ /*
+ * Ask MultiByteToWideChar to return an error if a multi-byte
+ * character cannot be converted to a wide-character.
+ */
+ flags = MB_ERR_INVALID_CHARS;
+ }
- /* Older Visual Studio or non-Microsoft compiler */
- size_t n;
+ /* Compute the length of input string without zero-terminator */
+ len = 0;
+ while (mbstr[len] != '\0' && len < count) {
+ len++;
+ }
- /* Convert to wide-character string (or count characters) */
- n = mbstowcs (wcstr, mbstr, sizeInWords);
- if (!wcstr || n < count) {
+ /* Convert to wide-character string */
+ n = MultiByteToWideChar(
+ /* Source code page */ cp,
+ /* Flags */ flags,
+ /* Pointer to string to convert */ mbstr,
+ /* Size of multi-byte string */ (int) len,
+ /* Pointer to output buffer */ wcstr,
+ /* Size of output buffer */ (int)sizeInWords - 1
+ );
- /* Zero-terminate output buffer */
- if (wcstr && sizeInWords) {
- if (n >= sizeInWords) {
- n = sizeInWords - 1;
- }
- wcstr[n] = 0;
- }
+ /* Ensure that output buffer is zero-terminated */
+ wcstr[n] = '\0';
- /* Length of resuting multi-byte string WITH zero terminator */
- if (pReturnValue) {
- *pReturnValue = n + 1;
- }
+ /* Return length of wide-character string with zero-terminator */
+ *pReturnValue = (size_t) (n + 1);
- /* Success */
+ /* Return zero if conversion succeeded */
+ if (n > 0) {
error = 0;
-
} else {
-
- /* Could not convert string */
error = 1;
-
}
-
-#endif
-
return error;
}
@@ -796,47 +1130,82 @@ dirent_wcstombs_s(
const wchar_t *wcstr,
size_t count)
{
+ int n;
int error;
-
-#if defined(_MSC_VER) && _MSC_VER >= 1400
-
- /* Microsoft Visual Studio 2005 or later */
- error = wcstombs_s (pReturnValue, mbstr, sizeInBytes, wcstr, count);
-
+ UINT cp;
+ size_t len;
+ BOOL flag = 0;
+ LPBOOL pflag;
+
+ /* Determine code page for multi-byte string */
+#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
+ if (AreFileApisANSI ()) {
+ /* Default ANSI code page */
+ cp = GetACP ();
+ } else {
+ /* Default OEM code page */
+ cp = GetOEMCP ();
+ }
#else
+ cp = CP_ACP;
+#endif // WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
- /* Older Visual Studio or non-Microsoft compiler */
- size_t n;
- /* Convert to multi-byte string (or count the number of bytes needed) */
- n = wcstombs (mbstr, wcstr, sizeInBytes);
- if (!mbstr || n < count) {
+ /* Compute the length of input string without zero-terminator */
+ len = 0;
+ while (wcstr[len] != '\0' && len < count) {
+ len++;
+ }
- /* Zero-terminate output buffer */
- if (mbstr && sizeInBytes) {
- if (n >= sizeInBytes) {
- n = sizeInBytes - 1;
- }
- mbstr[n] = '\0';
- }
+ /*
+ * Determine if we can ask WideCharToMultiByte to return information on
+ * broken characters. For more information, please see
+ * https://docs.microsoft.com/en-us/windows/desktop/api/stringapiset/nf-stringapiset-widechartomultibyte
+ */
+ switch (cp) {
+ case CP_UTF7:
+ case CP_UTF8:
+ /*
+ * WideCharToMultiByte fails if we request information on default
+ * characters. This is just a nuisance but doesn't affect the
+ * conversion: if Windows is configured to use UTF-8, then the default
+ * character should not be needed anyway.
+ */
+ pflag = NULL;
+ break;
- /* Lenght of resulting multi-bytes string WITH zero-terminator */
- if (pReturnValue) {
- *pReturnValue = n + 1;
- }
+ default:
+ /*
+ * Request that WideCharToMultiByte sets the flag if it uses the
+ * default character.
+ */
+ pflag = &flag;
+ }
- /* Success */
+ /* Convert wide-character string to multi-byte character string */
+ n = WideCharToMultiByte(
+ /* Target code page */ cp,
+ /* Flags */ 0,
+ /* Pointer to unicode string */ wcstr,
+ /* Length of unicode string */ (int) len,
+ /* Pointer to output buffer */ mbstr,
+ /* Size of output buffer */ (int)sizeInBytes - 1,
+ /* Default character */ NULL,
+ /* Whether default character was used or not */ pflag
+ );
+
+ /* Ensure that output buffer is zero-terminated */
+ mbstr[n] = '\0';
+
+ /* Return length of multi-byte string with zero-terminator */
+ *pReturnValue = (size_t) (n + 1);
+
+ /* Return zero if conversion succeeded without using default characters */
+ if (n > 0 && flag == 0) {
error = 0;
-
} else {
-
- /* Cannot convert string */
error = 1;
-
}
-
-#endif
-
return error;
}
@@ -858,6 +1227,7 @@ dirent_set_errno(
#endif
}
+
#ifdef __cplusplus
}
#endif
diff --git a/3rdparty/bx/makefile b/3rdparty/bx/makefile
index 65e55a7715e..e9b00eb6331 100644
--- a/3rdparty/bx/makefile
+++ b/3rdparty/bx/makefile
@@ -1,22 +1,25 @@
#
-# Copyright 2011-2018 Branimir Karadzic. All rights reserved.
-# License: https://github.com/bkaradzic/bx#license-bsd-2-clause
+# Copyright 2011-2022 Branimir Karadzic. All rights reserved.
+# License: https://github.com/bkaradzic/bx/blob/master/LICENSE
#
GENIE=../bx/tools/bin/$(OS)/genie
all:
- $(GENIE) vs2017
- $(GENIE) --gcc=android-arm gmake
- $(GENIE) --gcc=android-mips gmake
- $(GENIE) --gcc=android-x86 gmake
- $(GENIE) --gcc=mingw-gcc gmake
- $(GENIE) --gcc=linux-gcc gmake
- $(GENIE) --gcc=osx gmake
- $(GENIE) --gcc=ios-arm gmake
- $(GENIE) --gcc=ios-simulator gmake
+ $(GENIE) vs2017
+ $(GENIE) vs2019
+ $(GENIE) --gcc=android-arm gmake
+ $(GENIE) --gcc=android-arm64 gmake
+ $(GENIE) --gcc=android-x86 gmake
+ $(GENIE) --gcc=mingw-gcc gmake
+ $(GENIE) --gcc=linux-gcc gmake
+ $(GENIE) --gcc=haiku gmake
+ $(GENIE) --gcc=osx-x64 gmake
+ $(GENIE) --gcc=osx-arm64 gmake
+ $(GENIE) --gcc=ios-arm gmake
+ $(GENIE) --gcc=ios-simulator gmake
$(GENIE) --gcc=ios-simulator64 gmake
- $(GENIE) xcode8
+ $(GENIE) xcode8
.build/projects/gmake-android-arm:
$(GENIE) --gcc=android-arm gmake
@@ -26,13 +29,13 @@ android-arm-release: .build/projects/gmake-android-arm
make -R -C .build/projects/gmake-android-arm config=release
android-arm: android-arm-debug android-arm-release
-.build/projects/gmake-android-mips:
- $(GENIE) --gcc=android-mips gmake
-android-mips-debug: .build/projects/gmake-android-mips
- make -R -C .build/projects/gmake-android-mips config=debug
-android-mips-release: .build/projects/gmake-android-mips
- make -R -C .build/projects/gmake-android-mips config=release
-android-mips: android-mips-debug android-mips-release
+.build/projects/gmake-android-arm64:
+ $(GENIE) --gcc=android-arm64 gmake
+android-arm64-debug: .build/projects/gmake-android-arm64
+ make -R -C .build/projects/gmake-android-arm64 config=debug
+android-arm64-release: .build/projects/gmake-android-arm64
+ make -R -C .build/projects/gmake-android-arm64 config=release
+android-arm64: android-arm64-debug android-arm64-release
.build/projects/gmake-android-x86:
$(GENIE) --gcc=android-x86 gmake
@@ -50,6 +53,14 @@ linux-release64: .build/projects/gmake-linux
make -R -C .build/projects/gmake-linux config=release64
linux: linux-debug64 linux-release64
+.build/projects/gmake-haiku:
+ $(GENIE) --gcc=haiku gmake
+haiku-debug64: .build/projects/gmake-haiku
+ make -R -C .build/projects/gmake-haiku config=debug64
+haiku-release64: .build/projects/gmake-haiku
+ make -R -C .build/projects/gmake-haiku config=release64
+haiku: haiku-debug64 haiku-release64
+
.build/projects/gmake-mingw-gcc:
$(GENIE) --gcc=mingw-gcc gmake
mingw-gcc-debug32: .build/projects/gmake-mingw-gcc
@@ -77,13 +88,21 @@ mingw-clang: mingw-clang-debug32 mingw-clang-release32 mingw-clang-debug64 mingw
.build/projects/vs2017:
$(GENIE) vs2017
-.build/projects/gmake-osx:
- $(GENIE) --gcc=osx gmake
-osx-debug64: .build/projects/gmake-osx
- make -C .build/projects/gmake-osx config=debug64
-osx-release64: .build/projects/gmake-osx
- make -C .build/projects/gmake-osx config=release64
-osx: osx-debug64 osx-release64
+.build/projects/gmake-osx-x64:
+ $(GENIE) --gcc=osx-x64 gmake
+osx-x64-debug: .build/projects/gmake-osx-x64
+ make -C .build/projects/gmake-osx config=debug
+osx-x64-release: .build/projects/gmake-osx-x64
+ make -C .build/projects/gmake-osx config=release
+osx-x64: osx-x64-debug osx-x64-release
+
+.build/projects/gmake-osx-arm64:
+ $(GENIE) --gcc=osx-arm64 gmake
+osx-arm64-debug: .build/projects/gmake-osx-arm64
+ make -C .build/projects/gmake-osx-arm64 config=debug
+osx-arm64-release: .build/projects/gmake-osx-arm64
+ make -C .build/projects/gmake-osx-arm64 config=release
+osx-arm64: osx-arm64-debug osx-arm64-release
.build/projects/gmake-ios-arm:
$(GENIE) --gcc=ios-arm gmake
@@ -130,13 +149,21 @@ clean:
SILENT ?= @
UNAME := $(shell uname)
-ifeq ($(UNAME),$(filter $(UNAME),Linux GNU Darwin))
+ifeq ($(UNAME),$(filter $(UNAME),Linux GNU Darwin Haiku))
+ifeq ($(UNAME),$(filter $(UNAME),Darwin Haiku))
ifeq ($(UNAME),$(filter $(UNAME),Darwin))
OS=darwin
-BUILD_PROJECT_DIR=gmake-osx
-BUILD_OUTPUT_DIR=osx64_clang
+BUILD_PROJECT_DIR=gmake-osx-x64
+BUILD_OUTPUT_DIR=osx-x64
+BUILD_TOOLS_CONFIG=release
+EXE=
+else
+OS=haiku
+BUILD_PROJECT_DIR=gmake-haiku
+BUILD_OUTPUT_DIR=haiku64_gcc
BUILD_TOOLS_CONFIG=release64
EXE=
+endif
else
OS=linux
BUILD_PROJECT_DIR=gmake-linux
@@ -153,10 +180,10 @@ EXE=.exe
endif
# bin2c
-.build/osx64_clang/bin/bin2cRelease: .build/projects/gmake-osx
- $(SILENT) make -C .build/projects/gmake-osx bin2c config=$(BUILD_TOOLS_CONFIG)
+.build/osx-x64/bin/bin2cRelease: .build/projects/gmake-osx-x64
+ $(SILENT) make -C .build/projects/gmake-osx-x64 bin2c config=$(BUILD_TOOLS_CONFIG)
-tools/bin/darwin/bin2c: .build/osx64_clang/bin/bin2cRelease
+tools/bin/darwin/bin2c: .build/osx-x64/bin/bin2cRelease
$(SILENT) cp $(<) $(@)
.build/linux64_gcc/bin/bin2cRelease: .build/projects/gmake-linux
@@ -165,6 +192,12 @@ tools/bin/darwin/bin2c: .build/osx64_clang/bin/bin2cRelease
tools/bin/linux/bin2c: .build/linux64_gcc/bin/bin2cRelease
$(SILENT) cp $(<) $(@)
+.build/haiku64_gcc/bin/bin2cRelease: .build/projects/gmake-haiku
+ $(SILENT) make -C .build/projects/gmake-haiku bin2c config=$(BUILD_TOOLS_CONFIG)
+
+tools/bin/haiku/bin2c: .build/haiku64_gcc/bin/bin2cRelease
+ $(SILENT) cp $(<) $(@)
+
.build/win64_mingw-gcc/bin/bin2cRelease.exe: .build/projects/gmake-mingw-gcc
$(SILENT) make -C .build/projects/gmake-mingw-gcc bin2c config=$(BUILD_TOOLS_CONFIG)
@@ -174,10 +207,10 @@ tools/bin/windows/bin2c.exe: .build/win64_mingw-gcc/bin/bin2cRelease.exe
bin2c: tools/bin/$(OS)/bin2c$(EXE)
# lemon
-.build/osx64_clang/bin/lemonRelease: .build/projects/gmake-osx
- $(SILENT) make -C .build/projects/gmake-osx lemon config=$(BUILD_TOOLS_CONFIG)
+.build/osx-x64/bin/lemonRelease: .build/projects/gmake-osx-x64
+ $(SILENT) make -C .build/projects/gmake-osx-x64 lemon config=$(BUILD_TOOLS_CONFIG)
-tools/bin/darwin/lemon: .build/osx64_clang/bin/lemonRelease
+tools/bin/darwin/lemon: .build/osx-x64/bin/lemonRelease
$(SILENT) cp $(<) $(@)
.build/linux64_gcc/bin/lemonRelease: .build/projects/gmake-linux
@@ -186,6 +219,12 @@ tools/bin/darwin/lemon: .build/osx64_clang/bin/lemonRelease
tools/bin/linux/lemon: .build/linux64_gcc/bin/lemonRelease
$(SILENT) cp $(<) $(@)
+.build/haiku64_gcc/bin/lemonRelease: .build/projects/gmake-haiku
+ $(SILENT) make -C .build/projects/gmake-haiku lemon config=$(BUILD_TOOLS_CONFIG)
+
+tools/bin/haiku/lemon: .build/haiku64_gcc/bin/lemonRelease
+ $(SILENT) cp $(<) $(@)
+
.build/win64_mingw-gcc/bin/lemonRelease.exe: .build/projects/gmake-mingw-gcc
$(SILENT) make -C .build/projects/gmake-mingw-gcc lemon config=$(BUILD_TOOLS_CONFIG)
@@ -199,7 +238,7 @@ lemon: tools/bin/$(OS)/lemon$(EXE) tools/bin/$(OS)/lempar.c
tools: bin2c lemon
-dist: tools/bin/darwin/bin2c tools/bin/linux/bin2c tools/bin/windows/bin2c.exe
+dist: tools/bin/darwin/bin2c tools/bin/linux/bin2c tools/bin/windows/bin2c.exe tools/bin/haiku/bin2c
.build/$(BUILD_OUTPUT_DIR)/bin/bx.testRelease$(EXE): .build/projects/$(BUILD_PROJECT_DIR)
$(SILENT) make -C .build/projects/$(BUILD_PROJECT_DIR) bx.test config=$(BUILD_TOOLS_CONFIG)
diff --git a/3rdparty/bx/scripts/bin2c.lua b/3rdparty/bx/scripts/bin2c.lua
index fc4dec96c69..9e9e4866964 100644
--- a/3rdparty/bx/scripts/bin2c.lua
+++ b/3rdparty/bx/scripts/bin2c.lua
@@ -1,23 +1,17 @@
--
--- Copyright 2010-2018 Branimir Karadzic. All rights reserved.
--- License: https://github.com/bkaradzic/bx#license-bsd-2-clause
+-- Copyright 2010-2022 Branimir Karadzic. All rights reserved.
+-- License: https://github.com/bkaradzic/bx/blob/master/LICENSE
--
project "bin2c"
kind "ConsoleApp"
- includedirs {
- "../include",
- }
-
files {
"../tools/bin2c/**.cpp",
"../tools/bin2c/**.h",
}
- links {
- "bx",
- }
+ using_bx()
configuration { "mingw-*" }
targetextension ".exe"
@@ -26,6 +20,10 @@ project "bin2c"
links {
"pthread",
}
+ configuration { "osx-*" }
+ linkoptions {
+ "-framework Foundation"
+ }
configuration { "vs20* or mingw*" }
links {
diff --git a/3rdparty/bx/scripts/bx.lua b/3rdparty/bx/scripts/bx.lua
index bb0d17ade18..1bb5dc43d4b 100644
--- a/3rdparty/bx/scripts/bx.lua
+++ b/3rdparty/bx/scripts/bx.lua
@@ -1,8 +1,42 @@
--
--- Copyright 2010-2018 Branimir Karadzic. All rights reserved.
--- License: https://github.com/bkaradzic/bx#license-bsd-2-clause
+-- Copyright 2010-2022 Branimir Karadzic. All rights reserved.
+-- License: https://github.com/bkaradzic/bx/blob/master/LICENSE
--
+local function userdefines()
+ local defines = {}
+ local BX_CONFIG = os.getenv("BX_CONFIG")
+ if BX_CONFIG then
+ for def in BX_CONFIG:gmatch "[^%s:]+" do
+ table.insert(defines, "BX_CONFIG_" .. def)
+ end
+ end
+
+ return defines
+end
+
+function using_bx()
+ includedirs {
+ path.join(BX_DIR, "include"),
+ }
+
+ links {
+ "bx",
+ }
+
+ configuration { "Debug" }
+ defines {
+ "BX_CONFIG_DEBUG=1",
+ }
+
+ configuration { "Release" }
+ defines {
+ "BX_CONFIG_DEBUG=0",
+ }
+
+ configuration {}
+end
+
project "bx"
kind "StaticLib"
@@ -18,10 +52,7 @@ project "bx"
path.join(BX_DIR, "scripts/**.natvis"),
}
- configuration { "Debug" }
- defines {
- "BX_CONFIG_DEBUG=1",
- }
+ defines (userdefines())
configuration { "linux-*" }
buildoptions {
@@ -33,6 +64,7 @@ project "bx"
if _OPTIONS["with-amalgamated"] then
excludes {
path.join(BX_DIR, "src/allocator.cpp"),
+ path.join(BX_DIR, "src/bounds.cpp"),
path.join(BX_DIR, "src/bx.cpp"),
path.join(BX_DIR, "src/commandline.cpp"),
path.join(BX_DIR, "src/crtnone.cpp"),
@@ -60,4 +92,14 @@ project "bx"
}
end
+ configuration { "Debug" }
+ defines {
+ "BX_CONFIG_DEBUG=1",
+ }
+
+ configuration { "Release" }
+ defines {
+ "BX_CONFIG_DEBUG=0",
+ }
+
configuration {}
diff --git a/3rdparty/bx/scripts/genie.lua b/3rdparty/bx/scripts/genie.lua
index 3cdb23e7c60..5a7b3281bd9 100644
--- a/3rdparty/bx/scripts/genie.lua
+++ b/3rdparty/bx/scripts/genie.lua
@@ -1,6 +1,6 @@
--
--- Copyright 2010-2018 Branimir Karadzic. All rights reserved.
--- License: https://github.com/bkaradzic/bx#license-bsd-2-clause
+-- Copyright 2010-2022 Branimir Karadzic. All rights reserved.
+-- License: https://github.com/bkaradzic/bx/blob/master/LICENSE
--
newoption {
@@ -51,19 +51,21 @@ project "bx.test"
}
includedirs {
- path.join(BX_DIR, "include"),
BX_THIRD_PARTY_DIR,
}
+ defines {
+ "CATCH_AMALGAMATED_CUSTOM_MAIN",
+ }
+
files {
+ path.join(BX_DIR, "3rdparty/catch/catch_amalgamated.cpp"),
path.join(BX_DIR, "tests/*_test.cpp"),
path.join(BX_DIR, "tests/*.h"),
path.join(BX_DIR, "tests/dbg.*"),
}
- links {
- "bx",
- }
+ using_bx()
configuration { "vs* or mingw*" }
links {
@@ -81,7 +83,7 @@ project "bx.test"
"pthread",
}
- configuration { "osx" }
+ configuration { "osx*" }
links {
"Cocoa.framework",
}
@@ -126,11 +128,21 @@ project "bx.bench"
"pthread",
}
- configuration { "osx" }
+ configuration { "osx*" }
links {
"Cocoa.framework",
}
+ configuration { "Debug" }
+ defines {
+ "BX_CONFIG_DEBUG=1",
+ }
+
+ configuration { "Release" }
+ defines {
+ "BX_CONFIG_DEBUG=0",
+ }
+
configuration {}
strip()
diff --git a/3rdparty/bx/scripts/lemon.lua b/3rdparty/bx/scripts/lemon.lua
index 21024fd80b9..fd51b88a67c 100644
--- a/3rdparty/bx/scripts/lemon.lua
+++ b/3rdparty/bx/scripts/lemon.lua
@@ -1,6 +1,6 @@
--
--- Copyright 2010-2018 Branimir Karadzic. All rights reserved.
--- License: https://github.com/bkaradzic/bx#license-bsd-2-clause
+-- Copyright 2010-2022 Branimir Karadzic. All rights reserved.
+-- License: https://github.com/bkaradzic/bx/blob/master/LICENSE
--
project "lemon"
diff --git a/3rdparty/bx/scripts/toolchain.lua b/3rdparty/bx/scripts/toolchain.lua
index 03f97089b7b..964e58e3793 100644
--- a/3rdparty/bx/scripts/toolchain.lua
+++ b/3rdparty/bx/scripts/toolchain.lua
@@ -1,6 +1,6 @@
--
--- Copyright 2010-2018 Branimir Karadzic. All rights reserved.
--- License: https://github.com/bkaradzic/bx#license-bsd-2-clause
+-- Copyright 2010-2022 Branimir Karadzic. All rights reserved.
+-- License: https://github.com/bkaradzic/bx/blob/master/LICENSE
--
local bxDir = path.getabsolute("..")
@@ -42,6 +42,21 @@ local function crtNone()
configuration {}
end
+local android = {};
+
+local function androidToolchainRoot()
+ if android.toolchainRoot == nil then
+ local hostTags = {
+ windows = "windows-x86_64",
+ linux = "linux-x86_64",
+ macosx = "darwin-x86_64"
+ }
+ android.toolchainRoot = "$(ANDROID_NDK_ROOT)/toolchains/llvm/prebuilt/" .. hostTags[os.get()]
+ end
+
+ return android.toolchainRoot;
+end
+
function toolchain(_buildDir, _libDir)
newoption {
@@ -50,16 +65,19 @@ function toolchain(_buildDir, _libDir)
description = "Choose GCC flavor",
allowed = {
{ "android-arm", "Android - ARM" },
+ { "android-arm64", "Android - ARM64" },
{ "android-x86", "Android - x86" },
- { "asmjs", "Emscripten/asm.js" },
+ { "android-x86_64", "Android - x86_64" },
+ { "wasm2js", "Emscripten/Wasm2JS" },
+ { "wasm", "Emscripten/Wasm" },
{ "freebsd", "FreeBSD" },
{ "linux-gcc", "Linux (GCC compiler)" },
{ "linux-gcc-afl", "Linux (GCC + AFL fuzzer)" },
- { "linux-gcc-6", "Linux (GCC-6 compiler)" },
{ "linux-clang", "Linux (Clang compiler)" },
{ "linux-clang-afl", "Linux (Clang + AFL fuzzer)" },
- { "linux-mips-gcc", "Linux (MIPS, GCC compiler)" },
{ "linux-arm-gcc", "Linux (ARM, GCC compiler)" },
+ { "linux-ppc64le-gcc", "Linux (PPC64LE, GCC compiler)" },
+ { "linux-ppc64le-clang", "Linux (PPC64LE, Clang compiler)" },
{ "ios-arm", "iOS - ARM" },
{ "ios-arm64", "iOS - ARM64" },
{ "ios-simulator", "iOS - Simulator" },
@@ -69,7 +87,8 @@ function toolchain(_buildDir, _libDir)
{ "mingw-gcc", "MinGW" },
{ "mingw-clang", "MinGW (clang compiler)" },
{ "netbsd", "NetBSD" },
- { "osx", "OSX" },
+ { "osx-x64", "OSX - x64" },
+ { "osx-arm64", "OSX - ARM64" },
{ "orbis", "Orbis" },
{ "riscv", "RISC-V" },
{ "rpi", "RaspberryPi" },
@@ -81,13 +100,7 @@ function toolchain(_buildDir, _libDir)
value = "toolset",
description = "Choose VS toolset",
allowed = {
- { "vs2012-clang", "Clang 3.6" },
- { "vs2013-clang", "Clang 3.6" },
- { "vs2015-clang", "Clang 3.9" },
{ "vs2017-clang", "Clang with MS CodeGen" },
- { "vs2012-xp", "Visual Studio 2012 targeting XP" },
- { "vs2013-xp", "Visual Studio 2013 targeting XP" },
- { "vs2015-xp", "Visual Studio 2015 targeting XP" },
{ "vs2017-xp", "Visual Studio 2017 targeting XP" },
{ "winstore100", "Universal Windows App 10.0" },
{ "durango", "Durango" },
@@ -109,7 +122,7 @@ function toolchain(_buildDir, _libDir)
newoption {
trigger = "with-android",
value = "#",
- description = "Set Android platform version (default: android-14).",
+ description = "Set Android platform version (default: android-24).",
}
newoption {
@@ -162,9 +175,9 @@ function toolchain(_buildDir, _libDir)
os.exit(1)
end
- local androidPlatform = "android-24"
+ local androidApiLevel = 24
if _OPTIONS["with-android"] then
- androidPlatform = "android-" .. _OPTIONS["with-android"]
+ androidApiLevel = _OPTIONS["with-android"]
end
local iosPlatform = ""
@@ -182,9 +195,11 @@ function toolchain(_buildDir, _libDir)
tvosPlatform = _OPTIONS["with-tvos"]
end
- local windowsPlatform = string.gsub(os.getenv("WindowsSDKVersion") or "8.1", "\\", "")
+ local windowsPlatform = nil
if _OPTIONS["with-windows"] then
windowsPlatform = _OPTIONS["with-windows"]
+ elseif nil ~= os.getenv("WindowsSDKVersion") then
+ windowsPlatform = string.gsub(os.getenv("WindowsSDKVersion"), "\\", "")
end
local compiler32bit = false
@@ -193,7 +208,9 @@ function toolchain(_buildDir, _libDir)
end
flags {
+ "Cpp14",
"ExtraWarnings",
+ "FloatFast",
}
if _ACTION == "gmake" or _ACTION == "ninja" then
@@ -203,45 +220,30 @@ function toolchain(_buildDir, _libDir)
os.exit(1)
end
- if "android-arm" == _OPTIONS["gcc"] then
-
- if not os.getenv("ANDROID_NDK_ARM")
- or not os.getenv("ANDROID_NDK_CLANG")
- or not os.getenv("ANDROID_NDK_ROOT") then
- print("Set ANDROID_NDK_CLANG, ANDROID_NDK_ARM, and ANDROID_NDK_ROOT environment variables.")
- end
+ if "android-arm" == _OPTIONS["gcc"]
+ or "android-arm64" == _OPTIONS["gcc"]
+ or "android-x86" == _OPTIONS["gcc"]
+ or "android-x86_64" == _OPTIONS["gcc"] then
- premake.gcc.cc = "$(ANDROID_NDK_CLANG)/bin/clang"
- premake.gcc.cxx = "$(ANDROID_NDK_CLANG)/bin/clang++"
- premake.gcc.ar = "$(ANDROID_NDK_ARM)/bin/arm-linux-androideabi-ar"
+ premake.gcc.cc = androidToolchainRoot() .. "/bin/clang"
+ premake.gcc.cxx = androidToolchainRoot() .. "/bin/clang++"
+ premake.gcc.ar = androidToolchainRoot() .. "/bin/llvm-ar"
premake.gcc.llvm = true
- location (path.join(_buildDir, "projects", _ACTION .. "-android-arm"))
-
- elseif "android-x86" == _OPTIONS["gcc"] then
-
- if not os.getenv("ANDROID_NDK_X86")
- or not os.getenv("ANDROID_NDK_CLANG")
- or not os.getenv("ANDROID_NDK_ROOT") then
- print("Set ANDROID_NDK_CLANG, ANDROID_NDK_X86, and ANDROID_NDK_ROOT environment variables.")
- end
-
- premake.gcc.cc = "$(ANDROID_NDK_CLANG)/bin/clang"
- premake.gcc.cxx = "$(ANDROID_NDK_CLANG)/bin/clang++"
- premake.gcc.llvm = true
- location (path.join(_buildDir, "projects", _ACTION .. "-android-x86"))
+ location (path.join(_buildDir, "projects", _ACTION .. "-" .. _OPTIONS["gcc"]))
- elseif "asmjs" == _OPTIONS["gcc"] then
+ elseif "wasm2js" == _OPTIONS["gcc"] or "wasm" == _OPTIONS["gcc"] then
if not os.getenv("EMSCRIPTEN") then
- print("Set EMSCRIPTEN environment variable.")
+ print("Set EMSCRIPTEN environment variable to root directory of your Emscripten installation. (e.g. by entering the EMSDK command prompt)")
end
premake.gcc.cc = "\"$(EMSCRIPTEN)/emcc\""
premake.gcc.cxx = "\"$(EMSCRIPTEN)/em++\""
premake.gcc.ar = "\"$(EMSCRIPTEN)/emar\""
premake.gcc.llvm = true
- location (path.join(_buildDir, "projects", _ACTION .. "-asmjs"))
+ premake.gcc.namestyle = "Emscripten"
+ location (path.join(_buildDir, "projects", _ACTION .. "-" .. _OPTIONS["gcc"]))
elseif "freebsd" == _OPTIONS["gcc"] then
location (path.join(_buildDir, "projects", _ACTION .. "-freebsd"))
@@ -286,12 +288,6 @@ function toolchain(_buildDir, _libDir)
premake.gcc.ar = "ar"
location (path.join(_buildDir, "projects", _ACTION .. "-linux"))
- elseif "linux-gcc-6" == _OPTIONS["gcc"] then
- premake.gcc.cc = "gcc-6"
- premake.gcc.cxx = "g++-6"
- premake.gcc.ar = "ar"
- location (path.join(_buildDir, "projects", _ACTION .. "-linux"))
-
elseif "linux-clang" == _OPTIONS["gcc"] then
premake.gcc.cc = "clang"
premake.gcc.cxx = "clang++"
@@ -304,21 +300,18 @@ function toolchain(_buildDir, _libDir)
premake.gcc.ar = "ar"
location (path.join(_buildDir, "projects", _ACTION .. "-linux-clang"))
- elseif "linux-mips-gcc" == _OPTIONS["gcc"] then
- location (path.join(_buildDir, "projects", _ACTION .. "-linux-mips-gcc"))
-
elseif "linux-arm-gcc" == _OPTIONS["gcc"] then
location (path.join(_buildDir, "projects", _ACTION .. "-linux-arm-gcc"))
- elseif "linux-steamlink" == _OPTIONS["gcc"] then
- if not os.getenv("MARVELL_SDK_PATH") then
- print("Set MARVELL_SDK_PATH environment variable.")
- end
+ elseif "linux-ppc64le-gcc" == _OPTIONS["gcc"] then
+ location (path.join(_buildDir, "projects", _ACTION .. "-linux-ppc64le-gcc"))
- premake.gcc.cc = "$(MARVELL_SDK_PATH)/toolchain/bin/armv7a-cros-linux-gnueabi-gcc"
- premake.gcc.cxx = "$(MARVELL_SDK_PATH)/toolchain/bin/armv7a-cros-linux-gnueabi-g++"
- premake.gcc.ar = "$(MARVELL_SDK_PATH)/toolchain/bin/armv7a-cros-linux-gnueabi-ar"
- location (path.join(_buildDir, "projects", _ACTION .. "-linux-steamlink"))
+ elseif "linux-ppc64le-clang" == _OPTIONS["gcc"] then
+ premake.gcc.cc = "clang"
+ premake.gcc.cxx = "clang++"
+ premake.gcc.ar = "ar"
+ premake.gcc.llvm = true
+ location (path.join(_buildDir, "projects", _ACTION .. "-linux-ppc64le-clang"))
elseif "mingw-gcc" == _OPTIONS["gcc"] then
if not os.getenv("MINGW") then
@@ -350,7 +343,9 @@ function toolchain(_buildDir, _libDir)
elseif "netbsd" == _OPTIONS["gcc"] then
location (path.join(_buildDir, "projects", _ACTION .. "-netbsd"))
- elseif "osx" == _OPTIONS["gcc"] then
+ elseif "osx-x64" == _OPTIONS["gcc"]
+ or "osx-arm64" == _OPTIONS["gcc"] then
+
if os.is("linux") then
if not os.getenv("OSXCROSS") then
@@ -362,7 +357,8 @@ function toolchain(_buildDir, _libDir)
premake.gcc.cxx = "$(OSXCROSS)/target/bin/" .. osxToolchain .. "clang++"
premake.gcc.ar = "$(OSXCROSS)/target/bin/" .. osxToolchain .. "ar"
end
- location (path.join(_buildDir, "projects", _ACTION .. "-osx"))
+
+ location (path.join(_buildDir, "projects", _ACTION .. "-" .. _OPTIONS["gcc"]))
elseif "orbis" == _OPTIONS["gcc"] then
@@ -387,21 +383,20 @@ function toolchain(_buildDir, _libDir)
location (path.join(_buildDir, "projects", _ACTION .. "-riscv"))
end
- elseif _ACTION == "vs2012"
- or _ACTION == "vs2013"
- or _ACTION == "vs2015"
- or _ACTION == "vs2017"
+ elseif _ACTION == "vs2017"
+ or _ACTION == "vs2019"
+ or _ACTION == "vs2022"
then
local action = premake.action.current()
- action.vstudio.windowsTargetPlatformVersion = windowsPlatform
- action.vstudio.windowsTargetPlatformMinVersion = windowsPlatform
+ if nil ~= windowsPlatform then
+ action.vstudio.windowsTargetPlatformVersion = windowsPlatform
+ action.vstudio.windowsTargetPlatformMinVersion = windowsPlatform
+ end
if (_ACTION .. "-clang") == _OPTIONS["vs"] then
if "vs2017-clang" == _OPTIONS["vs"] then
premake.vstudio.toolset = "v141_clang_c2"
- elseif "vs2015-clang" == _OPTIONS["vs"] then
- premake.vstudio.toolset = "LLVM-vs2014"
else
premake.vstudio.toolset = ("LLVM-" .. _ACTION)
end
@@ -432,27 +427,9 @@ function toolchain(_buildDir, _libDir)
platforms { "Orbis" }
location (path.join(_buildDir, "projects", _ACTION .. "-orbis"))
- elseif ("vs2012-xp") == _OPTIONS["vs"] then
- premake.vstudio.toolset = ("v110_xp")
- location (path.join(_buildDir, "projects", _ACTION .. "-xp"))
-
- elseif "vs2013-xp" == _OPTIONS["vs"] then
- premake.vstudio.toolset = ("v120_xp")
- location (path.join(_buildDir, "projects", _ACTION .. "-xp"))
-
- elseif "vs2015-xp" == _OPTIONS["vs"] then
- premake.vstudio.toolset = ("v140_xp")
- location (path.join(_buildDir, "projects", _ACTION .. "-xp"))
-
- elseif "vs2015-xp" == _OPTIONS["vs"] then
- premake.vstudio.toolset = ("v141_xp")
- location (path.join(_buildDir, "projects", _ACTION .. "-xp"))
-
end
- elseif _ACTION == "xcode4"
- or _ACTION == "xcode8"
- or _ACTION == "xcode9" then
+ elseif _ACTION and _ACTION:match("^xcode.+$") then
local action = premake.action.current()
local str_or = function(str, def)
return #str > 0 and str or def
@@ -519,9 +496,9 @@ function toolchain(_buildDir, _libDir)
}
targetsuffix "Release"
- configuration { "qbs" }
- flags {
- "ExtraWarnings",
+ configuration { "*-clang" }
+ buildoptions {
+ "-Wno-tautological-constant-compare",
}
configuration { "vs*", "x32" }
@@ -535,8 +512,6 @@ function toolchain(_buildDir, _libDir)
"WIN32",
"_WIN32",
"_HAS_EXCEPTIONS=0",
- "_HAS_ITERATOR_DEBUGGING=0",
- "_ITERATOR_DEBUG_LEVEL=0",
"_SCL_SECURE=0",
"_SECURE_SCL=0",
"_SCL_SECURE_NO_WARNINGS",
@@ -547,14 +522,12 @@ function toolchain(_buildDir, _libDir)
"/wd4201", -- warning C4201: nonstandard extension used: nameless struct/union
"/wd4324", -- warning C4324: '': structure was padded due to alignment specifier
"/Ob2", -- The Inline Function Expansion
+ "/Zc:__cplusplus", -- Enable updated __cplusplus macro
}
linkoptions {
"/ignore:4221", -- LNK4221: This object file does not define any previously undefined public symbols, so it will not be used by any link operation that consumes this library
}
- configuration { "vs2008" }
- includedirs { path.join(bxDir, "include/compat/msvc/pre1600") }
-
configuration { "x32", "vs*" }
targetdir (path.join(_buildDir, "win32_" .. _ACTION, "bin"))
objdir (path.join(_buildDir, "win32_" .. _ACTION, "obj"))
@@ -633,9 +606,6 @@ function toolchain(_buildDir, _libDir)
"-Wunused-value",
"-Wundef",
}
- buildoptions_cpp {
- "-std=c++14",
- }
linkoptions {
"-Wl,--gc-sections",
"-static",
@@ -664,9 +634,9 @@ function toolchain(_buildDir, _libDir)
configuration { "mingw-clang" }
buildoptions {
- "-isystem$(MINGW)/lib/gcc/x86_64-w64-mingw32/4.8.1/include/c++",
- "-isystem$(MINGW)/lib/gcc/x86_64-w64-mingw32/4.8.1/include/c++/x86_64-w64-mingw32",
- "-isystem$(MINGW)/x86_64-w64-mingw32/include",
+ "-isystem $(MINGW)/lib/gcc/x86_64-w64-mingw32/4.8.1/include/c++",
+ "-isystem $(MINGW)/lib/gcc/x86_64-w64-mingw32/4.8.1/include/c++/x86_64-w64-mingw32",
+ "-isystem $(MINGW)/x86_64-w64-mingw32/include",
}
linkoptions {
"-Qunused-arguments",
@@ -689,20 +659,8 @@ function toolchain(_buildDir, _libDir)
}
buildoptions { "-m64" }
- configuration { "linux-clang" }
-
- configuration { "linux-gcc-6" }
- buildoptions {
--- "-fno-omit-frame-pointer",
--- "-fsanitize=address",
--- "-fsanitize=undefined",
--- "-fsanitize=float-divide-by-zero",
--- "-fsanitize=float-cast-overflow",
- }
- links {
--- "asan",
--- "ubsan",
- }
+ configuration { "linux-*" }
+ includedirs { path.join(bxDir, "include/compat/linux") }
configuration { "linux-gcc" }
buildoptions {
@@ -722,9 +680,6 @@ function toolchain(_buildDir, _libDir)
"-Wundef",
-- "-Wuseless-cast",
}
- buildoptions_cpp {
- "-std=c++14",
- }
links {
"rt",
"dl",
@@ -771,25 +726,6 @@ function toolchain(_buildDir, _libDir)
"-m64",
}
- configuration { "linux-mips-gcc" }
- targetdir (path.join(_buildDir, "linux32_mips_gcc/bin"))
- objdir (path.join(_buildDir, "linux32_mips_gcc/obj"))
- libdirs { path.join(_libDir, "lib/linux32_mips_gcc") }
- buildoptions {
- "-Wunused-value",
- "-Wundef",
- }
- buildoptions_cpp {
- "-std=c++14",
- }
- links {
- "rt",
- "dl",
- }
- linkoptions {
- "-Wl,--gc-sections",
- }
-
configuration { "linux-arm-gcc" }
targetdir (path.join(_buildDir, "linux32_arm_gcc/bin"))
objdir (path.join(_buildDir, "linux32_arm_gcc/obj"))
@@ -798,9 +734,6 @@ function toolchain(_buildDir, _libDir)
"-Wunused-value",
"-Wundef",
}
- buildoptions_cpp {
- "-std=c++14",
- }
links {
"rt",
"dl",
@@ -814,14 +747,6 @@ function toolchain(_buildDir, _libDir)
flags {
"NoImportLib",
}
- includedirs {
- "$(ANDROID_NDK_ROOT)/sources/cxx-stl/llvm-libc++/include",
- "${ANDROID_NDK_ROOT}/sysroot/usr/include",
- "$(ANDROID_NDK_ROOT)/sources/android/native_app_glue",
- }
- linkoptions {
- "-nostdlib",
- }
links {
"c",
"dl",
@@ -829,9 +754,11 @@ function toolchain(_buildDir, _libDir)
"android",
"log",
"c++_shared",
- "gcc",
}
buildoptions {
+ "--gcc-toolchain=" .. androidToolchainRoot(),
+ "--sysroot=" .. androidToolchainRoot() .. "/sysroot",
+ "-DANDROID",
"-fPIC",
"-no-canonical-prefixes",
"-Wa,--noexecstack",
@@ -840,10 +767,9 @@ function toolchain(_buildDir, _libDir)
"-Wunused-value",
"-Wundef",
}
- buildoptions_cpp {
- "-std=c++14",
- }
linkoptions {
+ "--gcc-toolchain=" .. androidToolchainRoot(),
+ "--sysroot=" .. androidToolchainRoot() .. "/sysroot",
"-no-canonical-prefixes",
"-Wl,--no-undefined",
"-Wl,-z,noexecstack",
@@ -851,103 +777,102 @@ function toolchain(_buildDir, _libDir)
"-Wl,-z,now",
}
- configuration { "linux-steamlink" }
- targetdir (path.join(_buildDir, "steamlink/bin"))
- objdir (path.join(_buildDir, "steamlink/obj"))
- libdirs { path.join(_libDir, "lib/steamlink") }
- includedirs { path.join(bxDir, "include/compat/linux") }
- defines {
- "__STEAMLINK__=1", -- There is no special prefedined compiler symbol to detect SteamLink, faking it.
- }
- buildoptions {
- "-std=c++14",
- "-Wfatal-errors",
- "-Wunused-value",
- "-Wundef",
- "-pthread",
- "-marm",
- "-mfloat-abi=hard",
- "--sysroot=$(MARVELL_SDK_PATH)/rootfs",
- }
- linkoptions {
- "-static-libgcc",
- "-static-libstdc++",
- "--sysroot=$(MARVELL_SDK_PATH)/rootfs",
- }
-
configuration { "android-arm" }
targetdir (path.join(_buildDir, "android-arm/bin"))
objdir (path.join(_buildDir, "android-arm/obj"))
- libdirs {
- "$(ANDROID_NDK_ROOT)/sources/cxx-stl/llvm-libc++/libs/armeabi-v7a",
- }
- includedirs {
- "$(ANDROID_NDK_ROOT)/sysroot/usr/include/arm-linux-androideabi",
- }
buildoptions {
- "-gcc-toolchain $(ANDROID_NDK_ARM)",
- "--sysroot=" .. path.join("$(ANDROID_NDK_ROOT)/platforms", androidPlatform, "arch-arm"),
- "-target armv7-none-linux-androideabi",
+ "--target=armv7-none-linux-android" .. androidApiLevel,
"-mthumb",
"-march=armv7-a",
"-mfloat-abi=softfp",
"-mfpu=neon",
- "-Wunused-value",
- "-Wundef",
}
linkoptions {
- "-gcc-toolchain $(ANDROID_NDK_ARM)",
- "--sysroot=" .. path.join("$(ANDROID_NDK_ROOT)/platforms", androidPlatform, "arch-arm"),
- path.join("$(ANDROID_NDK_ROOT)/platforms", androidPlatform, "arch-arm/usr/lib/crtbegin_so.o"),
- path.join("$(ANDROID_NDK_ROOT)/platforms", androidPlatform, "arch-arm/usr/lib/crtend_so.o"),
- "-target armv7-none-linux-androideabi",
+ "--target=armv7-none-linux-android" .. androidApiLevel,
"-march=armv7-a",
- "-Wl,--fix-cortex-a8",
+ }
+
+ configuration { "android-arm64" }
+ targetdir (path.join(_buildDir, "android-arm64/bin"))
+ objdir (path.join(_buildDir, "android-arm64/obj"))
+ buildoptions {
+ "--target=aarch64-none-linux-android" .. androidApiLevel,
+ }
+ linkoptions {
+ "--target=aarch64-none-linux-android" .. androidApiLevel,
}
configuration { "android-x86" }
targetdir (path.join(_buildDir, "android-x86/bin"))
objdir (path.join(_buildDir, "android-x86/obj"))
- libdirs {
- "$(ANDROID_NDK_ROOT)/sources/cxx-stl/llvm-libc++/libs/x86",
- }
- includedirs {
- "$(ANDROID_NDK_ROOT)/sysroot/usr/include/x86_64-linux-android",
- }
buildoptions {
- "-gcc-toolchain $(ANDROID_NDK_X86)",
- "--sysroot=" .. path.join("$(ANDROID_NDK_ROOT)/platforms", androidPlatform, "arch-x86"),
- "-target i686-none-linux-android",
- "-march=i686",
+ "--target=i686-none-linux-android" .. androidApiLevel,
"-mtune=atom",
"-mstackrealign",
"-msse3",
"-mfpmath=sse",
+ }
+ linkoptions {
+ "--target=i686-none-linux-android" .. androidApiLevel,
+ }
+
+ configuration { "android-x86_64" }
+ targetdir (path.join(_buildDir, "android-x86_64/bin"))
+ objdir (path.join(_buildDir, "android-x86_64/obj"))
+ buildoptions {
+ "--target=x86_64-none-linux-android" .. androidApiLevel,
+ }
+ linkoptions {
+ "--target=x86_64-none-linux-android" .. androidApiLevel,
+ }
+
+ configuration { "wasm*" }
+ buildoptions {
"-Wunused-value",
"-Wundef",
}
+
linkoptions {
- "-gcc-toolchain $(ANDROID_NDK_X86)",
- "--sysroot=" .. path.join("$(ANDROID_NDK_ROOT)/platforms", androidPlatform, "arch-x86"),
- path.join("$(ANDROID_NDK_ROOT)/platforms", androidPlatform, "arch-x86/usr/lib/crtbegin_so.o"),
- path.join("$(ANDROID_NDK_ROOT)/platforms", androidPlatform, "arch-x86/usr/lib/crtend_so.o"),
- "-target i686-none-linux-android",
+ "-s MAX_WEBGL_VERSION=2",
}
- configuration { "asmjs" }
- targetdir (path.join(_buildDir, "asmjs/bin"))
- objdir (path.join(_buildDir, "asmjs/obj"))
- libdirs { path.join(_libDir, "lib/asmjs") }
+ configuration { "linux-ppc64le*" }
buildoptions {
- "-i\"system$(EMSCRIPTEN)/system/include\"",
- "-i\"system$(EMSCRIPTEN)/system/include/libcxx\"",
- "-i\"system$(EMSCRIPTEN)/system/include/libc\"",
+ "-fsigned-char",
"-Wunused-value",
"-Wundef",
+ "-mcpu=power8",
}
- buildoptions_cpp {
- "-std=c++14",
+ links {
+ "rt",
+ "dl",
}
+ linkoptions {
+ "-Wl,--gc-sections",
+ }
+
+ configuration { "linux-ppc64le-gcc" }
+ targetdir (path.join(_buildDir, "linux_ppc64le_gcc/bin"))
+ objdir (path.join(_buildDir, "linux_ppc64le_gcc/obj"))
+ libdirs { path.join(_libDir, "lib/linux_ppc64le_gcc") }
+
+ configuration { "linux-ppc64le-clang" }
+ targetdir (path.join(_buildDir, "linux_ppc64le_clang/bin"))
+ objdir (path.join(_buildDir, "linux_ppc64le_clang/obj"))
+ libdirs { path.join(_libDir, "lib/linux_ppc64le_clang") }
+
+ configuration { "wasm2js" }
+ targetdir (path.join(_buildDir, "wasm2js/bin"))
+ objdir (path.join(_buildDir, "wasm2js/obj"))
+ libdirs { path.join(_libDir, "lib/wasm2js") }
+ linkoptions {
+ "-s WASM=0",
+ }
+
+ configuration { "wasm" }
+ targetdir (path.join(_buildDir, "wasm/bin"))
+ objdir (path.join(_buildDir, "wasm/obj"))
+ libdirs { path.join(_libDir, "lib/wasm") }
configuration { "freebsd" }
targetdir (path.join(_buildDir, "freebsd/bin"))
@@ -984,36 +909,33 @@ function toolchain(_buildDir, _libDir)
path.join(bxDir, "include/compat/freebsd"),
}
- configuration { "osx", "x32" }
- targetdir (path.join(_buildDir, "osx32_clang/bin"))
- objdir (path.join(_buildDir, "osx32_clang/obj"))
- --libdirs { path.join(_libDir, "lib/osx32_clang") }
- buildoptions {
- "-m32",
+ configuration { "osx-x64" }
+ targetdir (path.join(_buildDir, "osx-x64/bin"))
+ objdir (path.join(_buildDir, "osx-x64/obj"))
+ linkoptions {
+ "-arch x86_64",
}
-
- configuration { "osx", "x64" }
- targetdir (path.join(_buildDir, "osx64_clang/bin"))
- objdir (path.join(_buildDir, "osx64_clang/obj"))
- --libdirs { path.join(_libDir, "lib/osx64_clang") }
buildoptions {
- "-m64",
+ "-arch x86_64",
+ "-msse2",
+ "-target x86_64-apple-macos" .. (#macosPlatform > 0 and macosPlatform or "10.11"),
}
- configuration { "osx", "Universal" }
- targetdir (path.join(_buildDir, "osx_universal/bin"))
- objdir (path.join(_buildDir, "osx_universal/bin"))
-
- configuration { "osx" }
- buildoptions_cpp {
- "-std=c++14",
+ configuration { "osx-arm64" }
+ targetdir (path.join(_buildDir, "osx-arm64/bin"))
+ objdir (path.join(_buildDir, "osx-arm64/obj"))
+ linkoptions {
+ "-arch arm64",
}
- buildoptions_objcpp {
- "-std=c++14",
+ buildoptions {
+ "-arch arm64",
+ "-Wno-error=unused-command-line-argument",
+ "-Wno-unused-command-line-argument",
}
+
+ configuration { "osx*" }
buildoptions {
"-Wfatal-errors",
- "-msse2",
"-Wunused-value",
"-Wundef",
}
@@ -1023,12 +945,6 @@ function toolchain(_buildDir, _libDir)
linkoptions {
"-lc++",
}
- buildoptions_cpp {
- "-std=c++14",
- }
- buildoptions_objcpp {
- "-std=c++14",
- }
buildoptions {
"-Wfatal-errors",
"-Wunused-value",
@@ -1064,15 +980,16 @@ function toolchain(_buildDir, _libDir)
configuration { "ios-arm*" }
linkoptions {
- "-miphoneos-version-min=7.0",
+ "-miphoneos-version-min=9.0",
"--sysroot=/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS" ..iosPlatform .. ".sdk",
"-L/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS" ..iosPlatform .. ".sdk/usr/lib/system",
"-F/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS" ..iosPlatform .. ".sdk/System/Library/Frameworks",
"-F/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS" ..iosPlatform .. ".sdk/System/Library/PrivateFrameworks",
}
buildoptions {
- "-miphoneos-version-min=7.0",
+ "-miphoneos-version-min=9.0",
"--sysroot=/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS" ..iosPlatform .. ".sdk",
+ "-fembed-bitcode",
}
configuration { "ios-simulator" }
@@ -1080,7 +997,7 @@ function toolchain(_buildDir, _libDir)
objdir (path.join(_buildDir, "ios-simulator/obj"))
libdirs { path.join(_libDir, "lib/ios-simulator") }
linkoptions {
- "-mios-simulator-version-min=7.0",
+ "-mios-simulator-version-min=9.0",
"-arch i386",
"--sysroot=/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator" ..iosPlatform .. ".sdk",
"-L/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator" ..iosPlatform .. ".sdk/usr/lib/system",
@@ -1088,7 +1005,7 @@ function toolchain(_buildDir, _libDir)
"-F/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator" ..iosPlatform .. ".sdk/System/Library/PrivateFrameworks",
}
buildoptions {
- "-mios-simulator-version-min=7.0",
+ "-mios-simulator-version-min=9.0",
"-arch i386",
"--sysroot=/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator" ..iosPlatform .. ".sdk",
}
@@ -1098,7 +1015,7 @@ function toolchain(_buildDir, _libDir)
objdir (path.join(_buildDir, "ios-simulator64/obj"))
libdirs { path.join(_libDir, "lib/ios-simulator64") }
linkoptions {
- "-mios-simulator-version-min=7.0",
+ "-mios-simulator-version-min=9.0",
"-arch x86_64",
"--sysroot=/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator" ..iosPlatform .. ".sdk",
"-L/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator" ..iosPlatform .. ".sdk/usr/lib/system",
@@ -1106,7 +1023,7 @@ function toolchain(_buildDir, _libDir)
"-F/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator" ..iosPlatform .. ".sdk/System/Library/PrivateFrameworks",
}
buildoptions {
- "-mios-simulator-version-min=7.0",
+ "-mios-simulator-version-min=9.0",
"-arch x86_64",
"--sysroot=/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator" ..iosPlatform .. ".sdk",
}
@@ -1171,9 +1088,6 @@ function toolchain(_buildDir, _libDir)
"$(SCE_ORBIS_SDK_DIR)/target/include",
"$(SCE_ORBIS_SDK_DIR)/target/include_common",
}
- buildoptions_cpp {
- "-std=c++14",
- }
configuration { "rpi" }
targetdir (path.join(_buildDir, "rpi/bin"))
@@ -1190,9 +1104,6 @@ function toolchain(_buildDir, _libDir)
"-Wunused-value",
"-Wundef",
}
- buildoptions_cpp {
- "-std=c++14",
- }
includedirs {
"/opt/vc/include",
"/opt/vc/include/interface/vcos/pthreads",
@@ -1222,9 +1133,6 @@ function toolchain(_buildDir, _libDir)
"-Wundef",
"--sysroot=$(FREEDOM_E_SDK)/work/build/riscv-gnu-toolchain/riscv64-unknown-elf/prefix/riscv64-unknown-elf",
}
- buildoptions_cpp {
- "-std=c++14",
- }
configuration {} -- reset configuration
@@ -1233,25 +1141,13 @@ end
function strip()
- configuration { "android-arm", "Release" }
- postbuildcommands {
- "$(SILENT) echo Stripping symbols.",
- "$(SILENT) $(ANDROID_NDK_ARM)/bin/arm-linux-androideabi-strip -s \"$(TARGET)\""
- }
-
- configuration { "android-x86", "Release" }
+ configuration { "android-*", "Release" }
postbuildcommands {
"$(SILENT) echo Stripping symbols.",
- "$(SILENT) $(ANDROID_NDK_X86)/bin/i686-linux-android-strip -s \"$(TARGET)\""
+ "$(SILENT) " .. androidToolchainRoot() .. "/bin/llvm-strip -s \"$(TARGET)\""
}
- configuration { "linux-steamlink", "Release" }
- postbuildcommands {
- "$(SILENT) echo Stripping symbols.",
- "$(SILENT) $(MARVELL_SDK_PATH)/toolchain/bin/armv7a-cros-linux-gnueabi-strip -s \"$(TARGET)\""
- }
-
- configuration { "linux-* or rpi", "not linux-steamlink", "Release" }
+ configuration { "linux-* or rpi", "Release" }
postbuildcommands {
"$(SILENT) echo Stripping symbols.",
"$(SILENT) strip -s \"$(TARGET)\""
@@ -1263,24 +1159,6 @@ function strip()
"$(SILENT) $(MINGW)/bin/strip -s \"$(TARGET)\""
}
- configuration { "asmjs" }
- postbuildcommands {
- "$(SILENT) echo Running asmjs finalize.",
- "$(SILENT) \"$(EMSCRIPTEN)/emcc\" -O2 "
-
--- .. "-s ALLOW_MEMORY_GROWTH=1 "
--- .. "-s ASSERTIONS=2 "
--- .. "-s EMTERPRETIFY=1 "
--- .. "-s EMTERPRETIFY_ASYNC=1 "
- .. "-s PRECISE_F32=1 "
- .. "-s TOTAL_MEMORY=268435456 "
--- .. "-s USE_WEBGL2=1 "
-
- .. "--memory-init-file 1 "
- .. "\"$(TARGET)\" -o \"$(TARGET)\".html "
--- .. "--preload-file ../../../examples/runtime@/ "
- }
-
configuration { "riscv" }
postbuildcommands {
"$(SILENT) echo Stripping symbols.",
diff --git a/3rdparty/bx/src/allocator.cpp b/3rdparty/bx/src/allocator.cpp
index c26677edb25..203631f6009 100644
--- a/3rdparty/bx/src/allocator.cpp
+++ b/3rdparty/bx/src/allocator.cpp
@@ -1,9 +1,8 @@
/*
- * Copyright 2010-2018 Branimir Karadzic. All rights reserved.
- * License: https://github.com/bkaradzic/bx#license-bsd-2-clause
+ * Copyright 2010-2022 Branimir Karadzic. All rights reserved.
+ * License: https://github.com/bkaradzic/bx/blob/master/LICENSE
*/
-#include "bx_p.h"
#include <bx/allocator.h>
#include <malloc.h>
@@ -38,7 +37,7 @@ namespace bx
BX_UNUSED(_file, _line);
_aligned_free(_ptr);
# else
- bx::alignedFree(this, _ptr, _align, _file, _line);
+ alignedFree(this, _ptr, _align, _file, _line);
# endif // BX_
}
@@ -55,7 +54,7 @@ namespace bx
BX_UNUSED(_file, _line);
return _aligned_malloc(_size, _align);
# else
- return bx::alignedAlloc(this, _size, _align, _file, _line);
+ return alignedAlloc(this, _size, _align, _file, _line);
# endif // BX_
}
@@ -68,7 +67,7 @@ namespace bx
BX_UNUSED(_file, _line);
return _aligned_realloc(_ptr, _size, _align);
# else
- return bx::alignedRealloc(this, _ptr, _size, _align, _file, _line);
+ return alignedRealloc(this, _ptr, _size, _align, _file, _line);
# endif // BX_
}
diff --git a/3rdparty/bx/src/amalgamated.cpp b/3rdparty/bx/src/amalgamated.cpp
index d3f896b1416..037418a5717 100644
--- a/3rdparty/bx/src/amalgamated.cpp
+++ b/3rdparty/bx/src/amalgamated.cpp
@@ -1,9 +1,10 @@
/*
- * Copyright 2011-2018 Branimir Karadzic. All rights reserved.
- * License: https://github.com/bkaradzic/bx#license-bsd-2-clause
+ * Copyright 2011-2022 Branimir Karadzic. All rights reserved.
+ * License: https://github.com/bkaradzic/bx/blob/master/LICENSE
*/
#include "allocator.cpp"
+#include "bounds.cpp"
#include "bx.cpp"
#include "commandline.cpp"
#include "crtnone.cpp"
diff --git a/3rdparty/bx/src/bounds.cpp b/3rdparty/bx/src/bounds.cpp
new file mode 100644
index 00000000000..d7068fe42b0
--- /dev/null
+++ b/3rdparty/bx/src/bounds.cpp
@@ -0,0 +1,2039 @@
+/*
+ * Copyright 2011-2022 Branimir Karadzic. All rights reserved.
+ * License: https://github.com/bkaradzic/bgfx#license-bsd-2-clause
+ */
+
+#include <bx/rng.h>
+#include <bx/math.h>
+#include <bx/bounds.h>
+
+namespace bx
+{
+ Vec3 getCenter(const Aabb& _aabb)
+ {
+ return mul(add(_aabb.min, _aabb.max), 0.5f);
+ }
+
+ Vec3 getExtents(const Aabb& _aabb)
+ {
+ return mul(sub(_aabb.max, _aabb.min), 0.5f);
+ }
+
+ Vec3 getCenter(const Triangle& _triangle)
+ {
+ return mul(add(add(_triangle.v0, _triangle.v1), _triangle.v2), 1.0f/3.0f);
+ }
+
+ void toAabb(Aabb& _outAabb, const Vec3& _extents)
+ {
+ _outAabb.min = neg(_extents);
+ _outAabb.max = _extents;
+ }
+
+ void toAabb(Aabb& _outAabb, const Vec3& _center, const Vec3& _extents)
+ {
+ _outAabb.min = sub(_center, _extents);
+ _outAabb.max = add(_center, _extents);
+ }
+
+ void toAabb(Aabb& _outAabb, const Cylinder& _cylinder)
+ {
+ // Reference(s):
+ // - https://web.archive.org/web/20181113055756/http://iquilezles.org/www/articles/diskbbox/diskbbox.htm
+ //
+ const Vec3 axis = sub(_cylinder.end, _cylinder.pos);
+ const Vec3 asq = mul(axis, axis);
+ const Vec3 nsq = mul(asq, 1.0f/dot(axis, axis) );
+ const Vec3 tmp = sub(Vec3(1.0f), nsq);
+
+ const float inv = 1.0f/(tmp.x*tmp.y*tmp.z);
+
+ const Vec3 extent =
+ {
+ _cylinder.radius * tmp.x * sqrt( (nsq.x + nsq.y * nsq.z) * inv),
+ _cylinder.radius * tmp.y * sqrt( (nsq.y + nsq.z * nsq.x) * inv),
+ _cylinder.radius * tmp.z * sqrt( (nsq.z + nsq.x * nsq.y) * inv),
+ };
+
+ const Vec3 minP = sub(_cylinder.pos, extent);
+ const Vec3 minE = sub(_cylinder.end, extent);
+ const Vec3 maxP = add(_cylinder.pos, extent);
+ const Vec3 maxE = add(_cylinder.end, extent);
+
+ _outAabb.min = min(minP, minE);
+ _outAabb.max = max(maxP, maxE);
+ }
+
+ void toAabb(Aabb& _outAabb, const Disk& _disk)
+ {
+ // Reference(s):
+ // - https://web.archive.org/web/20181113055756/http://iquilezles.org/www/articles/diskbbox/diskbbox.htm
+ //
+ const Vec3 nsq = mul(_disk.normal, _disk.normal);
+ const Vec3 one = { 1.0f, 1.0f, 1.0f };
+ const Vec3 tmp = sub(one, nsq);
+ const float inv = 1.0f / (tmp.x*tmp.y*tmp.z);
+
+ const Vec3 extent =
+ {
+ _disk.radius * tmp.x * sqrt( (nsq.x + nsq.y * nsq.z) * inv),
+ _disk.radius * tmp.y * sqrt( (nsq.y + nsq.z * nsq.x) * inv),
+ _disk.radius * tmp.z * sqrt( (nsq.z + nsq.x * nsq.y) * inv),
+ };
+
+ _outAabb.min = sub(_disk.center, extent);
+ _outAabb.max = add(_disk.center, extent);
+ }
+
+ void toAabb(Aabb& _outAabb, const Obb& _obb)
+ {
+ Vec3 xyz = { 1.0f, 1.0f, 1.0f };
+ Vec3 tmp = mul(xyz, _obb.mtx);
+
+ _outAabb.min = tmp;
+ _outAabb.max = tmp;
+
+ for (uint32_t ii = 1; ii < 8; ++ii)
+ {
+ xyz.x = ii & 1 ? -1.0f : 1.0f;
+ xyz.y = ii & 2 ? -1.0f : 1.0f;
+ xyz.z = ii & 4 ? -1.0f : 1.0f;
+ tmp = mul(xyz, _obb.mtx);
+
+ _outAabb.min = min(_outAabb.min, tmp);
+ _outAabb.max = max(_outAabb.max, tmp);
+ }
+ }
+
+ void toAabb(Aabb& _outAabb, const Sphere& _sphere)
+ {
+ const float radius = _sphere.radius;
+ _outAabb.min = sub(_sphere.center, radius);
+ _outAabb.max = add(_sphere.center, radius);
+ }
+
+ void toAabb(Aabb& _outAabb, const Triangle& _triangle)
+ {
+ _outAabb.min = min(_triangle.v0, _triangle.v1, _triangle.v2);
+ _outAabb.max = max(_triangle.v0, _triangle.v1, _triangle.v2);
+ }
+
+ void aabbTransformToObb(Obb& _obb, const Aabb& _aabb, const float* _mtx)
+ {
+ toObb(_obb, _aabb);
+ float result[16];
+ mtxMul(result, _obb.mtx, _mtx);
+ memCopy(_obb.mtx, result, sizeof(result) );
+ }
+
+ void toAabb(Aabb& _outAabb, const void* _vertices, uint32_t _numVertices, uint32_t _stride)
+ {
+ Vec3 mn(init::None);
+ Vec3 mx(init::None);
+ uint8_t* vertex = (uint8_t*)_vertices;
+
+ mn = mx = load<Vec3>(vertex);
+ vertex += _stride;
+
+ for (uint32_t ii = 1; ii < _numVertices; ++ii)
+ {
+ const Vec3 pos = load<Vec3>(vertex);
+ vertex += _stride;
+
+ mn = min(pos, mn);
+ mx = max(pos, mx);
+ }
+
+ _outAabb.min = mn;
+ _outAabb.max = mx;
+ }
+
+ void toAabb(Aabb& _outAabb, const float* _mtx, const void* _vertices, uint32_t _numVertices, uint32_t _stride)
+ {
+ Vec3 mn(init::None);
+ Vec3 mx(init::None);
+ uint8_t* vertex = (uint8_t*)_vertices;
+ mn = mx = mul(load<Vec3>(vertex), _mtx);
+
+ vertex += _stride;
+
+ for (uint32_t ii = 1; ii < _numVertices; ++ii)
+ {
+ Vec3 pos = mul(load<Vec3>(vertex), _mtx);
+ vertex += _stride;
+
+ mn = min(pos, mn);
+ mx = max(pos, mx);
+ }
+
+ _outAabb.min = mn;
+ _outAabb.max = mx;
+ }
+
+ float calcAreaAabb(const Aabb& _aabb)
+ {
+ const float ww = _aabb.max.x - _aabb.min.x;
+ const float hh = _aabb.max.y - _aabb.min.y;
+ const float dd = _aabb.max.z - _aabb.min.z;
+ return 2.0f * (ww*hh + ww*dd + hh*dd);
+ }
+
+ void aabbExpand(Aabb& _outAabb, float _factor)
+ {
+ _outAabb.min.x -= _factor;
+ _outAabb.min.y -= _factor;
+ _outAabb.min.z -= _factor;
+ _outAabb.max.x += _factor;
+ _outAabb.max.y += _factor;
+ _outAabb.max.z += _factor;
+ }
+
+ void aabbExpand(Aabb& _outAabb, const Vec3& _pos)
+ {
+ _outAabb.min = min(_outAabb.min, _pos);
+ _outAabb.max = max(_outAabb.max, _pos);
+ }
+
+ void toObb(Obb& _outObb, const Aabb& _aabb)
+ {
+ memSet(_outObb.mtx, 0, sizeof(_outObb.mtx) );
+ _outObb.mtx[ 0] = (_aabb.max.x - _aabb.min.x) * 0.5f;
+ _outObb.mtx[ 5] = (_aabb.max.y - _aabb.min.y) * 0.5f;
+ _outObb.mtx[10] = (_aabb.max.z - _aabb.min.z) * 0.5f;
+ _outObb.mtx[12] = (_aabb.min.x + _aabb.max.x) * 0.5f;
+ _outObb.mtx[13] = (_aabb.min.y + _aabb.max.y) * 0.5f;
+ _outObb.mtx[14] = (_aabb.min.z + _aabb.max.z) * 0.5f;
+ _outObb.mtx[15] = 1.0f;
+ }
+
+ void calcObb(Obb& _outObb, const void* _vertices, uint32_t _numVertices, uint32_t _stride, uint32_t _steps)
+ {
+ Aabb aabb;
+ toAabb(aabb, _vertices, _numVertices, _stride);
+ float minArea = calcAreaAabb(aabb);
+
+ Obb best;
+ toObb(best, aabb);
+
+ float angleStep = float(kPiHalf/_steps);
+ float ax = 0.0f;
+ float mtx[16];
+
+ for (uint32_t ii = 0; ii < _steps; ++ii)
+ {
+ float ay = 0.0f;
+
+ for (uint32_t jj = 0; jj < _steps; ++jj)
+ {
+ float az = 0.0f;
+
+ for (uint32_t kk = 0; kk < _steps; ++kk)
+ {
+ mtxRotateXYZ(mtx, ax, ay, az);
+
+ float mtxT[16];
+ mtxTranspose(mtxT, mtx);
+ toAabb(aabb, mtxT, _vertices, _numVertices, _stride);
+
+ float area = calcAreaAabb(aabb);
+ if (area < minArea)
+ {
+ minArea = area;
+ aabbTransformToObb(best, aabb, mtx);
+ }
+
+ az += angleStep;
+ }
+
+ ay += angleStep;
+ }
+
+ ax += angleStep;
+ }
+
+ memCopy(&_outObb, &best, sizeof(Obb) );
+ }
+
+ void calcMaxBoundingSphere(Sphere& _sphere, const void* _vertices, uint32_t _numVertices, uint32_t _stride)
+ {
+ Aabb aabb;
+ toAabb(aabb, _vertices, _numVertices, _stride);
+
+ Vec3 center = getCenter(aabb);
+
+ float maxDistSq = 0.0f;
+ uint8_t* vertex = (uint8_t*)_vertices;
+
+ for (uint32_t ii = 0; ii < _numVertices; ++ii)
+ {
+ const Vec3& pos = load<Vec3>(vertex);
+ vertex += _stride;
+
+ const Vec3 tmp = sub(pos, center);
+ const float distSq = dot(tmp, tmp);
+ maxDistSq = max(distSq, maxDistSq);
+ }
+
+ _sphere.center = center;
+ _sphere.radius = sqrt(maxDistSq);
+ }
+
+ void calcMinBoundingSphere(Sphere& _sphere, const void* _vertices, uint32_t _numVertices, uint32_t _stride, float _step)
+ {
+ RngMwc rng;
+
+ uint8_t* vertex = (uint8_t*)_vertices;
+
+ Vec3 center(init::None);
+ float* position = (float*)&vertex[0];
+ center.x = position[0];
+ center.y = position[1];
+ center.z = position[2];
+
+ position = (float*)&vertex[1*_stride];
+ center.x += position[0];
+ center.y += position[1];
+ center.z += position[2];
+
+ center.x *= 0.5f;
+ center.y *= 0.5f;
+ center.z *= 0.5f;
+
+ float xx = position[0] - center.x;
+ float yy = position[1] - center.y;
+ float zz = position[2] - center.z;
+ float maxDistSq = xx*xx + yy*yy + zz*zz;
+
+ float radiusStep = _step * 0.37f;
+
+ bool done;
+ do
+ {
+ done = true;
+ for (uint32_t ii = 0, index = rng.gen()%_numVertices; ii < _numVertices; ++ii, index = (index + 1)%_numVertices)
+ {
+ position = (float*)&vertex[index*_stride];
+
+ xx = position[0] - center.x;
+ yy = position[1] - center.y;
+ zz = position[2] - center.z;
+ float distSq = xx*xx + yy*yy + zz*zz;
+
+ if (distSq > maxDistSq)
+ {
+ done = false;
+
+ center.x += xx * radiusStep;
+ center.y += yy * radiusStep;
+ center.z += zz * radiusStep;
+ maxDistSq = lerp(maxDistSq, distSq, _step);
+
+ break;
+ }
+ }
+
+ } while (!done);
+
+ _sphere.center = center;
+ _sphere.radius = sqrt(maxDistSq);
+ }
+
+ void buildFrustumPlanes(Plane* _result, const float* _viewProj)
+ {
+ const float xw = _viewProj[ 3];
+ const float yw = _viewProj[ 7];
+ const float zw = _viewProj[11];
+ const float ww = _viewProj[15];
+
+ const float xz = _viewProj[ 2];
+ const float yz = _viewProj[ 6];
+ const float zz = _viewProj[10];
+ const float wz = _viewProj[14];
+
+ Plane& near = _result[0];
+ Plane& far = _result[1];
+ Plane& left = _result[2];
+ Plane& right = _result[3];
+ Plane& top = _result[4];
+ Plane& bottom = _result[5];
+
+ near.normal.x = xw - xz;
+ near.normal.y = yw - yz;
+ near.normal.z = zw - zz;
+ near.dist = ww - wz;
+
+ far.normal.x = xw + xz;
+ far.normal.y = yw + yz;
+ far.normal.z = zw + zz;
+ far.dist = ww + wz;
+
+ const float xx = _viewProj[ 0];
+ const float yx = _viewProj[ 4];
+ const float zx = _viewProj[ 8];
+ const float wx = _viewProj[12];
+
+ left.normal.x = xw - xx;
+ left.normal.y = yw - yx;
+ left.normal.z = zw - zx;
+ left.dist = ww - wx;
+
+ right.normal.x = xw + xx;
+ right.normal.y = yw + yx;
+ right.normal.z = zw + zx;
+ right.dist = ww + wx;
+
+ const float xy = _viewProj[ 1];
+ const float yy = _viewProj[ 5];
+ const float zy = _viewProj[ 9];
+ const float wy = _viewProj[13];
+
+ top.normal.x = xw + xy;
+ top.normal.y = yw + yy;
+ top.normal.z = zw + zy;
+ top.dist = ww + wy;
+
+ bottom.normal.x = xw - xy;
+ bottom.normal.y = yw - yy;
+ bottom.normal.z = zw - zy;
+ bottom.dist = ww - wy;
+
+ Plane* plane = _result;
+ for (uint32_t ii = 0; ii < 6; ++ii)
+ {
+ const float invLen = 1.0f/length(plane->normal);
+ plane->normal = normalize(plane->normal);
+ plane->dist *= invLen;
+ ++plane;
+ }
+ }
+
+ Ray makeRay(float _x, float _y, const float* _invVp)
+ {
+ Ray ray;
+
+ const Vec3 near = { _x, _y, 0.0f };
+ ray.pos = mulH(near, _invVp);
+
+ const Vec3 far = { _x, _y, 1.0f };
+ Vec3 tmp = mulH(far, _invVp);
+
+ const Vec3 dir = sub(tmp, ray.pos);
+ ray.dir = normalize(dir);
+
+ return ray;
+ }
+
+ bool intersect(const Ray& _ray, const Aabb& _aabb, Hit* _hit)
+ {
+ const Vec3 invDir = rcp(_ray.dir);
+ const Vec3 tmp0 = sub(_aabb.min, _ray.pos);
+ const Vec3 t0 = mul(tmp0, invDir);
+ const Vec3 tmp1 = sub(_aabb.max, _ray.pos);
+ const Vec3 t1 = mul(tmp1, invDir);
+
+ const Vec3 mn = min(t0, t1);
+ const Vec3 mx = max(t0, t1);
+
+ const float tmin = max(mn.x, mn.y, mn.z);
+ const float tmax = min(mx.x, mx.y, mx.z);
+
+ if (0.0f > tmax
+ || tmin > tmax)
+ {
+ return false;
+ }
+
+ if (NULL != _hit)
+ {
+ _hit->plane.normal.x = float( (t1.x == tmin) - (t0.x == tmin) );
+ _hit->plane.normal.y = float( (t1.y == tmin) - (t0.y == tmin) );
+ _hit->plane.normal.z = float( (t1.z == tmin) - (t0.z == tmin) );
+
+ _hit->plane.dist = tmin;
+ _hit->pos = getPointAt(_ray, tmin);
+ }
+
+ return true;
+ }
+
+ static constexpr Aabb kUnitAabb =
+ {
+ { -1.0f, -1.0f, -1.0f },
+ { 1.0f, 1.0f, 1.0f },
+ };
+
+ bool intersect(const Ray& _ray, const Obb& _obb, Hit* _hit)
+ {
+ Aabb aabb;
+ toAabb(aabb, _obb);
+
+ if (!intersect(_ray, aabb) )
+ {
+ return false;
+ }
+
+ float mtxInv[16];
+ mtxInverse(mtxInv, _obb.mtx);
+
+ Ray obbRay;
+ obbRay.pos = mul(_ray.pos, mtxInv);
+ obbRay.dir = mulXyz0(_ray.dir, mtxInv);
+
+ if (intersect(obbRay, kUnitAabb, _hit) )
+ {
+ if (NULL != _hit)
+ {
+ _hit->pos = mul(_hit->pos, _obb.mtx);
+
+ const Vec3 tmp = mulXyz0(_hit->plane.normal, _obb.mtx);
+ _hit->plane.normal = normalize(tmp);
+ }
+
+ return true;
+ }
+
+ return false;
+ }
+
+ bool intersect(const Ray& _ray, const Disk& _disk, Hit* _hit)
+ {
+ Plane plane(_disk.normal, -dot(_disk.center, _disk.normal) );
+
+ Hit tmpHit;
+ _hit = NULL != _hit ? _hit : &tmpHit;
+
+ if (intersect(_ray, plane, _hit) )
+ {
+ const Vec3 tmp = sub(_disk.center, _hit->pos);
+ return dot(tmp, tmp) <= square(_disk.radius);
+ }
+
+ return false;
+ }
+
+ static bool intersect(const Ray& _ray, const Cylinder& _cylinder, bool _capsule, Hit* _hit)
+ {
+ Vec3 axis = sub(_cylinder.end, _cylinder.pos);
+ const Vec3 rc = sub(_ray.pos, _cylinder.pos);
+ const Vec3 dxa = cross(_ray.dir, axis);
+
+ const float len = length(dxa);
+ const Vec3 normal = normalize(dxa);
+ const float dist = abs(dot(rc, normal) );
+
+ if (dist > _cylinder.radius)
+ {
+ return false;
+ }
+
+ Vec3 vo = cross(rc, axis);
+ const float t0 = -dot(vo, normal) / len;
+
+ vo = normalize(cross(normal, axis) );
+
+ const float rsq = square(_cylinder.radius);
+ const float ddoto = dot(_ray.dir, vo);
+ const float ss = t0 - abs(sqrt(rsq - square(dist) ) / ddoto);
+
+ if (0.0f > ss)
+ {
+ return false;
+ }
+
+ const Vec3 point = getPointAt(_ray, ss);
+
+ const float axisLen = length(axis);
+ axis = normalize(axis);
+ const float pdota = dot(_cylinder.pos, axis);
+ const float height = dot(point, axis) - pdota;
+
+ if (0.0f < height
+ && axisLen > height)
+ {
+ if (NULL != _hit)
+ {
+ const float t1 = height / axisLen;
+ const Vec3 pointOnAxis = lerp(_cylinder.pos, _cylinder.end, t1);
+
+ _hit->pos = point;
+
+ const Vec3 tmp = sub(point, pointOnAxis);
+ _hit->plane.normal = normalize(tmp);
+
+ _hit->plane.dist = ss;
+ }
+
+ return true;
+ }
+
+ if (_capsule)
+ {
+ const float rdota = dot(_ray.pos, axis);
+ const float pp = rdota - pdota;
+ const float t1 = pp / axisLen;
+
+ const Vec3 pointOnAxis = lerp(_cylinder.pos, _cylinder.end, t1);
+ const Vec3 axisToRay = sub(_ray.pos, pointOnAxis);
+
+ if (_cylinder.radius < length(axisToRay)
+ && 0.0f > ss)
+ {
+ return false;
+ }
+
+ Sphere sphere;
+ sphere.radius = _cylinder.radius;
+
+ sphere.center = 0.0f >= height
+ ? _cylinder.pos
+ : _cylinder.end
+ ;
+
+ return intersect(_ray, sphere, _hit);
+ }
+
+ Plane plane(init::None);
+ Vec3 pos(init::None);
+
+ if (0.0f >= height)
+ {
+ plane.normal = neg(axis);
+ pos = _cylinder.pos;
+ }
+ else
+ {
+ plane.normal = axis;
+ pos = _cylinder.end;
+ }
+
+ plane.dist = -dot(pos, plane.normal);
+
+ Hit tmpHit;
+ _hit = NULL != _hit ? _hit : &tmpHit;
+
+ if (intersect(_ray, plane, _hit) )
+ {
+ const Vec3 tmp = sub(pos, _hit->pos);
+ return dot(tmp, tmp) <= rsq;
+ }
+
+ return false;
+ }
+
+ bool intersect(const Ray& _ray, const Cylinder& _cylinder, Hit* _hit)
+ {
+ return intersect(_ray, _cylinder, false, _hit);
+ }
+
+ bool intersect(const Ray& _ray, const Capsule& _capsule, Hit* _hit)
+ {
+ BX_STATIC_ASSERT(sizeof(Capsule) == sizeof(Cylinder) );
+ return intersect(_ray, *( (const Cylinder*)&_capsule), true, _hit);
+ }
+
+ bool intersect(const Ray& _ray, const Cone& _cone, Hit* _hit)
+ {
+ const Vec3 axis = sub(_cone.pos, _cone.end);
+
+ const float len = length(axis);
+ const Vec3 normal = normalize(axis);
+
+ Disk disk;
+ disk.center = _cone.pos;
+ disk.normal = normal;
+ disk.radius = _cone.radius;
+
+ Hit tmpInt;
+ Hit* out = NULL != _hit ? _hit : &tmpInt;
+ bool hit = intersect(_ray, disk, out);
+
+ const Vec3 ro = sub(_ray.pos, _cone.end);
+
+ const float hyp = sqrt(square(_cone.radius) + square(len) );
+ const float cosaSq = square(len/hyp);
+ const float ndoto = dot(normal, ro);
+ const float ndotd = dot(normal, _ray.dir);
+
+ const float aa = square(ndotd) - cosaSq;
+ const float bb = 2.0f * (ndotd*ndoto - dot(_ray.dir, ro)*cosaSq);
+ const float cc = square(ndoto) - dot(ro, ro)*cosaSq;
+
+ float det = bb*bb - 4.0f*aa*cc;
+
+ if (0.0f > det)
+ {
+ return hit;
+ }
+
+ det = sqrt(det);
+ const float invA2 = 1.0f / (2.0f*aa);
+ const float t1 = (-bb - det) * invA2;
+ const float t2 = (-bb + det) * invA2;
+
+ float tt = t1;
+ if (0.0f > t1
+ || (0.0f < t2 && t2 < t1) )
+ {
+ tt = t2;
+ }
+
+ if (0.0f > tt)
+ {
+ return hit;
+ }
+
+ const Vec3 hitPos = getPointAt(_ray, tt);
+ const Vec3 point = sub(hitPos, _cone.end);
+
+ const float hh = dot(normal, point);
+
+ if (0.0f > hh
+ || len < hh)
+ {
+ return hit;
+ }
+
+ if (NULL != _hit)
+ {
+ if (!hit
+ || tt < _hit->plane.dist)
+ {
+ _hit->plane.dist = tt;
+ _hit->pos = hitPos;
+
+ const float scale = hh / dot(point, point);
+ const Vec3 pointScaled = mul(point, scale);
+
+ const Vec3 tmp = sub(pointScaled, normal);
+ _hit->plane.normal = normalize(tmp);
+ }
+ }
+
+ return true;
+ }
+
+ bool intersect(const Ray& _ray, const Plane& _plane, bool _doublesided, Hit* _hit)
+ {
+ const float dist = distance(_plane, _ray.pos);
+ const float ndotd = dot(_ray.dir, _plane.normal);
+
+ if (!_doublesided
+ && (0.0f > dist || 0.0f < ndotd) )
+ {
+ return false;
+ }
+
+ if (NULL != _hit)
+ {
+ _hit->plane.normal = _plane.normal;
+
+ float tt = -dist/ndotd;
+ _hit->plane.dist = tt;
+ _hit->pos = getPointAt(_ray, tt);
+ }
+
+ return true;
+ }
+
+ bool intersect(const Ray& _ray, const Sphere& _sphere, Hit* _hit)
+ {
+ const Vec3 rs = sub(_ray.pos, _sphere.center);
+
+ const float bb = dot(rs, _ray.dir);
+ if (0.0f < bb)
+ {
+ return false;
+ }
+
+ const float aa = dot(_ray.dir, _ray.dir);
+ const float cc = dot(rs, rs) - square(_sphere.radius);
+
+ const float discriminant = bb*bb - aa*cc;
+
+ if (0.0f >= discriminant)
+ {
+ return false;
+ }
+
+ const float sqrtDiscriminant = sqrt(discriminant);
+ const float invA = 1.0f / aa;
+ const float tt = -(bb + sqrtDiscriminant)*invA;
+
+ if (0.0f >= tt)
+ {
+ return false;
+ }
+
+ if (NULL != _hit)
+ {
+ _hit->plane.dist = tt;
+
+ const Vec3 point = getPointAt(_ray, tt);
+ _hit->pos = point;
+
+ const Vec3 tmp = sub(point, _sphere.center);
+ _hit->plane.normal = normalize(tmp);
+ }
+
+ return true;
+ }
+
+ bool intersect(const Ray& _ray, const Triangle& _triangle, Hit* _hit)
+ {
+ const Vec3 edge10 = sub(_triangle.v1, _triangle.v0);
+ const Vec3 edge02 = sub(_triangle.v0, _triangle.v2);
+ const Vec3 normal = cross(edge02, edge10);
+ const Vec3 vo = sub(_triangle.v0, _ray.pos);
+ const Vec3 dxo = cross(_ray.dir, vo);
+ const float det = dot(normal, _ray.dir);
+
+ if (0.0f < det)
+ {
+ return false;
+ }
+
+ const float invDet = 1.0f/det;
+ const float bz = dot(dxo, edge02) * invDet;
+ const float by = dot(dxo, edge10) * invDet;
+ const float bx = 1.0f - by - bz;
+
+ if (0.0f > bx
+ || 0.0f > by
+ || 0.0f > bz)
+ {
+ return false;
+ }
+
+ if (NULL != _hit)
+ {
+ _hit->plane.normal = normalize(normal);
+
+ const float tt = dot(normal, vo) * invDet;
+ _hit->plane.dist = tt;
+ _hit->pos = getPointAt(_ray, tt);
+ }
+
+ return true;
+ }
+
+ Vec3 barycentric(const Triangle& _triangle, const Vec3& _pos)
+ {
+ const Vec3 v0 = sub(_triangle.v1, _triangle.v0);
+ const Vec3 v1 = sub(_triangle.v2, _triangle.v0);
+ const Vec3 v2 = sub(_pos, _triangle.v0);
+
+ const float dot00 = dot(v0, v0);
+ const float dot01 = dot(v0, v1);
+ const float dot02 = dot(v0, v2);
+ const float dot11 = dot(v1, v1);
+ const float dot12 = dot(v1, v2);
+
+ const float invDenom = 1.0f/(dot00*dot11 - square(dot01) );
+
+ const float vv = (dot11*dot02 - dot01*dot12)*invDenom;
+ const float ww = (dot00*dot12 - dot01*dot02)*invDenom;
+ const float uu = 1.0f - vv - ww;
+
+ return { uu, vv, ww };
+ }
+
+ Vec3 cartesian(const Triangle& _triangle, const Vec3& _uvw)
+ {
+ const Vec3 b0 = mul(_triangle.v0, _uvw.x);
+ const Vec3 b1 = mul(_triangle.v1, _uvw.y);
+ const Vec3 b2 = mul(_triangle.v2, _uvw.z);
+
+ return add(add(b0, b1), b2);
+ }
+
+ void calcPlane(Plane& _outPlane, const Disk& _disk)
+ {
+ calcPlane(_outPlane, _disk.normal, _disk.center);
+ }
+
+ void calcPlane(Plane& _outPlane, const Triangle& _triangle)
+ {
+ calcPlane(_outPlane, _triangle.v0, _triangle.v1, _triangle.v2);
+ }
+
+ float projectToAxis(const Vec3& _axis, const Vec3& _point)
+ {
+ return dot(_axis, _point);
+ }
+
+ Interval projectToAxis(const Vec3& _axis, const Vec3* _points, uint32_t _num)
+ {
+ Interval interval(projectToAxis(_axis, _points[0]) );
+
+ for (uint32_t ii = 1; ii < _num; ++ii)
+ {
+ interval.expand(projectToAxis(_axis, _points[ii]) );
+ }
+
+ return interval;
+ }
+
+ Interval projectToAxis(const Vec3& _axis, const Aabb& _aabb)
+ {
+ const float extent = abs(projectToAxis(abs(_axis), getExtents(_aabb) ) );
+ const float center = projectToAxis( _axis , getCenter (_aabb) );
+ return
+ {
+ center - extent,
+ center + extent,
+ };
+ }
+
+ Interval projectToAxis(const Vec3& _axis, const Triangle& _triangle)
+ {
+ const float a0 = projectToAxis(_axis, _triangle.v0);
+ const float a1 = projectToAxis(_axis, _triangle.v1);
+ const float a2 = projectToAxis(_axis, _triangle.v2);
+ return
+ {
+ min(a0, a1, a2),
+ max(a0, a1, a2),
+ };
+ }
+
+ struct Srt
+ {
+ Quaternion rotation = init::Identity;
+ Vec3 translation = init::Zero;
+ Vec3 scale = init::Zero;
+ };
+
+ Srt toSrt(const Aabb& _aabb)
+ {
+ return { init::Identity, getCenter(_aabb), getExtents(_aabb) };
+ }
+
+ Srt toSrt(const void* _mtx)
+ {
+ Srt result;
+
+ const float* mtx = (const float*)_mtx;
+
+ result.translation = { mtx[12], mtx[13], mtx[14] };
+
+ float xx = mtx[ 0];
+ float xy = mtx[ 1];
+ float xz = mtx[ 2];
+ float yx = mtx[ 4];
+ float yy = mtx[ 5];
+ float yz = mtx[ 6];
+ float zx = mtx[ 8];
+ float zy = mtx[ 9];
+ float zz = mtx[10];
+
+ result.scale =
+ {
+ sqrt(xx*xx + xy*xy + xz*xz),
+ sqrt(yx*yx + yy*yy + yz*yz),
+ sqrt(zx*zx + zy*zy + zz*zz),
+ };
+
+ const Vec3 invScale = rcp(result.scale);
+
+ xx *= invScale.x;
+ xy *= invScale.x;
+ xz *= invScale.x;
+ yx *= invScale.y;
+ yy *= invScale.y;
+ yz *= invScale.y;
+ zx *= invScale.z;
+ zy *= invScale.z;
+ zz *= invScale.z;
+
+ const float trace = xx + yy + zz;
+
+ if (0.0f < trace)
+ {
+ const float invS = 0.5f * rsqrt(trace + 1.0f);
+ result.rotation =
+ {
+ (yz - zy) * invS,
+ (zx - xz) * invS,
+ (xy - yx) * invS,
+ 0.25f / invS,
+ };
+ }
+ else
+ {
+ if (xx > yy
+ && xx > zz)
+ {
+ const float invS = 0.5f * sqrt(max(1.0f + xx - yy - zz, 1e-8f) );
+ result.rotation =
+ {
+ 0.25f / invS,
+ (xy + yx) * invS,
+ (xz + zx) * invS,
+ (yz - zy) * invS,
+ };
+ }
+ else if (yy > zz)
+ {
+ const float invS = 0.5f * sqrt(max(1.0f + yy - xx - zz, 1e-8f) );
+ result.rotation =
+ {
+ (xy + yx) * invS,
+ 0.25f / invS,
+ (yz + zy) * invS,
+ (zx - xz) * invS,
+ };
+ }
+ else
+ {
+ const float invS = 0.5f * sqrt(max(1.0f + zz - xx - yy, 1e-8f) );
+ result.rotation =
+ {
+ (xz + zx) * invS,
+ (yz + zy) * invS,
+ 0.25f / invS,
+ (xy - yx) * invS,
+ };
+ }
+ }
+
+ return result;
+ }
+
+ void mtxFromSrt(float* _outMtx, const Srt& _srt)
+ {
+ mtxFromQuaternion(_outMtx, _srt.rotation);
+
+ store<Vec3>(&_outMtx[0], mul(load<Vec3>(&_outMtx[0]), _srt.scale.x) );
+ store<Vec3>(&_outMtx[4], mul(load<Vec3>(&_outMtx[4]), _srt.scale.y) );
+ store<Vec3>(&_outMtx[8], mul(load<Vec3>(&_outMtx[8]), _srt.scale.z) );
+
+ store<Vec3>(&_outMtx[12], _srt.translation);
+ }
+
+ bool isNearZero(float _v)
+ {
+ return isEqual(_v, 0.0f, 0.00001f);
+ }
+
+ bool isNearZero(const Vec3& _v)
+ {
+ return isNearZero(dot(_v, _v) );
+ }
+
+ bool intersect(Line& _outLine, const Plane& _planeA, const Plane& _planeB)
+ {
+ const Vec3 axb = cross(_planeA.normal, _planeB.normal);
+ const float denom = dot(axb, axb);
+
+ if (isNearZero(denom) )
+ {
+ return false;
+ }
+
+ const Vec3 bxaxb = cross(_planeB.normal, axb);
+ const Vec3 axbxa = cross(axb, _planeA.normal);
+ const Vec3 tmp0 = mul(bxaxb, _planeA.dist);
+ const Vec3 tmp1 = mul(axbxa, _planeB.dist);
+ const Vec3 tmp2 = add(tmp0, tmp1);
+
+ _outLine.pos = mul(tmp2, -1.0f/denom);
+ _outLine.dir = normalize(axb);
+
+ return true;
+ }
+
+ Vec3 intersectPlanes(const Plane& _pa, const Plane& _pb, const Plane& _pc)
+ {
+ const Vec3 axb = cross(_pa.normal, _pb.normal);
+ const Vec3 bxc = cross(_pb.normal, _pc.normal);
+ const Vec3 cxa = cross(_pc.normal, _pa.normal);
+ const Vec3 tmp0 = mul(bxc, _pa.dist);
+ const Vec3 tmp1 = mul(cxa, _pb.dist);
+ const Vec3 tmp2 = mul(axb, _pc.dist);
+ const Vec3 tmp3 = add(tmp0, tmp1);
+ const Vec3 tmp4 = add(tmp3, tmp2);
+
+ const float denom = dot(_pa.normal, bxc);
+ const Vec3 result = mul(tmp4, -1.0f/denom);
+
+ return result;
+ }
+
+ bool intersect(float& _outTa, float& _outTb, const LineSegment& _a, const LineSegment& _b)
+ {
+ // Reference(s):
+ //
+ // - The shortest line between two lines in 3D
+ // https://web.archive.org/web/20120309093234/http://paulbourke.net/geometry/lineline3d/
+
+ const Vec3 bd = sub(_b.end, _b.pos);
+ if (isNearZero(bd) )
+ {
+ return false;
+ }
+
+ const Vec3 ad = sub(_a.end, _a.pos);
+ if (isNearZero(ad) )
+ {
+ return false;
+ }
+
+ const Vec3 ab = sub(_a.pos, _b.pos);
+
+ const float d0 = projectToAxis(ab, bd);
+ const float d1 = projectToAxis(ad, bd);
+ const float d2 = projectToAxis(ab, ad);
+ const float d3 = projectToAxis(bd, bd);
+ const float d4 = projectToAxis(ad, ad);
+
+ const float denom = d4*d3 - square(d1);
+
+ float ta = 0.0f;
+
+ if (!isNearZero(denom) )
+ {
+ ta = (d0*d1 - d2*d3)/denom;
+ }
+
+ _outTa = ta;
+ _outTb = (d0+d1*ta)/d3;
+
+ return true;
+ }
+
+ bool intersect(const LineSegment& _a, const LineSegment& _b)
+ {
+ float ta, tb;
+ if (!intersect(ta, tb, _a, _b) )
+ {
+ return false;
+ }
+
+ return 0.0f >= ta
+ && 1.0f <= ta
+ && 0.0f >= tb
+ && 1.0f <= tb
+ ;
+ }
+
+ bool intersect(const LineSegment& _line, const Plane& _plane, Hit* _hit)
+ {
+ const float dist = distance(_plane, _line.pos);
+ const float flip = sign(dist);
+ const Vec3 dir = normalize(sub(_line.end, _line.pos) );
+ const float ndotd = dot(dir, _plane.normal);
+ const float tt = -dist/ndotd;
+ const float len = length(sub(_line.end, _line.pos) );
+
+ if (tt < 0.0f || tt > len)
+ {
+ return false;
+ }
+
+ if (NULL != _hit)
+ {
+ _hit->pos = mad(dir, tt, _line.pos);
+
+ _hit->plane.normal = mul(_plane.normal, flip);
+ _hit->plane.dist = -dot(_hit->plane.normal, _hit->pos);
+ }
+
+ return true;
+ }
+
+ float distance(const Plane& _plane, const LineSegment& _line)
+ {
+ const float pd = distance(_plane, _line.pos);
+ const float ed = distance(_plane, _line.end);
+ return min(max(pd*ed, 0.0f), abs(pd), abs(ed) );
+ }
+
+ Vec3 closestPoint(const Line& _line, const Vec3& _point)
+ {
+ const float tt = projectToAxis(_line.dir, sub(_point, _line.pos) );
+ return getPointAt(_line, tt);
+ }
+
+ Vec3 closestPoint(const LineSegment& _line, const Vec3& _point, float& _outT)
+ {
+ const Vec3 axis = sub(_line.end, _line.pos);
+ const float lengthSq = dot(axis, axis);
+ const float tt = clamp(projectToAxis(axis, sub(_point, _line.pos) ) / lengthSq, 0.0f, 1.0f);
+ _outT = tt;
+ return mad(axis, tt, _line.pos);
+ }
+
+ Vec3 closestPoint(const LineSegment& _line, const Vec3& _point)
+ {
+ float ignored;
+ return closestPoint(_line, _point, ignored);
+ }
+
+ Vec3 closestPoint(const Plane& _plane, const Vec3& _point)
+ {
+ const float dist = distance(_plane, _point);
+ return sub(_point, mul(_plane.normal, dist) );
+ }
+
+ Vec3 closestPoint(const Aabb& _aabb, const Vec3& _point)
+ {
+ return clamp(_point, _aabb.min, _aabb.max);
+ }
+
+ Vec3 closestPoint(const Obb& _obb, const Vec3& _point)
+ {
+ const Srt srt = toSrt(_obb.mtx);
+
+ Aabb aabb;
+ toAabb(aabb, srt.scale);
+
+ const Quaternion invRotation = invert(srt.rotation);
+ const Vec3 obbSpacePos = mul(sub(_point, srt.translation), srt.rotation);
+ const Vec3 pos = closestPoint(aabb, obbSpacePos);
+
+ return add(mul(pos, invRotation), srt.translation);
+ }
+
+ Vec3 closestPoint(const Triangle& _triangle, const Vec3& _point)
+ {
+ Plane plane(init::None);
+ calcPlane(plane, _triangle);
+
+ const Vec3 pos = closestPoint(plane, _point);
+ const Vec3 uvw = barycentric(_triangle, pos);
+
+ return cartesian(_triangle, clamp<Vec3>(uvw, Vec3(0.0f), Vec3(1.0f) ) );
+ }
+
+ bool overlap(const Aabb& _aabb, const Vec3& _pos)
+ {
+ const Vec3 ac = getCenter(_aabb);
+ const Vec3 ae = getExtents(_aabb);
+ const Vec3 abc = abs(sub(ac, _pos) );
+
+ return abc.x <= ae.x
+ && abc.y <= ae.y
+ && abc.z <= ae.z
+ ;
+ }
+
+ bool overlap(const Aabb& _aabbA, const Aabb& _aabbB)
+ {
+ return true
+ && overlap(Interval{_aabbA.min.x, _aabbA.max.x}, Interval{_aabbB.min.x, _aabbB.max.x})
+ && overlap(Interval{_aabbA.min.y, _aabbA.max.y}, Interval{_aabbB.min.y, _aabbB.max.y})
+ && overlap(Interval{_aabbA.min.z, _aabbA.max.z}, Interval{_aabbB.min.z, _aabbB.max.z})
+ ;
+ }
+
+ bool overlap(const Aabb& _aabb, const Plane& _plane)
+ {
+ const Vec3 center = getCenter(_aabb);
+ const float dist = distance(_plane, center);
+
+ const Vec3 extents = getExtents(_aabb);
+ const Vec3 normal = abs(_plane.normal);
+ const float radius = dot(extents, normal);
+
+ return abs(dist) <= radius;
+ }
+
+ static constexpr Vec3 kAxis[] =
+ {
+ { 1.0f, 0.0f, 0.0f },
+ { 0.0f, 1.0f, 0.0f },
+ { 0.0f, 0.0f, 1.0f },
+ };
+
+ bool overlap(const Aabb& _aabb, const Triangle& _triangle)
+ {
+ Aabb triAabb;
+ toAabb(triAabb, _triangle);
+
+ if (!overlap(_aabb, triAabb) )
+ {
+ return false;
+ }
+
+ Plane plane(init::None);
+ calcPlane(plane, _triangle);
+
+ if (!overlap(_aabb, plane) )
+ {
+ return false;
+ }
+
+ const Vec3 center = getCenter(_aabb);
+ const Vec3 v0 = sub(_triangle.v0, center);
+ const Vec3 v1 = sub(_triangle.v1, center);
+ const Vec3 v2 = sub(_triangle.v2, center);
+
+ const Vec3 edge[] =
+ {
+ sub(v1, v0),
+ sub(v2, v1),
+ sub(v0, v2),
+ };
+
+ for (uint32_t ii = 0; ii < 3; ++ii)
+ {
+ for (uint32_t jj = 0; jj < 3; ++jj)
+ {
+ const Vec3 axis = cross(kAxis[ii], edge[jj]);
+
+ const Interval aabbR = projectToAxis(axis, _aabb);
+ const Interval triR = projectToAxis(axis, _triangle);
+
+ if (!overlap(aabbR, triR) )
+ {
+ return false;
+ }
+ }
+ }
+
+ return true;
+ }
+
+ bool overlap(const Aabb& _aabb, const Capsule& _capsule)
+ {
+ const Vec3 pos = closestPoint(LineSegment{_capsule.pos, _capsule.end}, getCenter(_aabb) );
+ return overlap(_aabb, Sphere{pos, _capsule.radius});
+ }
+
+ bool overlap(const Aabb& _aabb, const Cone& _cone)
+ {
+ float tt;
+ const Vec3 pos = closestPoint(LineSegment{_cone.pos, _cone.end}, getCenter(_aabb), tt);
+ return overlap(_aabb, Sphere{pos, lerp(_cone.radius, 0.0f, tt)});
+ }
+
+ bool overlap(const Aabb& _aabb, const Disk& _disk)
+ {
+ if (!overlap(_aabb, Sphere{_disk.center, _disk.radius}) )
+ {
+ return false;
+ }
+
+ Plane plane(init::None);
+ calcPlane(plane, _disk.normal, _disk.center);
+
+ return overlap(_aabb, plane);
+ }
+
+ static void calcObbVertices(
+ Vec3* _outVertices
+ , const Vec3& _axisX
+ , const Vec3& _axisY
+ , const Vec3& _axisZ
+ , const Vec3& _pos
+ , const Vec3& _scale
+ )
+ {
+ const Vec3 ax = mul(_axisX, _scale.x);
+ const Vec3 ay = mul(_axisY, _scale.y);
+ const Vec3 az = mul(_axisZ, _scale.z);
+
+ const Vec3 ppx = add(_pos, ax);
+ const Vec3 pmx = sub(_pos, ax);
+ const Vec3 ypz = add(ay, az);
+ const Vec3 ymz = sub(ay, az);
+
+ _outVertices[0] = sub(pmx, ymz);
+ _outVertices[1] = sub(ppx, ymz);
+ _outVertices[2] = add(ppx, ymz);
+ _outVertices[3] = add(pmx, ymz);
+ _outVertices[4] = sub(pmx, ypz);
+ _outVertices[5] = sub(ppx, ypz);
+ _outVertices[6] = add(ppx, ypz);
+ _outVertices[7] = add(pmx, ypz);
+ }
+
+ static bool overlaps(const Vec3& _axis, const Vec3* _vertsA, const Vec3* _vertsB)
+ {
+ Interval ia = projectToAxis(_axis, _vertsA, 8);
+ Interval ib = projectToAxis(_axis, _vertsB, 8);
+
+ return overlap(ia, ib);
+ }
+
+ static bool overlap(const Srt& _srtA, const Srt& _srtB)
+ {
+ const Vec3 ax = toXAxis(_srtA.rotation);
+ const Vec3 ay = toYAxis(_srtA.rotation);
+ const Vec3 az = toZAxis(_srtA.rotation);
+
+ const Vec3 bx = toXAxis(_srtB.rotation);
+ const Vec3 by = toYAxis(_srtB.rotation);
+ const Vec3 bz = toZAxis(_srtB.rotation);
+
+ Vec3 vertsA[8] = { init::None, init::None, init::None, init::None, init::None, init::None, init::None, init::None };
+ calcObbVertices(vertsA, ax, ay, az, init::Zero, _srtA.scale);
+
+ Vec3 vertsB[8] = { init::None, init::None, init::None, init::None, init::None, init::None, init::None, init::None };
+ calcObbVertices(vertsB, bx, by, bz, sub(_srtB.translation, _srtA.translation), _srtB.scale);
+
+ return overlaps(ax, vertsA, vertsB)
+ && overlaps(ay, vertsA, vertsB)
+ && overlaps(az, vertsA, vertsB)
+ && overlaps(bx, vertsA, vertsB)
+ && overlaps(by, vertsA, vertsB)
+ && overlaps(bz, vertsA, vertsB)
+ && overlaps(cross(ax, bx), vertsA, vertsB)
+ && overlaps(cross(ax, by), vertsA, vertsB)
+ && overlaps(cross(ax, bz), vertsA, vertsB)
+ && overlaps(cross(ay, bx), vertsA, vertsB)
+ && overlaps(cross(ay, by), vertsA, vertsB)
+ && overlaps(cross(ay, bz), vertsA, vertsB)
+ && overlaps(cross(az, bx), vertsA, vertsB)
+ && overlaps(cross(az, by), vertsA, vertsB)
+ && overlaps(cross(az, bz), vertsA, vertsB)
+ ;
+ }
+
+ bool overlap(const Aabb& _aabb, const Obb& _obb)
+ {
+ const Srt srtA = toSrt(_aabb);
+ const Srt srtB = toSrt(_obb.mtx);
+
+ return overlap(srtA, srtB);
+ }
+
+ bool overlap(const Capsule& _capsule, const Vec3& _pos)
+ {
+ const Vec3 pos = closestPoint(LineSegment{_capsule.pos, _capsule.end}, _pos);
+ return overlap(Sphere{pos, _capsule.radius}, _pos);
+ }
+
+ bool overlap(const Capsule& _capsule, const Plane& _plane)
+ {
+ return distance(_plane, LineSegment{_capsule.pos, _capsule.end}) <= _capsule.radius;
+ }
+
+ bool overlap(const Capsule& _capsuleA, const Capsule& _capsuleB)
+ {
+ float ta, tb;
+ if (!intersect(ta, tb, {_capsuleA.pos, _capsuleA.end}, {_capsuleB.pos, _capsuleB.end}) )
+ {
+ return false;
+ }
+
+ if (0.0f <= ta
+ && 1.0f >= ta
+ && 0.0f <= tb
+ && 1.0f >= tb)
+ {
+ const Vec3 ad = sub(_capsuleA.end, _capsuleA.pos);
+ const Vec3 bd = sub(_capsuleB.end, _capsuleB.pos);
+
+ return overlap(
+ Sphere{mad(ad, ta, _capsuleA.pos), _capsuleA.radius}
+ , Sphere{mad(bd, tb, _capsuleB.pos), _capsuleB.radius}
+ );
+ }
+
+ if (0.0f <= ta
+ && 1.0f >= ta)
+ {
+ return overlap(_capsuleA, Sphere{0.0f >= tb ? _capsuleB.pos : _capsuleB.end, _capsuleB.radius});
+ }
+
+ if (0.0f <= tb
+ && 1.0f >= tb)
+ {
+ return overlap(_capsuleB, Sphere{0.0f >= ta ? _capsuleA.pos : _capsuleA.end, _capsuleA.radius});
+ }
+
+ const Vec3 pa = 0.0f > ta ? _capsuleA.pos : _capsuleA.end;
+ const Vec3 pb = 0.0f > tb ? _capsuleB.pos : _capsuleB.end;
+ const Vec3 closestA = closestPoint(LineSegment{_capsuleA.pos, _capsuleA.end}, pb);
+ const Vec3 closestB = closestPoint(LineSegment{_capsuleB.pos, _capsuleB.end}, pa);
+
+ if (dot(closestA, pb) <= dot(closestB, pa) )
+ {
+ return overlap(_capsuleA, Sphere{closestB, _capsuleB.radius});
+ }
+
+ return overlap(_capsuleB, Sphere{closestA, _capsuleA.radius});
+ }
+
+ bool overlap(const Cone& _cone, const Vec3& _pos)
+ {
+ float tt;
+ const Vec3 pos = closestPoint(LineSegment{_cone.pos, _cone.end}, _pos, tt);
+ return overlap(Disk{pos, normalize(sub(_cone.end, _cone.pos) ), lerp(_cone.radius, 0.0f, tt)}, _pos);
+ }
+
+ bool overlap(const Cone& _cone, const Cylinder& _cylinder)
+ {
+ BX_UNUSED(_cone, _cylinder);
+ return false;
+ }
+
+ bool overlap(const Cone& _cone, const Capsule& _capsule)
+ {
+ BX_UNUSED(_cone, _capsule);
+ return false;
+ }
+
+ bool overlap(const Cone& _coneA, const Cone& _coneB)
+ {
+ BX_UNUSED(_coneA, _coneB);
+ return false;
+ }
+
+ bool overlap(const Cone& _cone, const Disk& _disk)
+ {
+ BX_UNUSED(_cone, _disk);
+ return false;
+ }
+
+ bool overlap(const Cone& _cone, const Obb& _obb)
+ {
+ BX_UNUSED(_cone, _obb);
+ return false;
+ }
+
+ bool overlap(const Cylinder& _cylinder, const Vec3& _pos)
+ {
+ const Vec3 pos = closestPoint(LineSegment{_cylinder.pos, _cylinder.end}, _pos);
+ return overlap(Disk{pos, normalize(sub(_cylinder.end, _cylinder.pos) ), _cylinder.radius}, _pos);
+ }
+
+ bool overlap(const Cylinder& _cylinder, const Sphere& _sphere)
+ {
+ const Vec3 pos = closestPoint(LineSegment{_cylinder.pos, _cylinder.end}, _sphere.center);
+ return overlap(Disk{pos, normalize(sub(_cylinder.end, _cylinder.pos) ), _cylinder.radius}, _sphere);
+ }
+
+ bool overlap(const Cylinder& _cylinder, const Aabb& _aabb)
+ {
+ const Vec3 pos = closestPoint(LineSegment{_cylinder.pos, _cylinder.end}, getCenter(_aabb) );
+ return overlap(Disk{pos, normalize(sub(_cylinder.end, _cylinder.pos) ), _cylinder.radius}, _aabb);
+ }
+
+ bool overlap(const Cylinder& _cylinder, const Plane& _plane)
+ {
+ BX_UNUSED(_cylinder, _plane);
+ return false;
+ }
+
+ bool overlap(const Cylinder& _cylinderA, const Cylinder& _cylinderB)
+ {
+ BX_UNUSED(_cylinderA, _cylinderB);
+ return false;
+ }
+
+ bool overlap(const Cylinder& _cylinder, const Capsule& _capsule)
+ {
+ BX_UNUSED(_cylinder, _capsule);
+ return false;
+ }
+
+ bool overlap(const Cylinder& _cylinder, const Disk& _disk)
+ {
+ BX_UNUSED(_cylinder, _disk);
+ return false;
+ }
+
+ bool overlap(const Cylinder& _cylinder, const Obb& _obb)
+ {
+ BX_UNUSED(_cylinder, _obb);
+ return false;
+ }
+
+ bool overlap(const Disk& _disk, const Vec3& _pos)
+ {
+ Plane plane(init::None);
+ calcPlane(plane, _disk.normal, _disk.center);
+
+ if (!isNearZero(distance(plane, _pos) ) )
+ {
+ return false;
+ }
+
+ return distanceSq(_disk.center, _pos) <= square(_disk.radius);
+ }
+
+ bool overlap(const Disk& _disk, const Plane& _plane)
+ {
+ Plane plane(init::None);
+ calcPlane(plane, _disk.normal, _disk.center);
+
+ if (!overlap(plane, _plane) )
+ {
+ return false;
+ }
+
+ return overlap(_plane, Sphere{_disk.center, _disk.radius});
+ }
+
+ bool overlap(const Disk& _disk, const Capsule& _capsule)
+ {
+ if (!overlap(_capsule, Sphere{_disk.center, _disk.radius}) )
+ {
+ return false;
+ }
+
+ Plane plane(init::None);
+ calcPlane(plane, _disk.normal, _disk.center);
+
+ return overlap(_capsule, plane);
+ }
+
+ bool overlap(const Disk& _diskA, const Disk& _diskB)
+ {
+ Plane planeA(init::None);
+ calcPlane(planeA, _diskA.normal, _diskA.center);
+
+ Plane planeB(init::None);
+ calcPlane(planeB, _diskB);
+
+ Line line;
+
+ if (!intersect(line, planeA, planeB) )
+ {
+ return false;
+ }
+
+ const Vec3 pa = closestPoint(line, _diskA.center);
+ const Vec3 pb = closestPoint(line, _diskB.center);
+
+ const float lenA = distance(pa, _diskA.center);
+ const float lenB = distance(pb, _diskB.center);
+
+ return sqrt(square(_diskA.radius) - square(lenA) )
+ + sqrt(square(_diskB.radius) - square(lenB) )
+ >= distance(pa, pb)
+ ;
+ }
+
+ bool overlap(const Disk& _disk, const Obb& _obb)
+ {
+ if (!overlap(_obb, Sphere{_disk.center, _disk.radius}) )
+ {
+ return false;
+ }
+
+ Plane plane(init::None);
+ calcPlane(plane, _disk.normal, _disk.center);
+
+ return overlap(_obb, plane);
+ }
+
+ bool overlap(const Obb& _obb, const Vec3& _pos)
+ {
+ const Srt srt = toSrt(_obb.mtx);
+
+ Aabb aabb;
+ toAabb(aabb, srt.scale);
+
+ const Quaternion invRotation = invert(srt.rotation);
+ const Vec3 pos = mul(sub(_pos, srt.translation), invRotation);
+
+ return overlap(aabb, pos);
+ }
+
+ bool overlap(const Obb& _obb, const Plane& _plane)
+ {
+ const Srt srt = toSrt(_obb.mtx);
+
+ const Quaternion invRotation = invert(srt.rotation);
+ const Vec3 axis =
+ {
+ projectToAxis(_plane.normal, mul(Vec3{1.0f, 0.0f, 0.0f}, invRotation) ),
+ projectToAxis(_plane.normal, mul(Vec3{0.0f, 1.0f, 0.0f}, invRotation) ),
+ projectToAxis(_plane.normal, mul(Vec3{0.0f, 0.0f, 1.0f}, invRotation) ),
+ };
+
+ const float dist = abs(distance(_plane, srt.translation) );
+ const float radius = dot(srt.scale, abs(axis) );
+
+ return dist <= radius;
+ }
+
+ bool overlap(const Obb& _obb, const Capsule& _capsule)
+ {
+ const Srt srt = toSrt(_obb.mtx);
+
+ Aabb aabb;
+ toAabb(aabb, srt.scale);
+
+ const Quaternion invRotation = invert(srt.rotation);
+
+ const Capsule capsule =
+ {
+ mul(sub(_capsule.pos, srt.translation), invRotation),
+ mul(sub(_capsule.end, srt.translation), invRotation),
+ _capsule.radius,
+ };
+
+ return overlap(aabb, capsule);
+ }
+
+ bool overlap(const Obb& _obbA, const Obb& _obbB)
+ {
+ const Srt srtA = toSrt(_obbA.mtx);
+ const Srt srtB = toSrt(_obbB.mtx);
+
+ return overlap(srtA, srtB);
+ }
+
+ bool overlap(const Plane& _plane, const LineSegment& _line)
+ {
+ return isNearZero(distance(_plane, _line) );
+ }
+
+ bool overlap(const Plane& _plane, const Vec3& _pos)
+ {
+ return isNearZero(distance(_plane, _pos) );
+ }
+
+ bool overlap(const Plane& _planeA, const Plane& _planeB)
+ {
+ const Vec3 dir = cross(_planeA.normal, _planeB.normal);
+ const float len = length(dir);
+
+ return !isNearZero(len);
+ }
+
+ bool overlap(const Plane& _plane, const Cone& _cone)
+ {
+ const Vec3 axis = sub(_cone.pos, _cone.end);
+ const float len = length(axis);
+ const Vec3 dir = normalize(axis);
+
+ const Vec3 v1 = cross(_plane.normal, dir);
+ const Vec3 v2 = cross(v1, dir);
+
+ const float bb = len;
+ const float aa = _cone.radius;
+ const float cc = sqrt(square(aa) + square(bb) );
+
+ const Vec3 pos = add(add(_cone.end
+ , mul(dir, len * bb/cc) )
+ , mul(v2, len * aa/cc)
+ );
+
+ return overlap(_plane, LineSegment{pos, _cone.end});
+ }
+
+ bool overlap(const Sphere& _sphere, const Vec3& _pos)
+ {
+ const float distSq = distanceSq(_sphere.center, _pos);
+ const float radiusSq = square(_sphere.radius);
+ return distSq <= radiusSq;
+ }
+
+ bool overlap(const Sphere& _sphereA, const Sphere& _sphereB)
+ {
+ const float distSq = distanceSq(_sphereA.center, _sphereB.center);
+ const float radiusSq = square(_sphereA.radius + _sphereB.radius);
+ return distSq <= radiusSq;
+ }
+
+ bool overlap(const Sphere& _sphere, const Aabb& _aabb)
+ {
+ const Vec3 pos = closestPoint(_aabb, _sphere.center);
+ return overlap(_sphere, pos);
+ }
+
+ bool overlap(const Sphere& _sphere, const Plane& _plane)
+ {
+ return abs(distance(_plane, _sphere.center) ) <= _sphere.radius;
+ }
+
+ bool overlap(const Sphere& _sphere, const Triangle& _triangle)
+ {
+ Plane plane(init::None);
+ calcPlane(plane, _triangle);
+
+ if (!overlap(_sphere, plane) )
+ {
+ return false;
+ }
+
+ const Vec3 pos = closestPoint(plane, _sphere.center);
+ const Vec3 uvw = barycentric(_triangle, pos);
+ const float nr = -_sphere.radius;
+
+ return uvw.x >= nr
+ && uvw.y >= nr
+ && uvw.z >= nr
+ ;
+ }
+
+ bool overlap(const Sphere& _sphere, const Capsule& _capsule)
+ {
+ const Vec3 pos = closestPoint(LineSegment{_capsule.pos, _capsule.end}, _sphere.center);
+ return overlap(_sphere, Sphere{pos, _capsule.radius});
+ }
+
+ bool overlap(const Sphere& _sphere, const Cone& _cone)
+ {
+ float tt;
+ const Vec3 pos = closestPoint(LineSegment{_cone.pos, _cone.end}, _sphere.center, tt);
+ return overlap(_sphere, Sphere{pos, lerp(_cone.radius, 0.0f, tt)});
+ }
+
+ bool overlap(const Sphere& _sphere, const Disk& _disk)
+ {
+ if (!overlap(_sphere, Sphere{_disk.center, _disk.radius}) )
+ {
+ return false;
+ }
+
+ Plane plane(init::None);
+ calcPlane(plane, _disk.normal, _disk.center);
+
+ return overlap(_sphere, plane);
+ }
+
+ bool overlap(const Sphere& _sphere, const Obb& _obb)
+ {
+ const Vec3 pos = closestPoint(_obb, _sphere.center);
+ return overlap(_sphere, pos);
+ }
+
+ bool overlap(const Triangle& _triangle, const Vec3& _pos)
+ {
+ const Vec3 uvw = barycentric(_triangle, _pos);
+
+ return uvw.x >= 0.0f
+ && uvw.y >= 0.0f
+ && uvw.z >= 0.0f
+ ;
+ }
+
+ bool overlap(const Triangle& _triangle, const Plane& _plane)
+ {
+ const float dist0 = distance(_plane, _triangle.v0);
+ const float dist1 = distance(_plane, _triangle.v1);
+ const float dist2 = distance(_plane, _triangle.v2);
+
+ const float minDist = min(dist0, dist1, dist2);
+ const float maxDist = max(dist0, dist1, dist2);
+
+ return 0.0f > minDist
+ && 0.0f < maxDist
+ ;
+ }
+
+ inline bool overlap(const Triangle& _triangleA, const Triangle& _triangleB, const Vec3& _axis)
+ {
+ const Interval ia = projectToAxis(_axis, _triangleA);
+ const Interval ib = projectToAxis(_axis, _triangleB);
+ return overlap(ia, ib);
+ }
+
+ bool overlap(const Triangle& _triangleA, const Triangle& _triangleB)
+ {
+ const Vec3 baA = sub(_triangleA.v1, _triangleA.v0);
+ const Vec3 cbA = sub(_triangleA.v2, _triangleA.v1);
+ const Vec3 acA = sub(_triangleA.v0, _triangleA.v2);
+
+ const Vec3 baB = sub(_triangleB.v1, _triangleB.v0);
+ const Vec3 cbB = sub(_triangleB.v2, _triangleB.v1);
+ const Vec3 acB = sub(_triangleB.v0, _triangleB.v2);
+
+ return overlap(_triangleA, _triangleB, cross(baA, cbA) )
+ && overlap(_triangleA, _triangleB, cross(baB, cbB) )
+ && overlap(_triangleA, _triangleB, cross(baB, baA) )
+ && overlap(_triangleA, _triangleB, cross(baB, cbA) )
+ && overlap(_triangleA, _triangleB, cross(baB, acA) )
+ && overlap(_triangleA, _triangleB, cross(cbB, baA) )
+ && overlap(_triangleA, _triangleB, cross(cbB, cbA) )
+ && overlap(_triangleA, _triangleB, cross(cbB, acA) )
+ && overlap(_triangleA, _triangleB, cross(acB, baA) )
+ && overlap(_triangleA, _triangleB, cross(acB, cbA) )
+ && overlap(_triangleA, _triangleB, cross(acB, acA) )
+ ;
+ }
+
+ template<typename Ty>
+ bool overlap(const Triangle& _triangle, const Ty& _ty)
+ {
+ Plane plane(init::None);
+ calcPlane(plane, _triangle);
+
+ plane.normal = neg(plane.normal);
+ plane.dist = -plane.dist;
+
+ const LineSegment line =
+ {
+ _ty.pos,
+ _ty.end,
+ };
+
+ Hit hit;
+ if (intersect(line, plane, &hit) )
+ {
+ return true;
+ }
+
+ const Vec3 pos = closestPoint(plane, hit.pos);
+ const Vec3 uvw = barycentric(_triangle, pos);
+
+ const float nr = -_ty.radius;
+
+ if (uvw.x >= nr
+ && uvw.y >= nr
+ && uvw.z >= nr)
+ {
+ return true;
+ }
+
+ const LineSegment ab = LineSegment{_triangle.v0, _triangle.v1};
+ const LineSegment bc = LineSegment{_triangle.v1, _triangle.v2};
+ const LineSegment ca = LineSegment{_triangle.v2, _triangle.v0};
+
+ float ta0 = 0.0f, tb0 = 0.0f;
+ const bool i0 = intersect(ta0, tb0, ab, line);
+
+ float ta1, tb1;
+ const bool i1 = intersect(ta1, tb1, bc, line);
+
+ float ta2, tb2;
+ const bool i2 = intersect(ta2, tb2, ca, line);
+
+ if (!i0
+ || !i1
+ || !i2)
+ {
+ return false;
+ }
+
+ ta0 = clamp(ta0, 0.0f, 1.0f);
+ ta1 = clamp(ta1, 0.0f, 1.0f);
+ ta2 = clamp(ta2, 0.0f, 1.0f);
+ tb0 = clamp(tb0, 0.0f, 1.0f);
+ tb1 = clamp(tb1, 0.0f, 1.0f);
+ tb2 = clamp(tb2, 0.0f, 1.0f);
+
+ const Vec3 pa0 = getPointAt(ab, ta0);
+ const Vec3 pa1 = getPointAt(bc, ta1);
+ const Vec3 pa2 = getPointAt(ca, ta2);
+
+ const Vec3 pb0 = getPointAt(line, tb0);
+ const Vec3 pb1 = getPointAt(line, tb1);
+ const Vec3 pb2 = getPointAt(line, tb2);
+
+ const float d0 = distanceSq(pa0, pb0);
+ const float d1 = distanceSq(pa1, pb1);
+ const float d2 = distanceSq(pa2, pb2);
+
+ if (d0 <= d1
+ && d0 <= d2)
+ {
+ return overlap(_ty, pa0);
+ }
+ else if (d1 <= d2)
+ {
+ return overlap(_ty, pa1);
+ }
+
+ return overlap(_ty, pa2);
+ }
+
+ bool overlap(const Triangle& _triangle, const Cylinder& _cylinder)
+ {
+ return overlap<Cylinder>(_triangle, _cylinder);
+ }
+
+ bool overlap(const Triangle& _triangle, const Capsule& _capsule)
+ {
+ return overlap<Capsule>(_triangle, _capsule);
+ }
+
+ bool overlap(const Triangle& _triangle, const Cone& _cone)
+ {
+ const LineSegment ab = LineSegment{_triangle.v0, _triangle.v1};
+ const LineSegment bc = LineSegment{_triangle.v1, _triangle.v2};
+ const LineSegment ca = LineSegment{_triangle.v2, _triangle.v0};
+
+ const LineSegment line =
+ {
+ _cone.pos,
+ _cone.end,
+ };
+
+ float ta0 = 0.0f, tb0 = 0.0f;
+ const bool i0 = intersect(ta0, tb0, ab, line);
+
+ float ta1, tb1;
+ const bool i1 = intersect(ta1, tb1, bc, line);
+
+ float ta2, tb2;
+ const bool i2 = intersect(ta2, tb2, ca, line);
+
+ if (!i0
+ || !i1
+ || !i2)
+ {
+ return false;
+ }
+
+ ta0 = clamp(ta0, 0.0f, 1.0f);
+ ta1 = clamp(ta1, 0.0f, 1.0f);
+ ta2 = clamp(ta2, 0.0f, 1.0f);
+ tb0 = clamp(tb0, 0.0f, 1.0f);
+ tb1 = clamp(tb1, 0.0f, 1.0f);
+ tb2 = clamp(tb2, 0.0f, 1.0f);
+
+ const Vec3 pa0 = getPointAt(ab, ta0);
+ const Vec3 pa1 = getPointAt(bc, ta1);
+ const Vec3 pa2 = getPointAt(ca, ta2);
+
+ const Vec3 pb0 = getPointAt(line, tb0);
+ const Vec3 pb1 = getPointAt(line, tb1);
+ const Vec3 pb2 = getPointAt(line, tb2);
+
+ const float d0 = distanceSq(pa0, pb0);
+ const float d1 = distanceSq(pa1, pb1);
+ const float d2 = distanceSq(pa2, pb2);
+
+ if (d0 <= d1
+ && d0 <= d2)
+ {
+ return overlap(_cone, pa0);
+ }
+ else if (d1 <= d2)
+ {
+ return overlap(_cone, pa1);
+ }
+
+ return overlap(_cone, pa2);
+ }
+
+ bool overlap(const Triangle& _triangle, const Disk& _disk)
+ {
+ if (!overlap(_triangle, Sphere{_disk.center, _disk.radius}) )
+ {
+ return false;
+ }
+
+ Plane plane(init::None);
+ calcPlane(plane, _disk.normal, _disk.center);
+
+ return overlap(_triangle, plane);
+ }
+
+ bool overlap(const Triangle& _triangle, const Obb& _obb)
+ {
+ const Srt srt = toSrt(_obb.mtx);
+
+ Aabb aabb;
+ toAabb(aabb, srt.scale);
+
+ const Quaternion invRotation = invert(srt.rotation);
+
+ const Triangle triangle =
+ {
+ mul(sub(_triangle.v0, srt.translation), invRotation),
+ mul(sub(_triangle.v1, srt.translation), invRotation),
+ mul(sub(_triangle.v2, srt.translation), invRotation),
+ };
+
+ return overlap(triangle, aabb);
+ }
+
+} // namespace bx
diff --git a/3rdparty/bx/src/bx.cpp b/3rdparty/bx/src/bx.cpp
index 659cb5917cf..45b4d7528a7 100644
--- a/3rdparty/bx/src/bx.cpp
+++ b/3rdparty/bx/src/bx.cpp
@@ -1,9 +1,8 @@
/*
- * Copyright 2010-2018 Branimir Karadzic. All rights reserved.
- * License: https://github.com/bkaradzic/bx#license-bsd-2-clause
+ * Copyright 2010-2022 Branimir Karadzic. All rights reserved.
+ * License: https://github.com/bkaradzic/bx/blob/master/LICENSE
*/
-#include "bx_p.h"
#include <bx/debug.h>
#include <bx/readerwriter.h>
@@ -44,29 +43,29 @@ namespace bx
#endif // BX_CRT_NONE
}
- void memCopy(void* _dst, const void* _src, uint32_t _size, uint32_t _num, uint32_t _srcPitch, uint32_t _dstPitch)
+ void memCopy(
+ void* _dst
+ , uint32_t _dstStride
+ , const void* _src
+ , uint32_t _srcStride
+ , uint32_t _stride
+ , uint32_t _numStrides
+ )
{
- const uint8_t* src = (const uint8_t*)_src;
- uint8_t* dst = (uint8_t*)_dst;
-
- for (uint32_t ii = 0; ii < _num; ++ii)
+ if (_stride == _srcStride
+ && _stride == _dstStride)
{
- memCopy(dst, src, _size);
- src += _srcPitch;
- dst += _dstPitch;
+ memCopy(_dst, _src, _stride*_numStrides);
+ return;
}
- }
- ///
- void gather(void* _dst, const void* _src, uint32_t _size, uint32_t _num, uint32_t _srcPitch)
- {
- memCopy(_dst, _src, _size, _num, _srcPitch, _size);
- }
+ const uint8_t* src = (const uint8_t*)_src;
+ uint8_t* dst = (uint8_t*)_dst;
- ///
- void scatter(void* _dst, const void* _src, uint32_t _size, uint32_t _num, uint32_t _dstPitch)
- {
- memCopy(_dst, _src, _size, _num, _size, _dstPitch);
+ for (uint32_t ii = 0; ii < _numStrides; ++ii, src += _srcStride, dst += _dstStride)
+ {
+ memCopy(dst, src, _stride);
+ }
}
void memMoveRef(void* _dst, const void* _src, size_t _numBytes)
@@ -102,6 +101,31 @@ namespace bx
#endif // BX_CRT_NONE
}
+ void memMove(
+ void* _dst
+ , uint32_t _dstStride
+ , const void* _src
+ , uint32_t _srcStride
+ , uint32_t _stride
+ , uint32_t _numStrides
+ )
+ {
+ if (_stride == _srcStride
+ && _stride == _dstStride)
+ {
+ memMove(_dst, _src, _stride*_numStrides);
+ return;
+ }
+
+ const uint8_t* src = (const uint8_t*)_src;
+ uint8_t* dst = (uint8_t*)_dst;
+
+ for (uint32_t ii = 0; ii < _numStrides; ++ii, src += _srcStride, dst += _dstStride)
+ {
+ memMove(dst, src, _stride);
+ }
+ }
+
void memSetRef(void* _dst, uint8_t _ch, size_t _numBytes)
{
uint8_t* dst = (uint8_t*)_dst;
@@ -121,6 +145,22 @@ namespace bx
#endif // BX_CRT_NONE
}
+ void memSet(void* _dst, uint32_t _dstStride, uint8_t _ch, uint32_t _stride, uint32_t _num)
+ {
+ if (_stride == _dstStride)
+ {
+ memSet(_dst, _ch, _stride*_num);
+ return;
+ }
+
+ uint8_t* dst = (uint8_t*)_dst;
+
+ for (uint32_t ii = 0; ii < _num; ++ii, dst += _dstStride)
+ {
+ memSet(dst, _ch, _stride);
+ }
+ }
+
int32_t memCmpRef(const void* _lhs, const void* _rhs, size_t _numBytes)
{
const char* lhs = (const char*)_lhs;
@@ -144,4 +184,16 @@ namespace bx
#endif // BX_CRT_NONE
}
+ ///
+ void gather(void* _dst, const void* _src, uint32_t _srcStride, uint32_t _stride, uint32_t _numStrides)
+ {
+ memMove(_dst, _stride, _src, _srcStride, _stride, _numStrides);
+ }
+
+ ///
+ void scatter(void* _dst, uint32_t _dstStride, const void* _src, uint32_t _stride, uint32_t _numStrides)
+ {
+ memMove(_dst, _dstStride, _src, _stride, _stride, _numStrides);
+ }
+
} // namespace bx
diff --git a/3rdparty/bx/src/bx_p.h b/3rdparty/bx/src/bx_p.h
deleted file mode 100644
index d4b00084de3..00000000000
--- a/3rdparty/bx/src/bx_p.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright 2010-2018 Branimir Karadzic. All rights reserved.
- * License: https://github.com/bkaradzic/bx#license-bsd-2-clause
- */
-
-#ifndef BX_P_H_HEADER_GUARD
-#define BX_P_H_HEADER_GUARD
-
-#ifndef BX_CONFIG_DEBUG
-# define BX_CONFIG_DEBUG 0
-#endif // BX_CONFIG_DEBUG
-
-#if BX_CONFIG_DEBUG
-# define BX_TRACE _BX_TRACE
-# define BX_WARN _BX_WARN
-# define BX_CHECK _BX_CHECK
-# define BX_CONFIG_ALLOCATOR_DEBUG 1
-#endif // BX_CONFIG_DEBUG
-
-#define _BX_TRACE(_format, ...) \
- BX_MACRO_BLOCK_BEGIN \
- bx::debugPrintf(__FILE__ "(" BX_STRINGIZE(__LINE__) "): BX " _format "\n", ##__VA_ARGS__); \
- BX_MACRO_BLOCK_END
-
-#define _BX_WARN(_condition, _format, ...) \
- BX_MACRO_BLOCK_BEGIN \
- if (!BX_IGNORE_C4127(_condition) ) \
- { \
- BX_TRACE("WARN " _format, ##__VA_ARGS__); \
- } \
- BX_MACRO_BLOCK_END
-
-#define _BX_CHECK(_condition, _format, ...) \
- BX_MACRO_BLOCK_BEGIN \
- if (!BX_IGNORE_C4127(_condition) ) \
- { \
- BX_TRACE("CHECK " _format, ##__VA_ARGS__); \
- bx::debugBreak(); \
- } \
- BX_MACRO_BLOCK_END
-
-#include <bx/bx.h>
-#include <bx/debug.h>
-
-#endif // BX_P_H_HEADER_GUARD
diff --git a/3rdparty/bx/src/commandline.cpp b/3rdparty/bx/src/commandline.cpp
index df322560b56..ca31636ca76 100644
--- a/3rdparty/bx/src/commandline.cpp
+++ b/3rdparty/bx/src/commandline.cpp
@@ -1,9 +1,8 @@
/*
- * Copyright 2010-2018 Branimir Karadzic. All rights reserved.
- * License: https://github.com/bkaradzic/bx#license-bsd-2-clause
+ * Copyright 2010-2022 Branimir Karadzic. All rights reserved.
+ * License: https://github.com/bkaradzic/bx/blob/master/LICENSE
*/
-#include "bx_p.h"
#include <bx/commandline.h>
#include <bx/string.h>
@@ -39,7 +38,7 @@ namespace bx
switch (state)
{
case SkipWhitespace:
- for (; isSpace(*curr); ++curr) {}; // skip whitespace
+ for (; isSpace(*curr) && *curr!=_term; ++curr) {}; // skip whitespace
state = SetTerm;
break;
@@ -47,7 +46,7 @@ namespace bx
if ('"' == *curr)
{
term = '"';
- ++curr; // skip begining quote
+ ++curr; // skip beginning quote
}
else
{
diff --git a/3rdparty/bx/src/crtnone.cpp b/3rdparty/bx/src/crtnone.cpp
index 93579515c7f..6abdeeeb67f 100644
--- a/3rdparty/bx/src/crtnone.cpp
+++ b/3rdparty/bx/src/crtnone.cpp
@@ -1,9 +1,8 @@
/*
- * Copyright 2010-2018 Branimir Karadzic. All rights reserved.
- * License: https://github.com/bkaradzic/bx#license-bsd-2-clause
+ * Copyright 2010-2022 Branimir Karadzic. All rights reserved.
+ * License: https://github.com/bkaradzic/bx/blob/master/LICENSE
*/
-#include "bx_p.h"
#include <bx/debug.h>
#include <bx/file.h>
#include <bx/math.h>
@@ -75,7 +74,7 @@ extern "C" char* strcat(char* _dst, const char* _src)
extern "C" const char* strchr(const char* _str, int _ch)
{
- return bx::strFind(_str, _ch);
+ return bx::strFind(_str, _ch).getPtr();
}
extern "C" int32_t strcmp(const char* _lhs, const char* _rhs)
@@ -95,12 +94,12 @@ extern "C" int32_t strcasecmp(const char* _lhs, const char* _rhs)
extern "C" const char* strstr(const char* _str, const char* _find)
{
- return bx::strFind(_str, _find);
+ return bx::strFind(_str, _find).getPtr();
}
extern "C" void qsort(void* _base, size_t _num, size_t _size, bx::ComparisonFn _fn)
{
- BX_CHECK(_num <= UINT32_MAX && _size <= UINT32_MAX, "");
+ BX_ASSERT(_num <= UINT32_MAX && _size <= UINT32_MAX, "");
return bx::quickSort(_base, _num, _size, _fn);
}
@@ -338,6 +337,12 @@ extern "C" int fscanf(FILE* _stream, const char* _format, ...)
return -1;
}
+extern "C" int __isoc99_fscanf(FILE* _stream, const char* _format, ...)
+{
+ BX_UNUSED(_stream, _format);
+ return -1;
+}
+
FILE * stdout;
extern "C" FILE* fopen(const char* _filename, const char* _mode)
@@ -601,6 +606,11 @@ extern "C" void free(void* _ptr)
crt0::realloc(_ptr, 0);
}
+extern "C" void exit(int _exitCode)
+{
+ crt0::exit(_exitCode);
+}
+
#endif // BX_PLATFORM_*
extern "C" void abort(void)
@@ -621,6 +631,10 @@ void operator delete(void*)
{
}
+void operator delete(void*, size_t)
+{
+}
+
extern "C" void __cxa_pure_virtual(void)
{
}
diff --git a/3rdparty/bx/src/debug.cpp b/3rdparty/bx/src/debug.cpp
index 8e8bae122a6..062df287d7a 100644
--- a/3rdparty/bx/src/debug.cpp
+++ b/3rdparty/bx/src/debug.cpp
@@ -1,9 +1,8 @@
/*
- * Copyright 2010-2018 Branimir Karadzic. All rights reserved.
- * License: https://github.com/bkaradzic/bx#license-bsd-2-clause
+ * Copyright 2010-2022 Branimir Karadzic. All rights reserved.
+ * License: https://github.com/bkaradzic/bx/blob/master/LICENSE
*/
-#include "bx_p.h"
#include <bx/debug.h>
#include <bx/string.h> // isPrint
#include <bx/readerwriter.h> // WriterI
@@ -24,8 +23,8 @@ extern "C" __declspec(dllimport) void __stdcall OutputDebugStringA(const char* _
# include <CoreFoundation/CFString.h>
extern "C" void NSLog(CFStringRef _format, ...);
# endif // defined(__OBJC__)
-#elif 0 // BX_PLATFORM_EMSCRIPTEN
-# include <emscripten.h>
+#elif BX_PLATFORM_EMSCRIPTEN
+# include <emscripten/emscripten.h>
#else
# include <stdio.h> // fputs, fflush
#endif // BX_PLATFORM_WINDOWS
@@ -43,6 +42,17 @@ namespace bx
// NaCl doesn't like int 3:
// NativeClient: NaCl module load failed: Validation failure. File violates Native Client safety rules.
__asm__ ("int $3");
+#elif BX_PLATFORM_EMSCRIPTEN
+ emscripten_log(0
+ | EM_LOG_CONSOLE
+ | EM_LOG_ERROR
+ | EM_LOG_C_STACK
+ | EM_LOG_JS_STACK
+ , "debugBreak!"
+ );
+ // Doing emscripten_debugger() disables asm.js validation due to an emscripten bug
+ //emscripten_debugger();
+ EM_ASM({ debugger; });
#else // cross platform implementation
int* int3 = (int*)3L;
*int3 = 3;
@@ -69,7 +79,7 @@ namespace bx
# else
NSLog(__CFStringMakeConstantString("%s"), _out);
# endif // defined(__OBJC__)
-#elif 0 // BX_PLATFORM_EMSCRIPTEN
+#elif BX_PLATFORM_EMSCRIPTEN
emscripten_log(EM_LOG_CONSOLE, "%s", _out);
#else
fputs(_out, stdout);
@@ -137,7 +147,7 @@ namespace bx
if (NULL != _data)
{
- const uint8_t* data = reinterpret_cast<const uint8_t*>(_data);
+ const uint8_t* data = (const uint8_t*)_data;
char hex[HEX_DUMP_WIDTH*3+1];
char ascii[HEX_DUMP_WIDTH+1];
uint32_t hexPos = 0;
diff --git a/3rdparty/bx/src/dtoa.cpp b/3rdparty/bx/src/dtoa.cpp
index 3c23ea516e1..a36314ed98d 100644
--- a/3rdparty/bx/src/dtoa.cpp
+++ b/3rdparty/bx/src/dtoa.cpp
@@ -1,9 +1,8 @@
/*
- * Copyright 2010-2018 Branimir Karadzic. All rights reserved.
- * License: https://github.com/bkaradzic/bx#license-bsd-2-clause
+ * Copyright 2010-2022 Branimir Karadzic. All rights reserved.
+ * License: https://github.com/bkaradzic/bx/blob/master/LICENSE
*/
-#include "bx_p.h"
#include <bx/cpu.h>
#include <bx/math.h>
#include <bx/string.h>
@@ -74,8 +73,8 @@ namespace bx
DiyFp operator-(const DiyFp& rhs) const
{
- BX_CHECK(e == rhs.e, "");
- BX_CHECK(f >= rhs.f, "");
+ BX_ASSERT(e == rhs.e, "");
+ BX_ASSERT(f >= rhs.f, "");
return DiyFp(f - rhs.f, e);
}
@@ -224,7 +223,7 @@ namespace bx
uint32_t index = static_cast<uint32_t>( (k >> 3) + 1);
*K = -(-348 + static_cast<int32_t>(index << 3) ); // decimal exponent no need lookup table
- BX_CHECK(index < sizeof(s_kCachedPowers_F) / sizeof(s_kCachedPowers_F[0]), "");
+ BX_ASSERT(index < sizeof(s_kCachedPowers_F) / sizeof(s_kCachedPowers_F[0]), "");
return DiyFp(s_kCachedPowers_F[index], s_kCachedPowers_E[index]);
}
@@ -1120,7 +1119,7 @@ namespace bx
bool fromString(int32_t* _out, const StringView& _str)
{
- StringView str = bx::strLTrimSpace(_str);
+ StringView str = strLTrimSpace(_str);
const char* ptr = str.getPtr();
const char* term = str.getTerm();
diff --git a/3rdparty/bx/src/easing.cpp b/3rdparty/bx/src/easing.cpp
index e9f82b280de..38f35ec2cad 100644
--- a/3rdparty/bx/src/easing.cpp
+++ b/3rdparty/bx/src/easing.cpp
@@ -1,9 +1,8 @@
/*
- * Copyright 2010-2018 Branimir Karadzic. All rights reserved.
- * License: https://github.com/bkaradzic/bx#license-bsd-2-clause
+ * Copyright 2010-2022 Branimir Karadzic. All rights reserved.
+ * License: https://github.com/bkaradzic/bx/blob/master/LICENSE
*/
-#include "bx_p.h"
#include <bx/easing.h>
namespace bx
diff --git a/3rdparty/bx/src/file.cpp b/3rdparty/bx/src/file.cpp
index 8a282cab91f..dab862006ae 100644
--- a/3rdparty/bx/src/file.cpp
+++ b/3rdparty/bx/src/file.cpp
@@ -1,24 +1,33 @@
/*
- * Copyright 2010-2018 Branimir Karadzic. All rights reserved.
- * License: https://github.com/bkaradzic/bx#license-bsd-2-clause
+ * Copyright 2010-2022 Branimir Karadzic. All rights reserved.
+ * License: https://github.com/bkaradzic/bx/blob/master/LICENSE
*/
-#include "bx_p.h"
#include <bx/file.h>
+#ifndef BX_CONFIG_CRT_FILE_READER_WRITER
+# define BX_CONFIG_CRT_FILE_READER_WRITER !BX_CRT_NONE
+#endif // BX_CONFIG_CRT_FILE_READER_WRITER
+
+#ifndef BX_CONFIG_CRT_DIRECTORY_READER
+# define BX_CONFIG_CRT_DIRECTORY_READER (BX_PLATFORM_OS_DESKTOP && !BX_CRT_NONE)
+#endif // BX_CONFIG_CRT_DIRECTORY_READER
+
#if BX_CRT_NONE
# include "crt0.h"
#else
-# include <stdio.h>
-# include <sys/stat.h>
+# if BX_CONFIG_CRT_DIRECTORY_READER
+# include <dirent.h>
+# endif // BX_CONFIG_CRT_DIRECTORY_READER
+# include <stdio.h> // remove
+# include <sys/stat.h> // stat, mkdir
+# if BX_CRT_MSVC
+# include <direct.h> // _getcwd
+# else
+# include <unistd.h> // getcwd
+# endif // BX_CRT_MSVC
#endif // !BX_CRT_NONE
-#ifndef BX_CONFIG_CRT_FILE_READER_WRITER
-# define BX_CONFIG_CRT_FILE_READER_WRITER !(0 \
- || BX_CRT_NONE \
- )
-#endif // BX_CONFIG_CRT_FILE_READER_WRITER
-
namespace bx
{
class NoopWriterImpl : public FileWriterI
@@ -64,6 +73,7 @@ namespace bx
# elif 0 \
|| BX_PLATFORM_ANDROID \
|| BX_PLATFORM_BSD \
+ || BX_PLATFORM_HAIKU \
|| BX_PLATFORM_IOS \
|| BX_PLATFORM_OSX
# define fseeko64 fseeko
@@ -89,18 +99,18 @@ namespace bx
virtual bool open(const FilePath& _filePath, Error* _err) override
{
- BX_CHECK(NULL != _err, "Reader/Writer interface calling functions must handle errors.");
+ BX_ASSERT(NULL != _err, "Reader/Writer interface calling functions must handle errors.");
if (NULL != m_file)
{
- BX_ERROR_SET(_err, BX_ERROR_READERWRITER_ALREADY_OPEN, "FileReader: File is already open.");
+ BX_ERROR_SET(_err, kErrorReaderWriterAlreadyOpen, "FileReader: File is already open.");
return false;
}
- m_file = fopen(_filePath.get(), "rb");
+ m_file = fopen(_filePath.getCPtr(), "rb");
if (NULL == m_file)
{
- BX_ERROR_SET(_err, BX_ERROR_READERWRITER_OPEN, "FileReader: Failed to open file.");
+ BX_ERROR_SET(_err, kErrorReaderWriterOpen, "FileReader: Failed to open file.");
return false;
}
@@ -120,26 +130,26 @@ namespace bx
virtual int64_t seek(int64_t _offset, Whence::Enum _whence) override
{
- BX_CHECK(NULL != m_file, "Reader/Writer file is not open.");
+ BX_ASSERT(NULL != m_file, "Reader/Writer file is not open.");
fseeko64(m_file, _offset, _whence);
return ftello64(m_file);
}
virtual int32_t read(void* _data, int32_t _size, Error* _err) override
{
- BX_CHECK(NULL != m_file, "Reader/Writer file is not open.");
- BX_CHECK(NULL != _err, "Reader/Writer interface calling functions must handle errors.");
+ BX_ASSERT(NULL != m_file, "Reader/Writer file is not open.");
+ BX_ASSERT(NULL != _err, "Reader/Writer interface calling functions must handle errors.");
int32_t size = (int32_t)fread(_data, 1, _size, m_file);
if (size != _size)
{
if (0 != feof(m_file) )
{
- BX_ERROR_SET(_err, BX_ERROR_READERWRITER_EOF, "FileReader: EOF.");
+ BX_ERROR_SET(_err, kErrorReaderWriterEof, "FileReader: EOF.");
}
else if (0 != ferror(m_file) )
{
- BX_ERROR_SET(_err, BX_ERROR_READERWRITER_READ, "FileReader: read error.");
+ BX_ERROR_SET(_err, kErrorReaderWriterRead, "FileReader: read error.");
}
return size >= 0 ? size : 0;
@@ -169,19 +179,19 @@ namespace bx
virtual bool open(const FilePath& _filePath, bool _append, Error* _err) override
{
- BX_CHECK(NULL != _err, "Reader/Writer interface calling functions must handle errors.");
+ BX_ASSERT(NULL != _err, "Reader/Writer interface calling functions must handle errors.");
if (NULL != m_file)
{
- BX_ERROR_SET(_err, BX_ERROR_READERWRITER_ALREADY_OPEN, "FileReader: File is already open.");
+ BX_ERROR_SET(_err, kErrorReaderWriterAlreadyOpen, "FileReader: File is already open.");
return false;
}
- m_file = fopen(_filePath.get(), _append ? "ab" : "wb");
+ m_file = fopen(_filePath.getCPtr(), _append ? "ab" : "wb");
if (NULL == m_file)
{
- BX_ERROR_SET(_err, BX_ERROR_READERWRITER_OPEN, "FileWriter: Failed to open file.");
+ BX_ERROR_SET(_err, kErrorReaderWriterOpen, "FileWriter: Failed to open file.");
return false;
}
@@ -201,20 +211,20 @@ namespace bx
virtual int64_t seek(int64_t _offset, Whence::Enum _whence) override
{
- BX_CHECK(NULL != m_file, "Reader/Writer file is not open.");
+ BX_ASSERT(NULL != m_file, "Reader/Writer file is not open.");
fseeko64(m_file, _offset, _whence);
return ftello64(m_file);
}
virtual int32_t write(const void* _data, int32_t _size, Error* _err) override
{
- BX_CHECK(NULL != m_file, "Reader/Writer file is not open.");
- BX_CHECK(NULL != _err, "Reader/Writer interface calling functions must handle errors.");
+ BX_ASSERT(NULL != m_file, "Reader/Writer file is not open.");
+ BX_ASSERT(NULL != _err, "Reader/Writer interface calling functions must handle errors.");
int32_t size = (int32_t)fwrite(_data, 1, _size, m_file);
if (size != _size)
{
- BX_ERROR_SET(_err, BX_ERROR_READERWRITER_WRITE, "FileWriter: write failed.");
+ BX_ERROR_SET(_err, kErrorReaderWriterWrite, "FileWriter: write failed.");
return size >= 0 ? size : 0;
}
@@ -261,19 +271,19 @@ namespace bx
virtual bool open(const FilePath& _filePath, Error* _err) override
{
- BX_CHECK(NULL != _err, "Reader/Writer interface calling functions must handle errors.");
+ BX_ASSERT(NULL != _err, "Reader/Writer interface calling functions must handle errors.");
if (0 != m_fd)
{
- BX_ERROR_SET(_err, BX_ERROR_READERWRITER_ALREADY_OPEN, "FileReader: File is already open.");
+ BX_ERROR_SET(_err, kErrorReaderWriterAlreadyOpen, "FileReader: File is already open.");
return false;
}
- m_fd = crt0::open(_filePath.get(), crt0::Open::Read, 0);
+ m_fd = crt0::open(_filePath.getCPtr(), crt0::Open::Read, 0);
if (0 >= m_fd)
{
- BX_ERROR_SET(_err, BX_ERROR_READERWRITER_OPEN, "FileReader: Failed to open file.");
+ BX_ERROR_SET(_err, kErrorReaderWriterOpen, "FileReader: Failed to open file.");
return false;
}
@@ -293,14 +303,14 @@ namespace bx
virtual int64_t seek(int64_t _offset, Whence::Enum _whence) override
{
- BX_CHECK(0 != m_fd, "Reader/Writer file is not open.");
+ BX_ASSERT(0 != m_fd, "Reader/Writer file is not open.");
return crt0::seek(m_fd, _offset, crt0::Whence::Enum(_whence) );
}
virtual int32_t read(void* _data, int32_t _size, Error* _err) override
{
- BX_CHECK(0 != m_fd, "Reader/Writer file is not open.");
- BX_CHECK(NULL != _err, "Reader/Writer interface calling functions must handle errors.");
+ BX_ASSERT(0 != m_fd, "Reader/Writer file is not open.");
+ BX_ASSERT(NULL != _err, "Reader/Writer interface calling functions must handle errors.");
int32_t size = crt0::read(m_fd, _data, _size);
if (size != _size)
@@ -308,11 +318,11 @@ namespace bx
BX_UNUSED(_err);
// if (0 != feof(m_file) )
// {
-// BX_ERROR_SET(_err, BX_ERROR_READERWRITER_EOF, "FileReader: EOF.");
+// BX_ERROR_SET(_err, kErrorReaderWriterEof, "FileReader: EOF.");
// }
// else if (0 != ferror(m_file) )
// {
-// BX_ERROR_SET(_err, BX_ERROR_READERWRITER_READ, "FileReader: read error.");
+// BX_ERROR_SET(_err, kErrorReaderWriterRead, "FileReader: read error.");
// }
return size >= 0 ? size : 0;
@@ -342,19 +352,19 @@ namespace bx
virtual bool open(const FilePath& _filePath, bool _append, Error* _err) override
{
- BX_CHECK(NULL != _err, "Reader/Writer interface calling functions must handle errors.");
+ BX_ASSERT(NULL != _err, "Reader/Writer interface calling functions must handle errors.");
if (0 != m_fd)
{
- BX_ERROR_SET(_err, BX_ERROR_READERWRITER_ALREADY_OPEN, "FileReader: File is already open.");
+ BX_ERROR_SET(_err, kErrorReaderWriterAlreadyOpen, "FileReader: File is already open.");
return false;
}
- m_fd = crt0::open(_filePath.get(), _append ? crt0::Open::Append : crt0::Open::Write, 0600);
+ m_fd = crt0::open(_filePath.getCPtr(), _append ? crt0::Open::Append : crt0::Open::Write, 0600);
if (0 >= m_fd)
{
- BX_ERROR_SET(_err, BX_ERROR_READERWRITER_OPEN, "FileWriter: Failed to open file.");
+ BX_ERROR_SET(_err, kErrorReaderWriterOpen, "FileWriter: Failed to open file.");
return false;
}
@@ -374,19 +384,19 @@ namespace bx
virtual int64_t seek(int64_t _offset, Whence::Enum _whence) override
{
- BX_CHECK(0 != m_fd, "Reader/Writer file is not open.");
+ BX_ASSERT(0 != m_fd, "Reader/Writer file is not open.");
return crt0::seek(m_fd, _offset, crt0::Whence::Enum(_whence) );
}
virtual int32_t write(const void* _data, int32_t _size, Error* _err) override
{
- BX_CHECK(0 != m_fd, "Reader/Writer file is not open.");
- BX_CHECK(NULL != _err, "Reader/Writer interface calling functions must handle errors.");
+ BX_ASSERT(0 != m_fd, "Reader/Writer file is not open.");
+ BX_ASSERT(NULL != _err, "Reader/Writer interface calling functions must handle errors.");
int32_t size = crt0::write(m_fd, _data, _size);
if (size != _size)
{
- BX_ERROR_SET(_err, BX_ERROR_READERWRITER_WRITE, "FileWriter: write failed.");
+ BX_ERROR_SET(_err, kErrorReaderWriterWrite, "FileWriter: write failed.");
return size >= 0 ? size : 0;
}
@@ -553,18 +563,193 @@ namespace bx
return impl->write(_data, _size, _err);
}
- bool stat(const FilePath& _filePath, FileInfo& _outFileInfo)
+#if BX_CONFIG_CRT_DIRECTORY_READER
+
+ class DirectoryReaderImpl : public ReaderOpenI, public CloserI, public ReaderI
+ {
+ public:
+ DirectoryReaderImpl()
+ : m_dir(NULL)
+ , m_pos(0)
+ {
+ }
+
+ virtual ~DirectoryReaderImpl()
+ {
+ close();
+ }
+
+ virtual bool open(const FilePath& _filePath, Error* _err) override
+ {
+ BX_ASSERT(NULL != _err, "Reader/Writer interface calling functions must handle errors.");
+
+ m_dir = opendir(_filePath.getCPtr() );
+
+ if (NULL == m_dir)
+ {
+ BX_ERROR_SET(_err, kErrorReaderWriterOpen, "DirectoryReader: Failed to open directory.");
+ return false;
+ }
+
+ m_pos = 0;
+
+ return true;
+ }
+
+ virtual void close() override
+ {
+ if (NULL != m_dir)
+ {
+ closedir(m_dir);
+ m_dir = NULL;
+ }
+ }
+
+ virtual int32_t read(void* _data, int32_t _size, Error* _err) override
+ {
+ BX_ASSERT(NULL != _err, "Reader/Writer interface calling functions must handle errors.");
+
+ int32_t total = 0;
+
+ uint8_t* out = (uint8_t*)_data;
+
+ while (0 < _size)
+ {
+ if (0 == m_pos)
+ {
+ if (!fetch(m_cache, m_dir) )
+ {
+ BX_ERROR_SET(_err, kErrorReaderWriterEof, "DirectoryReader: EOF.");
+ return total;
+ }
+ }
+
+ const uint8_t* src = (const uint8_t*)&m_cache;
+ int32_t size = min<int32_t>(_size, sizeof(m_cache)-m_pos);
+ memCopy(&out[total], &src[m_pos], size);
+ total += size;
+ _size -= size;
+
+ m_pos += size;
+ m_pos %= sizeof(m_cache);
+ }
+
+ return total;
+ }
+
+ static bool fetch(FileInfo& _out, DIR* _dir)
+ {
+ for (;;)
+ {
+ const dirent* item = readdir(_dir);
+
+ if (NULL == item)
+ {
+ break;
+ }
+
+ if (0 != (item->d_type & DT_DIR) )
+ {
+ _out.type = FileType::Dir;
+ _out.size = UINT64_MAX;
+ _out.filePath.set(item->d_name);
+ return true;
+ }
+
+ if (0 != (item->d_type & DT_REG) )
+ {
+ _out.type = FileType::File;
+ _out.size = UINT64_MAX;
+ _out.filePath.set(item->d_name);
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ FileInfo m_cache;
+ DIR* m_dir;
+ int32_t m_pos;
+ };
+
+#else
+
+ class DirectoryReaderImpl : public ReaderOpenI, public CloserI, public ReaderI
+ {
+ public:
+ DirectoryReaderImpl()
+ {
+ }
+
+ virtual ~DirectoryReaderImpl()
+ {
+ }
+
+ virtual bool open(const FilePath& _filePath, Error* _err) override
+ {
+ BX_UNUSED(_filePath);
+ BX_ERROR_SET(_err, kErrorReaderWriterOpen, "DirectoryReader: Failed to open directory.");
+ return false;
+ }
+
+ virtual void close() override
+ {
+ }
+
+ virtual int32_t read(void* _data, int32_t _size, Error* _err) override
+ {
+ BX_UNUSED(_data, _size);
+ BX_ASSERT(NULL != _err, "Reader/Writer interface calling functions must handle errors.");
+ BX_ERROR_SET(_err, kErrorReaderWriterEof, "DirectoryReader: EOF.");
+ return 0;
+ }
+ };
+
+#endif // BX_CONFIG_CRT_DIRECTORY_READER
+
+ DirectoryReader::DirectoryReader()
+ {
+ BX_STATIC_ASSERT(sizeof(DirectoryReaderImpl) <= sizeof(m_internal) );
+ BX_PLACEMENT_NEW(m_internal, DirectoryReaderImpl);
+ }
+
+ DirectoryReader::~DirectoryReader()
+ {
+ DirectoryReaderImpl* impl = reinterpret_cast<DirectoryReaderImpl*>(m_internal);
+ impl->~DirectoryReaderImpl();
+ }
+
+ bool DirectoryReader::open(const FilePath& _filePath, Error* _err)
+ {
+ DirectoryReaderImpl* impl = reinterpret_cast<DirectoryReaderImpl*>(m_internal);
+ return impl->open(_filePath, _err);
+ }
+
+ void DirectoryReader::close()
+ {
+ DirectoryReaderImpl* impl = reinterpret_cast<DirectoryReaderImpl*>(m_internal);
+ impl->close();
+ }
+
+ int32_t DirectoryReader::read(void* _data, int32_t _size, Error* _err)
+ {
+ DirectoryReaderImpl* impl = reinterpret_cast<DirectoryReaderImpl*>(m_internal);
+ return impl->read(_data, _size, _err);
+ }
+
+ bool stat(FileInfo& _outFileInfo, const FilePath& _filePath)
{
#if BX_CRT_NONE
BX_UNUSED(_filePath, _outFileInfo);
return false;
#else
- _outFileInfo.m_size = 0;
- _outFileInfo.m_type = FileInfo::Count;
+ _outFileInfo.size = 0;
+ _outFileInfo.type = FileType::Count;
# if BX_COMPILER_MSVC
struct ::_stat64 st;
- int32_t result = ::_stat64(_filePath.get(), &st);
+ int32_t result = ::_stat64(_filePath.getCPtr(), &st);
if (0 != result)
{
@@ -573,15 +758,15 @@ namespace bx
if (0 != (st.st_mode & _S_IFREG) )
{
- _outFileInfo.m_type = FileInfo::Regular;
+ _outFileInfo.type = FileType::File;
}
else if (0 != (st.st_mode & _S_IFDIR) )
{
- _outFileInfo.m_type = FileInfo::Directory;
+ _outFileInfo.type = FileType::Dir;
}
# else
struct ::stat st;
- int32_t result = ::stat(_filePath.get(), &st);
+ int32_t result = ::stat(_filePath.getCPtr(), &st);
if (0 != result)
{
return false;
@@ -589,18 +774,185 @@ namespace bx
if (0 != (st.st_mode & S_IFREG) )
{
- _outFileInfo.m_type = FileInfo::Regular;
+ _outFileInfo.type = FileType::File;
}
else if (0 != (st.st_mode & S_IFDIR) )
{
- _outFileInfo.m_type = FileInfo::Directory;
+ _outFileInfo.type = FileType::Dir;
}
# endif // BX_COMPILER_MSVC
- _outFileInfo.m_size = st.st_size;
+ _outFileInfo.size = st.st_size;
return true;
#endif // BX_CRT_NONE
}
+ bool make(const FilePath& _filePath, Error* _err)
+ {
+ BX_ERROR_SCOPE(_err);
+
+ if (!_err->isOk() )
+ {
+ return false;
+ }
+
+#if BX_CRT_MSVC
+ int32_t result = ::_mkdir(_filePath.getCPtr() );
+#elif BX_CRT_MINGW
+ int32_t result = ::mkdir(_filePath.getCPtr());
+#elif BX_CRT_NONE
+ BX_UNUSED(_filePath);
+ int32_t result = -1;
+#else
+ int32_t result = ::mkdir(_filePath.getCPtr(), 0700);
+#endif // BX_CRT_MSVC
+
+ if (0 != result)
+ {
+ BX_ERROR_SET(_err, kErrorAccess, "The parent directory does not allow write permission to the process.");
+ return false;
+ }
+
+ return true;
+ }
+
+ bool makeAll(const FilePath& _filePath, Error* _err)
+ {
+ BX_ERROR_SCOPE(_err);
+
+ if (!_err->isOk() )
+ {
+ return false;
+ }
+
+ FileInfo fi;
+
+ if (stat(fi, _filePath) )
+ {
+ if (FileType::Dir == fi.type)
+ {
+ return true;
+ }
+
+ BX_ERROR_SET(_err, kErrorNotDirectory, "File already exist, and is not directory.");
+ return false;
+ }
+
+ const StringView dir = strRTrim(_filePath, "/");
+ const StringView slash = strRFind(dir, '/');
+
+ if (!slash.isEmpty()
+ && slash.getPtr() - dir.getPtr() > 1)
+ {
+ if (!makeAll(StringView(dir.getPtr(), slash.getPtr() ), _err) )
+ {
+ return false;
+ }
+ }
+
+ FilePath path(dir);
+ return make(path, _err);
+ }
+
+ bool remove(const FilePath& _filePath, Error* _err)
+ {
+ BX_ERROR_SCOPE(_err);
+
+ if (!_err->isOk() )
+ {
+ return false;
+ }
+
+#if BX_CRT_MSVC
+ int32_t result = -1;
+ FileInfo fi;
+ if (stat(fi, _filePath) )
+ {
+ if (FileType::Dir == fi.type)
+ {
+ result = ::_rmdir(_filePath.getCPtr() );
+ }
+ else
+ {
+ result = ::remove(_filePath.getCPtr() );
+ }
+ }
+#elif BX_CRT_NONE
+ BX_UNUSED(_filePath);
+ int32_t result = -1;
+#else
+ int32_t result = ::remove(_filePath.getCPtr() );
+#endif // BX_CRT_MSVC
+
+ if (0 != result)
+ {
+ BX_ERROR_SET(_err, kErrorAccess, "The parent directory does not allow write permission to the process.");
+ return false;
+ }
+
+ return true;
+ }
+
+ bool removeAll(const FilePath& _filePath, Error* _err)
+ {
+ BX_ERROR_SCOPE(_err);
+
+ if (remove(_filePath, _err) )
+ {
+ return true;
+ }
+
+ _err->reset();
+
+ FileInfo fi;
+
+ if (!stat(fi, _filePath) )
+ {
+ BX_ERROR_SET(_err, kErrorAccess, "The parent directory does not allow write permission to the process.");
+ return false;
+ }
+
+ if (FileType::Dir != fi.type)
+ {
+ BX_ERROR_SET(_err, kErrorNotDirectory, "File already exist, and is not directory.");
+ return false;
+ }
+
+ Error err;
+ DirectoryReader dr;
+
+ if (!open(&dr, _filePath, &err) )
+ {
+ BX_ERROR_SET(_err, kErrorNotDirectory, "File already exist, and is not directory.");
+ return false;
+ }
+
+ while (err.isOk() )
+ {
+ read(&dr, fi, &err);
+
+ if (err.isOk() )
+ {
+ if (0 == strCmp(fi.filePath, ".")
+ || 0 == strCmp(fi.filePath, "..") )
+ {
+ continue;
+ }
+
+ FilePath path(_filePath);
+ path.join(fi.filePath);
+ if (!removeAll(path, _err) )
+ {
+ _err->reset();
+ break;
+ }
+ }
+ }
+
+ close(&dr);
+
+ return remove(_filePath, _err);
+ }
+
} // namespace bx
diff --git a/3rdparty/bx/src/filepath.cpp b/3rdparty/bx/src/filepath.cpp
index 0ee2fc171ad..892bf80e48c 100644
--- a/3rdparty/bx/src/filepath.cpp
+++ b/3rdparty/bx/src/filepath.cpp
@@ -1,24 +1,19 @@
/*
- * Copyright 2010-2018 Branimir Karadzic. All rights reserved.
- * License: https://github.com/bkaradzic/bx#license-bsd-2-clause
+ * Copyright 2010-2022 Branimir Karadzic. All rights reserved.
+ * License: https://github.com/bkaradzic/bx/blob/master/LICENSE
*/
-#include "bx_p.h"
#include <bx/file.h>
#include <bx/os.h>
#include <bx/readerwriter.h>
#if !BX_CRT_NONE
-# include <stdio.h> // remove
-# include <dirent.h> // opendir
-
# if BX_CRT_MSVC
# include <direct.h> // _getcwd
# else
-# include <sys/stat.h> // mkdir
# include <unistd.h> // getcwd
# endif // BX_CRT_MSVC
-#endif // 0
+#endif // !BX_CRT_NONE
#if BX_PLATFORM_WINDOWS
extern "C" __declspec(dllimport) unsigned long __stdcall GetTempPathA(unsigned long _max, char* _ptr);
@@ -154,7 +149,7 @@ namespace bx
return size;
}
- static bool getEnv(char* _out, uint32_t* _inOutSize, const StringView& _name, FileInfo::Enum _type)
+ static bool getEnv(char* _out, uint32_t* _inOutSize, const StringView& _name, FileType::Enum _type)
{
uint32_t len = *_inOutSize;
*_out = '\0';
@@ -162,8 +157,8 @@ namespace bx
if (getEnv(_out, &len, _name) )
{
FileInfo fi;
- if (stat(_out, fi)
- && _type == fi.m_type)
+ if (stat(fi, _out)
+ && _type == fi.type)
{
*_inOutSize = len;
return true;
@@ -204,9 +199,9 @@ namespace bx
{
return false
#if BX_PLATFORM_WINDOWS
- || getEnv(_out, _inOutSize, "USERPROFILE", FileInfo::Directory)
+ || getEnv(_out, _inOutSize, "USERPROFILE", FileType::Dir)
#endif // BX_PLATFORM_WINDOWS
- || getEnv(_out, _inOutSize, "HOME", FileInfo::Directory)
+ || getEnv(_out, _inOutSize, "HOME", FileType::Dir)
;
}
@@ -232,7 +227,7 @@ namespace bx
{
uint32_t len = *_inOutSize;
*_out = '\0';
- bool ok = getEnv(_out, &len, *tmp, FileInfo::Directory);
+ bool ok = getEnv(_out, &len, *tmp, FileType::Dir);
if (ok
&& len != 0
@@ -244,8 +239,8 @@ namespace bx
}
FileInfo fi;
- if (stat("/tmp", fi)
- && FileInfo::Directory == fi.m_type)
+ if (stat(fi, "/tmp")
+ && FileType::Dir == fi.type)
{
strCopy(_out, *_inOutSize, "/tmp");
*_inOutSize = 4;
@@ -336,7 +331,12 @@ namespace bx
set(tmp);
}
- const char* FilePath::get() const
+ FilePath::operator StringView() const
+ {
+ return StringView(m_filePath, strLen(m_filePath) );
+ }
+
+ const char* FilePath::getCPtr() const
{
return m_filePath;
}
@@ -360,7 +360,7 @@ namespace bx
return StringView(fileName.getPtr()+1);
}
- return get();
+ return getCPtr();
}
StringView FilePath::getBaseName() const
@@ -385,7 +385,8 @@ namespace bx
const StringView fileName = getFileName();
if (!fileName.isEmpty() )
{
- return strFind(fileName, '.');
+ const StringView dot = strFind(fileName, '.');
+ return StringView(dot.getPtr(), fileName.getTerm() );
}
return StringView();
@@ -403,171 +404,4 @@ namespace bx
return 0 == strCmp(m_filePath, ".");
}
- bool make(const FilePath& _filePath, Error* _err)
- {
- BX_ERROR_SCOPE(_err);
-
- if (!_err->isOk() )
- {
- return false;
- }
-
-#if BX_CRT_MSVC
- int32_t result = ::_mkdir(_filePath.get() );
-#elif BX_CRT_MINGW
- int32_t result = ::mkdir(_filePath.get());
-#elif BX_CRT_NONE
- BX_UNUSED(_filePath);
- int32_t result = -1;
-#else
- int32_t result = ::mkdir(_filePath.get(), 0700);
-#endif // BX_CRT_MSVC
-
- if (0 != result)
- {
- BX_ERROR_SET(_err, BX_ERROR_ACCESS, "The parent directory does not allow write permission to the process.");
- return false;
- }
-
- return true;
- }
-
- bool makeAll(const FilePath& _filePath, Error* _err)
- {
- BX_ERROR_SCOPE(_err);
-
- if (!_err->isOk() )
- {
- return false;
- }
-
- FileInfo fi;
-
- if (stat(_filePath, fi) )
- {
- if (FileInfo::Directory == fi.m_type)
- {
- return true;
- }
-
- BX_ERROR_SET(_err, BX_ERROR_NOT_DIRECTORY, "File already exist, and is not directory.");
- return false;
- }
-
- const StringView dir = strRTrim(_filePath.get(), "/");
- const StringView slash = strRFind(dir, '/');
-
- if (!slash.isEmpty()
- && slash.getPtr() - dir.getPtr() > 1)
- {
- if (!makeAll(StringView(dir.getPtr(), slash.getPtr() ), _err) )
- {
- return false;
- }
- }
-
- FilePath path(dir);
- return make(path, _err);
- }
-
- bool remove(const FilePath& _filePath, Error* _err)
- {
- BX_ERROR_SCOPE(_err);
-
- if (!_err->isOk() )
- {
- return false;
- }
-
-#if BX_CRT_MSVC
- int32_t result = -1;
- FileInfo fi;
- if (stat(_filePath, fi) )
- {
- if (FileInfo::Directory == fi.m_type)
- {
- result = ::_rmdir(_filePath.get() );
- }
- else
- {
- result = ::remove(_filePath.get() );
- }
- }
-#elif BX_CRT_NONE
- BX_UNUSED(_filePath);
- int32_t result = -1;
-#else
- int32_t result = ::remove(_filePath.get() );
-#endif // BX_CRT_MSVC
-
- if (0 != result)
- {
- BX_ERROR_SET(_err, BX_ERROR_ACCESS, "The parent directory does not allow write permission to the process.");
- return false;
- }
-
- return true;
- }
-
- bool removeAll(const FilePath& _filePath, Error* _err)
- {
- BX_ERROR_SCOPE(_err);
-
- if (remove(_filePath, _err) )
- {
- return true;
- }
-
- _err->reset();
-
- FileInfo fi;
-
- if (!stat(_filePath, fi) )
- {
- BX_ERROR_SET(_err, BX_ERROR_ACCESS, "The parent directory does not allow write permission to the process.");
- return false;
- }
-
- if (FileInfo::Directory != fi.m_type)
- {
- BX_ERROR_SET(_err, BX_ERROR_NOT_DIRECTORY, "File already exist, and is not directory.");
- return false;
- }
-
-#if BX_CRT_NONE
- BX_UNUSED(_filePath);
- return false;
-#elif BX_PLATFORM_WINDOWS \
- || BX_PLATFORM_LINUX \
- || BX_PLATFORM_OSX
- DIR* dir = opendir(_filePath.get() );
- if (NULL == dir)
- {
- BX_ERROR_SET(_err, BX_ERROR_NOT_DIRECTORY, "File already exist, and is not directory.");
- return false;
- }
-
- for (dirent* item = readdir(dir); NULL != item; item = readdir(dir) )
- {
- if (0 == strCmp(item->d_name, ".")
- || 0 == strCmp(item->d_name, "..") )
- {
- continue;
- }
-
- FilePath path(_filePath);
- path.join(item->d_name);
- if (!removeAll(path, _err) )
- {
- _err->reset();
- break;
- }
- }
-
- closedir(dir);
-#endif // !BX_CRT_NONE
-
- return remove(_filePath, _err);
- }
-
} // namespace bx
diff --git a/3rdparty/bx/src/hash.cpp b/3rdparty/bx/src/hash.cpp
index 7ae5e39cc80..0fcfaaca6c9 100644
--- a/3rdparty/bx/src/hash.cpp
+++ b/3rdparty/bx/src/hash.cpp
@@ -1,9 +1,8 @@
/*
- * Copyright 2011-2018 Branimir Karadzic. All rights reserved.
- * License: https://github.com/bkaradzic/bx#license-bsd-2-clause
+ * Copyright 2011-2022 Branimir Karadzic. All rights reserved.
+ * License: https://github.com/bkaradzic/bx/blob/master/LICENSE
*/
-#include "bx_p.h"
#include <bx/hash.h>
namespace bx
@@ -134,7 +133,7 @@ void HashCrc32::begin(Enum _type)
m_table = s_crcTable[_type];
}
-void HashCrc32::add(const void* _data, int _len)
+void HashCrc32::add(const void* _data, int32_t _len)
{
const uint8_t* data = (const uint8_t*)_data;
@@ -148,4 +147,122 @@ void HashCrc32::add(const void* _data, int _len)
m_hash = hash;
}
+struct HashMurmur2APod
+{
+ uint32_t m_hash;
+ uint32_t m_tail;
+ uint32_t m_count;
+ uint32_t m_size;
+};
+BX_STATIC_ASSERT(sizeof(HashMurmur2A) == sizeof(HashMurmur2APod) );
+
+BX_FORCE_INLINE void mmix(uint32_t& _h, uint32_t& _k)
+{
+ constexpr uint32_t kMurmurMul = 0x5bd1e995;
+ constexpr uint32_t kMurmurRightShift = 24;
+
+ _k *= kMurmurMul;
+ _k ^= _k >> kMurmurRightShift;
+ _k *= kMurmurMul;
+ _h *= kMurmurMul;
+ _h ^= _k;
+}
+
+static void mixTail(HashMurmur2APod& _self, const uint8_t*& _data, int32_t& _len)
+{
+ while (_len
+ && ( (_len<4) || _self.m_count)
+ )
+ {
+ _self.m_tail |= (*_data++) << (_self.m_count * 8);
+
+ _self.m_count++;
+ _len--;
+
+ if (_self.m_count == 4)
+ {
+ mmix(_self.m_hash, _self.m_tail);
+ _self.m_tail = 0;
+ _self.m_count = 0;
+ }
+ }
+}
+
+BX_FORCE_INLINE uint32_t readAligned(const uint8_t* _data)
+{
+ return *(uint32_t*)_data;
+}
+
+BX_FORCE_INLINE uint32_t readUnaligned(const uint8_t* _data)
+{
+ if (BX_ENABLED(BX_CPU_ENDIAN_BIG) )
+ {
+ return 0
+ | _data[0]<<24
+ | _data[1]<<16
+ | _data[2]<<8
+ | _data[3]
+ ;
+ }
+ else
+ {
+ return 0
+ | _data[0]
+ | _data[1]<<8
+ | _data[2]<<16
+ | _data[3]<<24
+ ;
+ }
+}
+
+typedef uint32_t (*ReadDataFn)(const uint8_t* _data);
+
+template<ReadDataFn FnT>
+static void addData(HashMurmur2APod& _self, const uint8_t* _data, int32_t _len)
+{
+ while (_len >= 4)
+ {
+ uint32_t kk = FnT(_data);
+
+ mmix(_self.m_hash, kk);
+
+ _data += 4;
+ _len -= 4;
+ }
+
+ mixTail(_self, _data, _len);
+}
+
+void HashMurmur2A::add(const void* _data, int32_t _len)
+{
+ HashMurmur2APod& self = *(HashMurmur2APod*)this;
+
+ const uint8_t* data = (const uint8_t*)_data;
+
+ m_size += _len;
+ mixTail(self, data, _len);
+
+ if (BX_UNLIKELY(!isAligned(data, 4) ) )
+ {
+ addData<readUnaligned>(self, data, _len);
+ return;
+ }
+
+ addData<readAligned>(self, data, _len);
+}
+
+uint32_t HashMurmur2A::end()
+{
+ constexpr uint32_t kMurmurMul = 0x5bd1e995;
+
+ mmix(m_hash, m_tail);
+ mmix(m_hash, m_size);
+
+ m_hash ^= m_hash >> 13;
+ m_hash *= kMurmurMul;
+ m_hash ^= m_hash >> 15;
+
+ return m_hash;
+}
+
} // namespace bx
diff --git a/3rdparty/bx/src/math.cpp b/3rdparty/bx/src/math.cpp
index ba0676e96bf..8975d5bed25 100644
--- a/3rdparty/bx/src/math.cpp
+++ b/3rdparty/bx/src/math.cpp
@@ -1,12 +1,13 @@
/*
- * Copyright 2011-2018 Branimir Karadzic. All rights reserved.
- * License: https://github.com/bkaradzic/bx#license-bsd-2-clause
+ * Copyright 2011-2022 Branimir Karadzic. All rights reserved.
+ * License: https://github.com/bkaradzic/bx/blob/master/LICENSE
*/
-#include "bx_p.h"
#include <bx/math.h>
#include <bx/uint32_t.h>
+#include <bx/string.h>
+
namespace bx
{
const float kInfinity = bitsToFloat(UINT32_C(0x7f800000) );
@@ -113,7 +114,7 @@ namespace bx
if (maxaxy == 0.0f)
{
- return 0.0f*sign(_y);
+ return _y < 0.0f ? -0.0f : 0.0f;
}
const float mxy = minaxy / maxaxy;
@@ -126,7 +127,7 @@ namespace bx
const float tmp5 = tmp4 * mxy;
const float tmp6 = ay > ax ? kPiHalf - tmp5 : tmp5;
const float tmp7 = _x < 0.0f ? kPi - tmp6 : tmp6;
- const float result = sign(_y)*tmp7;
+ const float result = _y < 0.0f ? -tmp7 : tmp7;
return result;
}
@@ -239,87 +240,53 @@ namespace bx
return result;
}
- BX_CONST_FUNC float floor(float _a)
+ void mtxLookAt(float* _result, const Vec3& _eye, const Vec3& _at, const Vec3& _up, Handedness::Enum _handedness)
{
- if (_a < 0.0f)
- {
- const float fr = fract(-_a);
- const float result = -_a - fr;
-
- return -(0.0f != fr
- ? result + 1.0f
- : result)
- ;
- }
-
- return _a - fract(_a);
- }
-
- static void mtxLookAtImpl(float* _result, const Vec3& _eye, const Vec3& _view, const Vec3& _up)
- {
- const Vec3 uxv = cross(_up, _view);
+ const Vec3 view = normalize(
+ Handedness::Right == _handedness
+ ? sub(_eye, _at)
+ : sub(_at, _eye)
+ );
+ const Vec3 uxv = cross(_up, view);
const Vec3 right = normalize(uxv);
- const Vec3 up = cross(_view, right);
+ const Vec3 up = cross(view, right);
memSet(_result, 0, sizeof(float)*16);
_result[ 0] = right.x;
_result[ 1] = up.x;
- _result[ 2] = _view.x;
+ _result[ 2] = view.x;
_result[ 4] = right.y;
_result[ 5] = up.y;
- _result[ 6] = _view.y;
+ _result[ 6] = view.y;
_result[ 8] = right.z;
_result[ 9] = up.z;
- _result[10] = _view.z;
+ _result[10] = view.z;
_result[12] = -dot(right, _eye);
- _result[13] = -dot(up, _eye);
- _result[14] = -dot(_view, _eye);
+ _result[13] = -dot(up, _eye);
+ _result[14] = -dot(view, _eye);
_result[15] = 1.0f;
}
- void mtxLookAtLh(float* _result, const Vec3& _eye, const Vec3& _at, const Vec3& _up)
- {
- const Vec3 tmp = sub(_at, _eye);
- const Vec3 view = normalize(tmp);
-
- mtxLookAtImpl(_result, _eye, view, _up);
- }
-
- void mtxLookAtRh(float* _result, const Vec3& _eye, const Vec3& _at, const Vec3& _up)
- {
- const Vec3 tmp = sub(_eye, _at);
- const Vec3 view = normalize(tmp);
-
- mtxLookAtImpl(_result, _eye, view, _up);
- }
-
- void mtxLookAt(float* _result, const Vec3& _eye, const Vec3& _at, const Vec3& _up)
- {
- mtxLookAtLh(_result, _eye, _at, _up);
- }
-
- template<Handness::Enum HandnessT>
- void mtxProjXYWH(float* _result, float _x, float _y, float _width, float _height, float _near, float _far, bool _oglNdc)
+ static void mtxProjXYWH(float* _result, float _x, float _y, float _width, float _height, float _near, float _far, bool _homogeneousNdc, Handedness::Enum _handedness)
{
const float diff = _far-_near;
- const float aa = _oglNdc ? ( _far+_near)/diff : _far/diff;
- const float bb = _oglNdc ? (2.0f*_far*_near)/diff : _near*aa;
+ const float aa = _homogeneousNdc ? ( _far+_near)/diff : _far/diff;
+ const float bb = _homogeneousNdc ? (2.0f*_far*_near)/diff : _near*aa;
memSet(_result, 0, sizeof(float)*16);
_result[ 0] = _width;
_result[ 5] = _height;
- _result[ 8] = (Handness::Right == HandnessT) ? _x : -_x;
- _result[ 9] = (Handness::Right == HandnessT) ? _y : -_y;
- _result[10] = (Handness::Right == HandnessT) ? -aa : aa;
- _result[11] = (Handness::Right == HandnessT) ? -1.0f : 1.0f;
+ _result[ 8] = (Handedness::Right == _handedness) ? _x : -_x;
+ _result[ 9] = (Handedness::Right == _handedness) ? _y : -_y;
+ _result[10] = (Handedness::Right == _handedness) ? -aa : aa;
+ _result[11] = (Handedness::Right == _handedness) ? -1.0f : 1.0f;
_result[14] = -bb;
}
- template<Handness::Enum HandnessT>
- void mtxProjImpl(float* _result, float _ut, float _dt, float _lt, float _rt, float _near, float _far, bool _oglNdc)
+ void mtxProj(float* _result, float _ut, float _dt, float _lt, float _rt, float _near, float _far, bool _homogeneousNdc, Handedness::Enum _handedness)
{
const float invDiffRl = 1.0f/(_rt - _lt);
const float invDiffUd = 1.0f/(_ut - _dt);
@@ -327,96 +294,47 @@ namespace bx
const float height = 2.0f*_near * invDiffUd;
const float xx = (_rt + _lt) * invDiffRl;
const float yy = (_ut + _dt) * invDiffUd;
- mtxProjXYWH<HandnessT>(_result, xx, yy, width, height, _near, _far, _oglNdc);
+ mtxProjXYWH(_result, xx, yy, width, height, _near, _far, _homogeneousNdc, _handedness);
}
- template<Handness::Enum HandnessT>
- void mtxProjImpl(float* _result, const float _fov[4], float _near, float _far, bool _oglNdc)
+ void mtxProj(float* _result, const float _fov[4], float _near, float _far, bool _homogeneousNdc, Handedness::Enum _handedness)
{
- mtxProjImpl<HandnessT>(_result, _fov[0], _fov[1], _fov[2], _fov[3], _near, _far, _oglNdc);
+ mtxProj(_result, _fov[0], _fov[1], _fov[2], _fov[3], _near, _far, _homogeneousNdc, _handedness);
}
- template<Handness::Enum HandnessT>
- void mtxProjImpl(float* _result, float _fovy, float _aspect, float _near, float _far, bool _oglNdc)
+ void mtxProj(float* _result, float _fovy, float _aspect, float _near, float _far, bool _homogeneousNdc, Handedness::Enum _handedness)
{
const float height = 1.0f/tan(toRad(_fovy)*0.5f);
const float width = height * 1.0f/_aspect;
- mtxProjXYWH<HandnessT>(_result, 0.0f, 0.0f, width, height, _near, _far, _oglNdc);
+ mtxProjXYWH(_result, 0.0f, 0.0f, width, height, _near, _far, _homogeneousNdc, _handedness);
}
- void mtxProj(float* _result, float _ut, float _dt, float _lt, float _rt, float _near, float _far, bool _oglNdc)
- {
- mtxProjImpl<Handness::Left>(_result, _ut, _dt, _lt, _rt, _near, _far, _oglNdc);
- }
-
- void mtxProj(float* _result, const float _fov[4], float _near, float _far, bool _oglNdc)
- {
- mtxProjImpl<Handness::Left>(_result, _fov, _near, _far, _oglNdc);
- }
-
- void mtxProj(float* _result, float _fovy, float _aspect, float _near, float _far, bool _oglNdc)
- {
- mtxProjImpl<Handness::Left>(_result, _fovy, _aspect, _near, _far, _oglNdc);
- }
-
- void mtxProjLh(float* _result, float _ut, float _dt, float _lt, float _rt, float _near, float _far, bool _oglNdc)
- {
- mtxProjImpl<Handness::Left>(_result, _ut, _dt, _lt, _rt, _near, _far, _oglNdc);
- }
-
- void mtxProjLh(float* _result, const float _fov[4], float _near, float _far, bool _oglNdc)
- {
- mtxProjImpl<Handness::Left>(_result, _fov, _near, _far, _oglNdc);
- }
-
- void mtxProjLh(float* _result, float _fovy, float _aspect, float _near, float _far, bool _oglNdc)
- {
- mtxProjImpl<Handness::Left>(_result, _fovy, _aspect, _near, _far, _oglNdc);
- }
-
- void mtxProjRh(float* _result, float _ut, float _dt, float _lt, float _rt, float _near, float _far, bool _oglNdc)
- {
- mtxProjImpl<Handness::Right>(_result, _ut, _dt, _lt, _rt, _near, _far, _oglNdc);
- }
-
- void mtxProjRh(float* _result, const float _fov[4], float _near, float _far, bool _oglNdc)
- {
- mtxProjImpl<Handness::Right>(_result, _fov, _near, _far, _oglNdc);
- }
-
- void mtxProjRh(float* _result, float _fovy, float _aspect, float _near, float _far, bool _oglNdc)
- {
- mtxProjImpl<Handness::Right>(_result, _fovy, _aspect, _near, _far, _oglNdc);
- }
-
- template<NearFar::Enum NearFarT, Handness::Enum HandnessT>
- void mtxProjInfXYWH(float* _result, float _x, float _y, float _width, float _height, float _near, bool _oglNdc)
+ static void mtxProjInfXYWH(float* _result, float _x, float _y, float _width, float _height, float _near, bool _homogeneousNdc, Handedness::Enum _handedness, NearFar::Enum _nearFar)
{
float aa;
float bb;
- if (BX_ENABLED(NearFar::Reverse == NearFarT) )
+ if (NearFar::Reverse == _nearFar)
{
- aa = _oglNdc ? -1.0f : 0.0f;
- bb = _oglNdc ? -2.0f*_near : -_near;
+ aa = _homogeneousNdc ? -1.0f : 0.0f;
+ bb = _homogeneousNdc ? -2.0f*_near : -_near;
}
else
{
aa = 1.0f;
- bb = _oglNdc ? 2.0f*_near : _near;
+ bb = _homogeneousNdc ? 2.0f*_near : _near;
}
memSet(_result, 0, sizeof(float)*16);
_result[ 0] = _width;
_result[ 5] = _height;
- _result[ 8] = (Handness::Right == HandnessT) ? _x : -_x;
- _result[ 9] = (Handness::Right == HandnessT) ? _y : -_y;
- _result[10] = (Handness::Right == HandnessT) ? -aa : aa;
- _result[11] = (Handness::Right == HandnessT) ? -1.0f : 1.0f;
+ _result[ 8] = (Handedness::Right == _handedness) ? _x : -_x;
+ _result[ 9] = (Handedness::Right == _handedness) ? _y : -_y;
+ _result[10] = (Handedness::Right == _handedness) ? -aa : aa;
+ _result[11] = (Handedness::Right == _handedness) ? -1.0f : 1.0f;
_result[14] = -bb;
}
- template<NearFar::Enum NearFarT, Handness::Enum HandnessT>
- void mtxProjInfImpl(float* _result, float _ut, float _dt, float _lt, float _rt, float _near, bool _oglNdc)
+ void mtxProjInf(float* _result, float _ut, float _dt, float _lt, float _rt, float _near, bool _homogeneousNdc, Handedness::Enum _handedness, NearFar::Enum _nearFar)
{
const float invDiffRl = 1.0f/(_rt - _lt);
const float invDiffUd = 1.0f/(_ut - _dt);
@@ -424,107 +342,29 @@ namespace bx
const float height = 2.0f*_near * invDiffUd;
const float xx = (_rt + _lt) * invDiffRl;
const float yy = (_ut + _dt) * invDiffUd;
- mtxProjInfXYWH<NearFarT,HandnessT>(_result, xx, yy, width, height, _near, _oglNdc);
+ mtxProjInfXYWH(_result, xx, yy, width, height, _near, _homogeneousNdc, _handedness, _nearFar);
}
- template<NearFar::Enum NearFarT, Handness::Enum HandnessT>
- void mtxProjInfImpl(float* _result, const float _fov[4], float _near, bool _oglNdc)
+ void mtxProjInf(float* _result, const float _fov[4], float _near, bool _homogeneousNdc, Handedness::Enum _handedness, NearFar::Enum _nearFar)
{
- mtxProjInfImpl<NearFarT,HandnessT>(_result, _fov[0], _fov[1], _fov[2], _fov[3], _near, _oglNdc);
+ mtxProjInf(_result, _fov[0], _fov[1], _fov[2], _fov[3], _near, _homogeneousNdc, _handedness, _nearFar);
}
- template<NearFar::Enum NearFarT, Handness::Enum HandnessT>
- void mtxProjInfImpl(float* _result, float _fovy, float _aspect, float _near, bool _oglNdc)
+ void mtxProjInf(float* _result, float _fovy, float _aspect, float _near, bool _homogeneousNdc, Handedness::Enum _handedness, NearFar::Enum _nearFar)
{
const float height = 1.0f/tan(toRad(_fovy)*0.5f);
const float width = height * 1.0f/_aspect;
- mtxProjInfXYWH<NearFarT,HandnessT>(_result, 0.0f, 0.0f, width, height, _near, _oglNdc);
- }
-
- void mtxProjInf(float* _result, const float _fov[4], float _near, bool _oglNdc)
- {
- mtxProjInfImpl<NearFar::Default,Handness::Left>(_result, _fov, _near, _oglNdc);
- }
-
- void mtxProjInf(float* _result, float _ut, float _dt, float _lt, float _rt, float _near, bool _oglNdc)
- {
- mtxProjInfImpl<NearFar::Default,Handness::Left>(_result, _ut, _dt, _lt, _rt, _near, _oglNdc);
- }
-
- void mtxProjInf(float* _result, float _fovy, float _aspect, float _near, bool _oglNdc)
- {
- mtxProjInfImpl<NearFar::Default,Handness::Left>(_result, _fovy, _aspect, _near, _oglNdc);
- }
-
- void mtxProjInfLh(float* _result, float _ut, float _dt, float _lt, float _rt, float _near, bool _oglNdc)
- {
- mtxProjInfImpl<NearFar::Default,Handness::Left>(_result, _ut, _dt, _lt, _rt, _near, _oglNdc);
- }
-
- void mtxProjInfLh(float* _result, const float _fov[4], float _near, bool _oglNdc)
- {
- mtxProjInfImpl<NearFar::Default,Handness::Left>(_result, _fov, _near, _oglNdc);
- }
-
- void mtxProjInfLh(float* _result, float _fovy, float _aspect, float _near, bool _oglNdc)
- {
- mtxProjInfImpl<NearFar::Default,Handness::Left>(_result, _fovy, _aspect, _near, _oglNdc);
+ mtxProjInfXYWH(_result, 0.0f, 0.0f, width, height, _near, _homogeneousNdc, _handedness, _nearFar);
}
- void mtxProjInfRh(float* _result, float _ut, float _dt, float _lt, float _rt, float _near, bool _oglNdc)
- {
- mtxProjInfImpl<NearFar::Default,Handness::Right>(_result, _ut, _dt, _lt, _rt, _near, _oglNdc);
- }
-
- void mtxProjInfRh(float* _result, const float _fov[4], float _near, bool _oglNdc)
- {
- mtxProjInfImpl<NearFar::Default,Handness::Right>(_result, _fov, _near, _oglNdc);
- }
-
- void mtxProjInfRh(float* _result, float _fovy, float _aspect, float _near, bool _oglNdc)
- {
- mtxProjInfImpl<NearFar::Default,Handness::Right>(_result, _fovy, _aspect, _near, _oglNdc);
- }
-
- void mtxProjRevInfLh(float* _result, float _ut, float _dt, float _lt, float _rt, float _near, bool _oglNdc)
- {
- mtxProjInfImpl<NearFar::Reverse,Handness::Left>(_result, _ut, _dt, _lt, _rt, _near, _oglNdc);
- }
-
- void mtxProjRevInfLh(float* _result, const float _fov[4], float _near, bool _oglNdc)
- {
- mtxProjInfImpl<NearFar::Reverse,Handness::Left>(_result, _fov, _near, _oglNdc);
- }
-
- void mtxProjRevInfLh(float* _result, float _fovy, float _aspect, float _near, bool _oglNdc)
- {
- mtxProjInfImpl<NearFar::Reverse,Handness::Left>(_result, _fovy, _aspect, _near, _oglNdc);
- }
-
- void mtxProjRevInfRh(float* _result, float _ut, float _dt, float _lt, float _rt, float _near, bool _oglNdc)
- {
- mtxProjInfImpl<NearFar::Reverse,Handness::Right>(_result, _ut, _dt, _lt, _rt, _near, _oglNdc);
- }
-
- void mtxProjRevInfRh(float* _result, const float _fov[4], float _near, bool _oglNdc)
- {
- mtxProjInfImpl<NearFar::Reverse,Handness::Right>(_result, _fov, _near, _oglNdc);
- }
-
- void mtxProjRevInfRh(float* _result, float _fovy, float _aspect, float _near, bool _oglNdc)
- {
- mtxProjInfImpl<NearFar::Reverse,Handness::Right>(_result, _fovy, _aspect, _near, _oglNdc);
- }
-
- template<Handness::Enum HandnessT>
- void mtxOrthoImpl(float* _result, float _left, float _right, float _bottom, float _top, float _near, float _far, float _offset, bool _oglNdc)
+ void mtxOrtho(float* _result, float _left, float _right, float _bottom, float _top, float _near, float _far, float _offset, bool _homogeneousNdc, Handedness::Enum _handedness)
{
const float aa = 2.0f/(_right - _left);
const float bb = 2.0f/(_top - _bottom);
- const float cc = (_oglNdc ? 2.0f : 1.0f) / (_far - _near);
+ const float cc = (_homogeneousNdc ? 2.0f : 1.0f) / (_far - _near);
const float dd = (_left + _right )/(_left - _right);
const float ee = (_top + _bottom)/(_bottom - _top );
- const float ff = _oglNdc
+ const float ff = _homogeneousNdc
? (_near + _far)/(_near - _far)
: _near /(_near - _far)
;
@@ -532,28 +372,13 @@ namespace bx
memSet(_result, 0, sizeof(float)*16);
_result[ 0] = aa;
_result[ 5] = bb;
- _result[10] = (Handness::Right == HandnessT) ? -cc : cc;
+ _result[10] = Handedness::Right == _handedness ? -cc : cc;
_result[12] = dd + _offset;
_result[13] = ee;
_result[14] = ff;
_result[15] = 1.0f;
}
- void mtxOrtho(float* _result, float _left, float _right, float _bottom, float _top, float _near, float _far, float _offset, bool _oglNdc)
- {
- mtxOrthoImpl<Handness::Left>(_result, _left, _right, _bottom, _top, _near, _far, _offset, _oglNdc);
- }
-
- void mtxOrthoLh(float* _result, float _left, float _right, float _bottom, float _top, float _near, float _far, float _offset, bool _oglNdc)
- {
- mtxOrthoImpl<Handness::Left>(_result, _left, _right, _bottom, _top, _near, _far, _offset, _oglNdc);
- }
-
- void mtxOrthoRh(float* _result, float _left, float _right, float _bottom, float _top, float _near, float _far, float _offset, bool _oglNdc)
- {
- mtxOrthoImpl<Handness::Right>(_result, _left, _right, _bottom, _top, _near, _far, _offset, _oglNdc);
- }
-
void mtxRotateX(float* _result, float _ax)
{
const float sx = sin(_ax);
@@ -694,15 +519,15 @@ namespace bx
void mtx3Inverse(float* _result, const float* _a)
{
- float xx = _a[0];
- float xy = _a[1];
- float xz = _a[2];
- float yx = _a[3];
- float yy = _a[4];
- float yz = _a[5];
- float zx = _a[6];
- float zy = _a[7];
- float zz = _a[8];
+ const float xx = _a[0];
+ const float xy = _a[1];
+ const float xz = _a[2];
+ const float yx = _a[3];
+ const float yy = _a[4];
+ const float yz = _a[5];
+ const float zx = _a[6];
+ const float zy = _a[7];
+ const float zz = _a[8];
float det = 0.0f;
det += xx * (yy*zz - yz*zy);
@@ -726,22 +551,22 @@ namespace bx
void mtxInverse(float* _result, const float* _a)
{
- float xx = _a[ 0];
- float xy = _a[ 1];
- float xz = _a[ 2];
- float xw = _a[ 3];
- float yx = _a[ 4];
- float yy = _a[ 5];
- float yz = _a[ 6];
- float yw = _a[ 7];
- float zx = _a[ 8];
- float zy = _a[ 9];
- float zz = _a[10];
- float zw = _a[11];
- float wx = _a[12];
- float wy = _a[13];
- float wz = _a[14];
- float ww = _a[15];
+ const float xx = _a[ 0];
+ const float xy = _a[ 1];
+ const float xz = _a[ 2];
+ const float xw = _a[ 3];
+ const float yx = _a[ 4];
+ const float yy = _a[ 5];
+ const float yz = _a[ 6];
+ const float yw = _a[ 7];
+ const float zx = _a[ 8];
+ const float zy = _a[ 9];
+ const float zz = _a[10];
+ const float zw = _a[11];
+ const float wx = _a[12];
+ const float wy = _a[13];
+ const float wz = _a[14];
+ const float ww = _a[15];
float det = 0.0f;
det += xx * (yy*(zz*ww - zw*wz) - yz*(zy*ww - zw*wy) + yw*(zy*wz - zz*wy) );
@@ -772,6 +597,71 @@ namespace bx
_result[15] = +(xx*(yy*zz - zy*yz) - xy*(yx*zz - zx*yz) + xz*(yx*zy - zx*yy) ) * invDet;
}
+ void mtx3Cofactor(float* _result, const float* _a)
+ {
+ const float xx = _a[0];
+ const float xy = _a[1];
+ const float xz = _a[2];
+ const float yx = _a[3];
+ const float yy = _a[4];
+ const float yz = _a[5];
+ const float zx = _a[6];
+ const float zy = _a[7];
+ const float zz = _a[8];
+
+ _result[0] = +(yy*zz - yz * zy);
+ _result[1] = -(yx*zz - yz * zx);
+ _result[2] = +(yx*zy - yy * zx);
+
+ _result[3] = -(xy*zz - xz * zy);
+ _result[4] = +(xx*zz - xz * zx);
+ _result[5] = -(xx*zy - xy * zx);
+
+ _result[6] = +(xy*yz - xz * yy);
+ _result[7] = -(xx*yz - xz * yx);
+ _result[8] = +(xx*yy - xy * yx);
+ }
+
+ void mtxCofactor(float* _result, const float* _a)
+ {
+ const float xx = _a[0];
+ const float xy = _a[1];
+ const float xz = _a[2];
+ const float xw = _a[3];
+ const float yx = _a[4];
+ const float yy = _a[5];
+ const float yz = _a[6];
+ const float yw = _a[7];
+ const float zx = _a[8];
+ const float zy = _a[9];
+ const float zz = _a[10];
+ const float zw = _a[11];
+ const float wx = _a[12];
+ const float wy = _a[13];
+ const float wz = _a[14];
+ const float ww = _a[15];
+
+ _result[ 0] = +(yy*(zz*ww - wz * zw) - yz * (zy*ww - wy * zw) + yw * (zy*wz - wy * zz) );
+ _result[ 1] = -(yx*(zz*ww - wz * zw) - yz * (zx*ww - wx * zw) + yw * (zx*wz - wx * zz) );
+ _result[ 2] = +(yx*(zy*ww - wy * zw) - yy * (zx*ww - wx * zw) + yw * (zx*wy - wx * zy) );
+ _result[ 3] = -(yx*(zy*wz - wy * zz) - yy * (zx*wz - wx * zz) + yz * (zx*wy - wx * zy) );
+
+ _result[ 4] = -(xy*(zz*ww - wz * zw) - xz * (zy*ww - wy * zw) + xw * (zy*wz - wy * zz) );
+ _result[ 5] = +(xx*(zz*ww - wz * zw) - xz * (zx*ww - wx * zw) + xw * (zx*wz - wx * zz) );
+ _result[ 6] = -(xx*(zy*ww - wy * zw) - xy * (zx*ww - wx * zw) + xw * (zx*wy - wx * zy) );
+ _result[ 7] = +(xx*(zy*wz - wy * zz) - xy * (zx*wz - wx * zz) + xz * (zx*wy - wx * zy) );
+
+ _result[ 8] = +(xy*(yz*ww - wz * yw) - xz * (yy*ww - wy * yw) + xw * (yy*wz - wy * yz) );
+ _result[ 9] = -(xx*(yz*ww - wz * yw) - xz * (yx*ww - wx * yw) + xw * (yx*wz - wx * yz) );
+ _result[10] = +(xx*(yy*ww - wy * yw) - xy * (yx*ww - wx * yw) + xw * (yx*wy - wx * yy) );
+ _result[11] = -(xx*(yy*wz - wy * yz) - xy * (yx*wz - wx * yz) + xz * (yx*wy - wx * yy) );
+
+ _result[12] = -(xy*(yz*zw - zz * yw) - xz * (yy*zw - zy * yw) + xw * (yy*zz - zy * yz) );
+ _result[13] = +(xx*(yz*zw - zz * yw) - xz * (yx*zw - zx * yw) + xw * (yx*zz - zx * yz) );
+ _result[14] = -(xx*(yy*zw - zy * yw) - xy * (yx*zw - zx * yw) + xw * (yx*zy - zx * yy) );
+ _result[15] = +(xx*(yy*zz - zy * yz) - xy * (yx*zz - zx * yz) + xz * (yx*zy - zx * yy) );
+ }
+
void calcLinearFit2D(float _result[2], const void* _points, uint32_t _stride, uint32_t _numPoints)
{
float sumX = 0.0f;
diff --git a/3rdparty/bx/src/mutex.cpp b/3rdparty/bx/src/mutex.cpp
index 27c6b63b709..0ef8597a8aa 100644
--- a/3rdparty/bx/src/mutex.cpp
+++ b/3rdparty/bx/src/mutex.cpp
@@ -1,9 +1,8 @@
/*
- * Copyright 2010-2018 Branimir Karadzic. All rights reserved.
- * License: https://github.com/bkaradzic/bx#license-bsd-2-clause
+ * Copyright 2010-2022 Branimir Karadzic. All rights reserved.
+ * License: https://github.com/bkaradzic/bx/blob/master/LICENSE
*/
-#include "bx_p.h"
#include <bx/mutex.h>
#if BX_CONFIG_SUPPORTS_THREADING
@@ -12,15 +11,21 @@
# include <bx/cpu.h>
# include "crt0.h"
#elif BX_PLATFORM_ANDROID \
+ || BX_PLATFORM_BSD \
+ || BX_PLATFORM_HAIKU \
|| BX_PLATFORM_LINUX \
|| BX_PLATFORM_IOS \
|| BX_PLATFORM_OSX \
|| BX_PLATFORM_PS4 \
- || BX_PLATFORM_RPI
+ || BX_PLATFORM_RPI \
+ || BX_PLATFORM_NX
# include <pthread.h>
#elif BX_PLATFORM_WINDOWS \
|| BX_PLATFORM_WINRT \
|| BX_PLATFORM_XBOXONE
+# ifndef WIN32_LEAN_AND_MEAN
+# define WIN32_LEAN_AND_MEAN
+# endif // WIN32_LEAN_AND_MEAN
# include <windows.h>
# include <errno.h>
#endif // BX_PLATFORM_
@@ -54,12 +59,12 @@ namespace bx
{
uint32_t* futex = (uint32_t*)m_internal;
- if (State::Unlocked == bx::atomicCompareAndSwap<uint32_t>(futex, State::Unlocked, State::Locked) )
+ if (State::Unlocked == atomicCompareAndSwap<uint32_t>(futex, State::Unlocked, State::Locked) )
{
return;
}
- while (State::Unlocked != bx::atomicCompareAndSwap<uint32_t>(futex, State::Locked, State::Contested) )
+ while (State::Unlocked != atomicCompareAndSwap<uint32_t>(futex, State::Locked, State::Contested) )
{
crt0::futexWait(futex, State::Contested);
}
@@ -69,7 +74,7 @@ namespace bx
{
uint32_t* futex = (uint32_t*)m_internal;
- if (State::Contested == bx::atomicCompareAndSwap<uint32_t>(futex, State::Locked, State::Unlocked) )
+ if (State::Contested == atomicCompareAndSwap<uint32_t>(futex, State::Locked, State::Unlocked) )
{
crt0::futexWake(futex, State::Locked);
}
@@ -156,4 +161,26 @@ namespace bx
} // namespace bx
-#endif // BX_MUTEX_H_HEADER_GUARD
+#else
+
+namespace bx
+{
+ Mutex::Mutex()
+ {
+ }
+
+ Mutex::~Mutex()
+ {
+ }
+
+ void Mutex::lock()
+ {
+ }
+
+ void Mutex::unlock()
+ {
+ }
+
+} // namespace bx
+
+#endif // BX_CONFIG_SUPPORTS_THREADING
diff --git a/3rdparty/bx/src/os.cpp b/3rdparty/bx/src/os.cpp
index 0e925bb2f90..99394579b72 100644
--- a/3rdparty/bx/src/os.cpp
+++ b/3rdparty/bx/src/os.cpp
@@ -1,9 +1,8 @@
/*
- * Copyright 2010-2018 Branimir Karadzic. All rights reserved.
- * License: https://github.com/bkaradzic/bx#license-bsd-2-clause
+ * Copyright 2010-2022 Branimir Karadzic. All rights reserved.
+ * License: https://github.com/bkaradzic/bx/blob/master/LICENSE
*/
-#include "bx_p.h"
#include <bx/string.h>
#include <bx/os.h>
#include <bx/uint32_t.h>
@@ -15,25 +14,28 @@
#endif // BX_CRT_MSVC
#if BX_PLATFORM_WINDOWS || BX_PLATFORM_WINRT
+# ifndef WIN32_LEAN_AND_MEAN
+# define WIN32_LEAN_AND_MEAN
+# endif // WIN32_LEAN_AND_MEAN
# include <windows.h>
# include <psapi.h>
#elif BX_PLATFORM_ANDROID \
- || BX_PLATFORM_EMSCRIPTEN \
|| BX_PLATFORM_BSD \
+ || BX_PLATFORM_EMSCRIPTEN \
+ || BX_PLATFORM_HAIKU \
|| BX_PLATFORM_HURD \
|| BX_PLATFORM_IOS \
|| BX_PLATFORM_LINUX \
+ || BX_PLATFORM_NX \
|| BX_PLATFORM_OSX \
|| BX_PLATFORM_PS4 \
- || BX_PLATFORM_RPI \
- || BX_PLATFORM_STEAMLINK \
- || BX_PLATFORM_NX
+ || BX_PLATFORM_RPI
# include <sched.h> // sched_yield
-# if BX_PLATFORM_BSD \
- || BX_PLATFORM_IOS \
- || BX_PLATFORM_OSX \
- || BX_PLATFORM_PS4 \
- || BX_PLATFORM_STEAMLINK
+# if BX_PLATFORM_BSD \
+ || BX_PLATFORM_HAIKU \
+ || BX_PLATFORM_IOS \
+ || BX_PLATFORM_OSX \
+ || BX_PLATFORM_PS4
# include <pthread.h> // mach_port_t
# endif // BX_PLATFORM_*
@@ -45,11 +47,13 @@
# if BX_PLATFORM_ANDROID
# include <malloc.h> // mallinfo
# elif BX_PLATFORM_LINUX \
- || BX_PLATFORM_RPI \
- || BX_PLATFORM_STEAMLINK
+ || BX_PLATFORM_RPI
# include <stdio.h> // fopen
# include <unistd.h> // syscall
# include <sys/syscall.h>
+# elif BX_PLATFORM_HAIKU
+# include <stdio.h> // fopen
+# include <unistd.h> // syscall
# elif BX_PLATFORM_OSX
# include <mach/mach.h> // mach_task_basic_info
# elif BX_PLATFORM_HURD
@@ -62,7 +66,6 @@
namespace bx
{
-
void sleep(uint32_t _ms)
{
#if BX_PLATFORM_WINDOWS
@@ -97,8 +100,7 @@ namespace bx
#if BX_PLATFORM_WINDOWS
return ::GetCurrentThreadId();
#elif BX_PLATFORM_LINUX \
- || BX_PLATFORM_RPI \
- || BX_PLATFORM_STEAMLINK
+ || BX_PLATFORM_RPI
return (pid_t)::syscall(SYS_gettid);
#elif BX_PLATFORM_IOS \
|| BX_PLATFORM_OSX
@@ -174,7 +176,7 @@ namespace bx
void* dlopen(const FilePath& _filePath)
{
#if BX_PLATFORM_WINDOWS
- return (void*)::LoadLibraryA(_filePath.get() );
+ return (void*)::LoadLibraryA(_filePath.getCPtr() );
#elif BX_PLATFORM_EMSCRIPTEN \
|| BX_PLATFORM_PS4 \
|| BX_PLATFORM_XBOXONE \
@@ -183,12 +185,19 @@ namespace bx
BX_UNUSED(_filePath);
return NULL;
#else
- return ::dlopen(_filePath.get(), RTLD_LOCAL|RTLD_LAZY);
+ void* so = ::dlopen(_filePath.getCPtr(), RTLD_LOCAL|RTLD_LAZY);
+ BX_WARN(NULL != so, "dlopen failed: \"%s\".", ::dlerror() );
+ return so;
#endif // BX_PLATFORM_
}
void dlclose(void* _handle)
{
+ if (NULL == _handle)
+ {
+ return;
+ }
+
#if BX_PLATFORM_WINDOWS
::FreeLibrary( (HMODULE)_handle);
#elif BX_PLATFORM_EMSCRIPTEN \
@@ -206,7 +215,7 @@ namespace bx
{
const int32_t symbolMax = _symbol.getLength()+1;
char* symbol = (char*)alloca(symbolMax);
- bx::strCopy(symbol, symbolMax, _symbol);
+ strCopy(symbol, symbolMax, _symbol);
#if BX_PLATFORM_WINDOWS
return (void*)::GetProcAddress( (HMODULE)_handle, symbol);
@@ -226,16 +235,17 @@ namespace bx
{
const int32_t nameMax = _name.getLength()+1;
char* name = (char*)alloca(nameMax);
- bx::strCopy(name, nameMax, _name);
+ strCopy(name, nameMax, _name);
#if BX_PLATFORM_WINDOWS
DWORD len = ::GetEnvironmentVariableA(name, _out, *_inOutSize);
bool result = len != 0 && len < *_inOutSize;
*_inOutSize = len;
return result;
-#elif BX_PLATFORM_PS4 \
- || BX_PLATFORM_XBOXONE \
- || BX_PLATFORM_WINRT \
+#elif BX_PLATFORM_EMSCRIPTEN \
+ || BX_PLATFORM_PS4 \
+ || BX_PLATFORM_XBOXONE \
+ || BX_PLATFORM_WINRT \
|| BX_CRT_NONE
BX_UNUSED(name, _out, _inOutSize);
return false;
@@ -263,21 +273,22 @@ namespace bx
{
const int32_t nameMax = _name.getLength()+1;
char* name = (char*)alloca(nameMax);
- bx::strCopy(name, nameMax, _name);
+ strCopy(name, nameMax, _name);
char* value = NULL;
if (!_value.isEmpty() )
{
int32_t valueMax = _value.getLength()+1;
value = (char*)alloca(valueMax);
- bx::strCopy(value, valueMax, _value);
+ strCopy(value, valueMax, _value);
}
#if BX_PLATFORM_WINDOWS
::SetEnvironmentVariableA(name, value);
-#elif BX_PLATFORM_PS4 \
- || BX_PLATFORM_XBOXONE \
- || BX_PLATFORM_WINRT \
+#elif BX_PLATFORM_EMSCRIPTEN \
+ || BX_PLATFORM_PS4 \
+ || BX_PLATFORM_XBOXONE \
+ || BX_PLATFORM_WINRT \
|| BX_CRT_NONE
BX_UNUSED(name, value);
#else
@@ -339,7 +350,7 @@ namespace bx
int32_t len = 0;
for(uint32_t ii = 0; NULL != _argv[ii]; ++ii)
{
- len += snprintf(&temp[len], bx::uint32_imax(0, total-len)
+ len += snprintf(&temp[len], uint32_imax(0, total-len)
, "%s "
, _argv[ii]
);
@@ -368,4 +379,9 @@ namespace bx
#endif // BX_PLATFORM_LINUX || BX_PLATFORM_HURD
}
+ void exit(int32_t _exitCode)
+ {
+ ::exit(_exitCode);
+ }
+
} // namespace bx
diff --git a/3rdparty/bx/src/process.cpp b/3rdparty/bx/src/process.cpp
index 90d663b3f5a..8afa1feb230 100644
--- a/3rdparty/bx/src/process.cpp
+++ b/3rdparty/bx/src/process.cpp
@@ -1,9 +1,8 @@
/*
- * Copyright 2010-2018 Branimir Karadzic. All rights reserved.
- * License: https://github.com/bkaradzic/bx#license-bsd-2-clause
+ * Copyright 2010-2022 Branimir Karadzic. All rights reserved.
+ * License: https://github.com/bkaradzic/bx/blob/master/LICENSE
*/
-#include "bx_p.h"
#include <bx/process.h>
#include <stdio.h>
@@ -34,28 +33,28 @@ namespace bx
ProcessReader::~ProcessReader()
{
- BX_CHECK(NULL == m_file, "Process not closed!");
+ BX_ASSERT(NULL == m_file, "Process not closed!");
}
bool ProcessReader::open(const FilePath& _filePath, const StringView& _args, Error* _err)
{
- BX_CHECK(NULL != _err, "Reader/Writer interface calling functions must handle errors.");
+ BX_ASSERT(NULL != _err, "Reader/Writer interface calling functions must handle errors.");
if (NULL != m_file)
{
- BX_ERROR_SET(_err, BX_ERROR_READERWRITER_ALREADY_OPEN, "ProcessReader: File is already open.");
+ BX_ERROR_SET(_err, kErrorReaderWriterAlreadyOpen, "ProcessReader: File is already open.");
return false;
}
char tmp[kMaxFilePath*2] = "\"";
- strCat(tmp, BX_COUNTOF(tmp), _filePath.get() );
+ strCat(tmp, BX_COUNTOF(tmp), _filePath);
strCat(tmp, BX_COUNTOF(tmp), "\" ");
strCat(tmp, BX_COUNTOF(tmp), _args);
m_file = popen(tmp, "r");
if (NULL == m_file)
{
- BX_ERROR_SET(_err, BX_ERROR_READERWRITER_OPEN, "ProcessReader: Failed to open process.");
+ BX_ERROR_SET(_err, kErrorReaderWriterOpen, "ProcessReader: Failed to open process.");
return false;
}
@@ -64,7 +63,7 @@ namespace bx
void ProcessReader::close()
{
- BX_CHECK(NULL != m_file, "Process not open!");
+ BX_ASSERT(NULL != m_file, "Process not open!");
FILE* file = (FILE*)m_file;
m_exitCode = pclose(file);
m_file = NULL;
@@ -72,7 +71,7 @@ namespace bx
int32_t ProcessReader::read(void* _data, int32_t _size, Error* _err)
{
- BX_CHECK(NULL != _err, "Reader/Writer interface calling functions must handle errors."); BX_UNUSED(_err);
+ BX_ASSERT(NULL != _err, "Reader/Writer interface calling functions must handle errors."); BX_UNUSED(_err);
FILE* file = (FILE*)m_file;
int32_t size = (int32_t)fread(_data, 1, _size, file);
@@ -80,11 +79,11 @@ namespace bx
{
if (0 != feof(file) )
{
- BX_ERROR_SET(_err, BX_ERROR_READERWRITER_EOF, "ProcessReader: EOF.");
+ BX_ERROR_SET(_err, kErrorReaderWriterEof, "ProcessReader: EOF.");
}
else if (0 != ferror(file) )
{
- BX_ERROR_SET(_err, BX_ERROR_READERWRITER_READ, "ProcessReader: read error.");
+ BX_ERROR_SET(_err, kErrorReaderWriterRead, "ProcessReader: read error.");
}
return size >= 0 ? size : 0;
@@ -105,28 +104,28 @@ namespace bx
ProcessWriter::~ProcessWriter()
{
- BX_CHECK(NULL == m_file, "Process not closed!");
+ BX_ASSERT(NULL == m_file, "Process not closed!");
}
bool ProcessWriter::open(const FilePath& _filePath, const StringView& _args, Error* _err)
{
- BX_CHECK(NULL != _err, "Reader/Writer interface calling functions must handle errors.");
+ BX_ASSERT(NULL != _err, "Reader/Writer interface calling functions must handle errors.");
if (NULL != m_file)
{
- BX_ERROR_SET(_err, BX_ERROR_READERWRITER_ALREADY_OPEN, "ProcessWriter: File is already open.");
+ BX_ERROR_SET(_err, kErrorReaderWriterAlreadyOpen, "ProcessWriter: File is already open.");
return false;
}
char tmp[kMaxFilePath*2] = "\"";
- strCat(tmp, BX_COUNTOF(tmp), _filePath.get() );
+ strCat(tmp, BX_COUNTOF(tmp), _filePath);
strCat(tmp, BX_COUNTOF(tmp), "\" ");
strCat(tmp, BX_COUNTOF(tmp), _args);
m_file = popen(tmp, "w");
if (NULL == m_file)
{
- BX_ERROR_SET(_err, BX_ERROR_READERWRITER_OPEN, "ProcessWriter: Failed to open process.");
+ BX_ERROR_SET(_err, kErrorReaderWriterOpen, "ProcessWriter: Failed to open process.");
return false;
}
@@ -135,7 +134,7 @@ namespace bx
void ProcessWriter::close()
{
- BX_CHECK(NULL != m_file, "Process not open!");
+ BX_ASSERT(NULL != m_file, "Process not open!");
FILE* file = (FILE*)m_file;
m_exitCode = pclose(file);
m_file = NULL;
@@ -143,7 +142,7 @@ namespace bx
int32_t ProcessWriter::write(const void* _data, int32_t _size, Error* _err)
{
- BX_CHECK(NULL != _err, "Reader/Writer interface calling functions must handle errors."); BX_UNUSED(_err);
+ BX_ASSERT(NULL != _err, "Reader/Writer interface calling functions must handle errors."); BX_UNUSED(_err);
FILE* file = (FILE*)m_file;
int32_t size = (int32_t)fwrite(_data, 1, _size, file);
@@ -151,7 +150,7 @@ namespace bx
{
if (0 != ferror(file) )
{
- BX_ERROR_SET(_err, BX_ERROR_READERWRITER_WRITE, "ProcessWriter: write error.");
+ BX_ERROR_SET(_err, kErrorReaderWriterWrite, "ProcessWriter: write error.");
}
return size >= 0 ? size : 0;
diff --git a/3rdparty/bx/src/semaphore.cpp b/3rdparty/bx/src/semaphore.cpp
index 3663fe767b5..787b913a8d8 100644
--- a/3rdparty/bx/src/semaphore.cpp
+++ b/3rdparty/bx/src/semaphore.cpp
@@ -1,9 +1,8 @@
/*
- * Copyright 2010-2018 Branimir Karadzic. All rights reserved.
- * License: https://github.com/bkaradzic/bx#license-bsd-2-clause
+ * Copyright 2010-2022 Branimir Karadzic. All rights reserved.
+ * License: https://github.com/bkaradzic/bx/blob/master/LICENSE
*/
-#include "bx_p.h"
#include <bx/semaphore.h>
#if BX_CONFIG_SUPPORTS_THREADING
@@ -20,6 +19,9 @@
#elif BX_PLATFORM_WINDOWS \
|| BX_PLATFORM_WINRT \
|| BX_PLATFORM_XBOXONE
+# ifndef WIN32_LEAN_AND_MEAN
+# define WIN32_LEAN_AND_MEAN
+# endif // WIN32_LEAN_AND_MEAN
# include <windows.h>
# include <limits.h>
# if BX_PLATFORM_XBOXONE
@@ -76,7 +78,7 @@ namespace bx
SemaphoreInternal* si = (SemaphoreInternal*)m_internal;
si->m_handle = dispatch_semaphore_create(0);
- BX_CHECK(NULL != si->m_handle, "dispatch_semaphore_create failed.");
+ BX_ASSERT(NULL != si->m_handle, "dispatch_semaphore_create failed.");
}
Semaphore::~Semaphore()
@@ -140,10 +142,10 @@ namespace bx
int result;
result = pthread_mutex_init(&si->m_mutex, NULL);
- BX_CHECK(0 == result, "pthread_mutex_init %d", result);
+ BX_ASSERT(0 == result, "pthread_mutex_init %d", result);
result = pthread_cond_init(&si->m_cond, NULL);
- BX_CHECK(0 == result, "pthread_cond_init %d", result);
+ BX_ASSERT(0 == result, "pthread_cond_init %d", result);
BX_UNUSED(result);
}
@@ -154,10 +156,10 @@ namespace bx
int result;
result = pthread_cond_destroy(&si->m_cond);
- BX_CHECK(0 == result, "pthread_cond_destroy %d", result);
+ BX_ASSERT(0 == result, "pthread_cond_destroy %d", result);
result = pthread_mutex_destroy(&si->m_mutex);
- BX_CHECK(0 == result, "pthread_mutex_destroy %d", result);
+ BX_ASSERT(0 == result, "pthread_mutex_destroy %d", result);
BX_UNUSED(result);
}
@@ -167,18 +169,18 @@ namespace bx
SemaphoreInternal* si = (SemaphoreInternal*)m_internal;
int result = pthread_mutex_lock(&si->m_mutex);
- BX_CHECK(0 == result, "pthread_mutex_lock %d", result);
+ BX_ASSERT(0 == result, "pthread_mutex_lock %d", result);
for (uint32_t ii = 0; ii < _count; ++ii)
{
result = pthread_cond_signal(&si->m_cond);
- BX_CHECK(0 == result, "pthread_cond_signal %d", result);
+ BX_ASSERT(0 == result, "pthread_cond_signal %d", result);
}
si->m_count += _count;
result = pthread_mutex_unlock(&si->m_mutex);
- BX_CHECK(0 == result, "pthread_mutex_unlock %d", result);
+ BX_ASSERT(0 == result, "pthread_mutex_unlock %d", result);
BX_UNUSED(result);
}
@@ -188,7 +190,7 @@ namespace bx
SemaphoreInternal* si = (SemaphoreInternal*)m_internal;
int result = pthread_mutex_lock(&si->m_mutex);
- BX_CHECK(0 == result, "pthread_mutex_lock %d", result);
+ BX_ASSERT(0 == result, "pthread_mutex_lock %d", result);
if (-1 == _msecs)
{
@@ -219,7 +221,7 @@ namespace bx
}
result = pthread_mutex_unlock(&si->m_mutex);
- BX_CHECK(0 == result, "pthread_mutex_unlock %d", result);
+ BX_ASSERT(0 == result, "pthread_mutex_unlock %d", result);
BX_UNUSED(result);
@@ -240,7 +242,7 @@ namespace bx
#else
si->m_handle = CreateSemaphoreA(NULL, 0, LONG_MAX, NULL);
#endif
- BX_CHECK(NULL != si->m_handle, "Failed to create Semaphore!");
+ BX_ASSERT(NULL != si->m_handle, "Failed to create Semaphore!");
}
Semaphore::~Semaphore()
diff --git a/3rdparty/bx/src/settings.cpp b/3rdparty/bx/src/settings.cpp
index e09e11f687f..7f16eeee10f 100644
--- a/3rdparty/bx/src/settings.cpp
+++ b/3rdparty/bx/src/settings.cpp
@@ -1,9 +1,8 @@
/*
- * Copyright 2011-2018 Branimir Karadzic. All rights reserved.
- * License: https://github.com/bkaradzic/bx#license-bsd-2-clause
+ * Copyright 2011-2022 Branimir Karadzic. All rights reserved.
+ * License: https://github.com/bkaradzic/bx/blob/master/LICENSE
*/
-#include "bx_p.h"
#include <bx/settings.h>
namespace
diff --git a/3rdparty/bx/src/sort.cpp b/3rdparty/bx/src/sort.cpp
index 515b33f24f1..31ad8c795f4 100644
--- a/3rdparty/bx/src/sort.cpp
+++ b/3rdparty/bx/src/sort.cpp
@@ -1,9 +1,8 @@
/*
- * Copyright 2010-2018 Branimir Karadzic. All rights reserved.
- * License: https://github.com/bkaradzic/bx#license-bsd-2-clause
+ * Copyright 2010-2022 Branimir Karadzic. All rights reserved.
+ * License: https://github.com/bkaradzic/bx/blob/master/LICENSE
*/
-#include "bx_p.h"
#include <bx/sort.h>
namespace bx
@@ -52,5 +51,124 @@ namespace bx
quickSortR(pivot, _data, _num, _stride, _fn);
}
+ bool isSorted(const void* _data, uint32_t _num, uint32_t _stride, const ComparisonFn _fn)
+ {
+ const uint8_t* data = (uint8_t*)_data;
+
+ for (uint32_t ii = 1; ii < _num; ++ii)
+ {
+ int32_t result = _fn(&data[(ii-1)*_stride], &data[ii*_stride]);
+
+ if (0 < result)
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ uint32_t unique(void* _data, uint32_t _num, uint32_t _stride, const ComparisonFn _fn)
+ {
+ if (0 == _num)
+ {
+ return 0;
+ }
+
+ uint8_t* data = (uint8_t*)_data;
+
+ uint32_t last = 0;
+
+ for (uint32_t ii = 1; ii < _num; ++ii)
+ {
+ int32_t result = _fn(&data[last*_stride], &data[ii*_stride]);
+ BX_ASSERT(0 >= result, "Performing unique on non-sorted array (ii %d, last %d)!", ii, last);
+
+ if (0 > result)
+ {
+ last++;
+ swap(&data[last*_stride], &data[ii*_stride], _stride);
+ }
+ }
+
+ return last+1;
+ }
+
+ uint32_t lowerBound(const void* _key, const void* _data, uint32_t _num, uint32_t _stride, const ComparisonFn _fn)
+ {
+ uint32_t offset = 0;
+ const uint8_t* data = (uint8_t*)_data;
+
+ for (uint32_t ll = _num; offset < ll;)
+ {
+ const uint32_t idx = (offset + ll) / 2;
+
+ int32_t result = _fn(_key, &data[idx * _stride]);
+
+ if (result <= 0)
+ {
+ ll = idx;
+ }
+ else
+ {
+ offset = idx + 1;
+ }
+ }
+
+ return offset;
+ }
+
+ uint32_t upperBound(const void* _key, const void* _data, uint32_t _num, uint32_t _stride, const ComparisonFn _fn)
+ {
+ uint32_t offset = 0;
+ const uint8_t* data = (uint8_t*)_data;
+
+ for (uint32_t ll = _num; offset < ll;)
+ {
+ const uint32_t idx = (offset + ll) / 2;
+
+ int32_t result = _fn(_key, &data[idx * _stride]);
+
+ if (result < 0)
+ {
+ ll = idx;
+ }
+ else
+ {
+ offset = idx + 1;
+ }
+ }
+
+ return offset;
+ }
+
+ int32_t binarySearch(const void* _key, const void* _data, uint32_t _num, uint32_t _stride, const ComparisonFn _fn)
+ {
+ uint32_t offset = 0;
+ const uint8_t* data = (uint8_t*)_data;
+
+ for (uint32_t ll = _num; offset < ll;)
+ {
+ const uint32_t idx = (offset + ll) / 2;
+
+ int32_t result = _fn(_key, &data[idx * _stride]);
+
+ if (result < 0)
+ {
+ ll = idx;
+ }
+ else if (result > 0)
+ {
+ offset = idx + 1;
+ }
+ else
+ {
+ return idx;
+ }
+ }
+
+ return ~offset;
+ }
+
} // namespace bx
diff --git a/3rdparty/bx/src/string.cpp b/3rdparty/bx/src/string.cpp
index 7710028ae6d..94429ebd21d 100644
--- a/3rdparty/bx/src/string.cpp
+++ b/3rdparty/bx/src/string.cpp
@@ -1,12 +1,11 @@
/*
- * Copyright 2010-2018 Branimir Karadzic. All rights reserved.
- * License: https://github.com/bkaradzic/bx#license-bsd-2-clause
+ * Copyright 2010-2022 Branimir Karadzic. All rights reserved.
+ * License: https://github.com/bkaradzic/bx/blob/master/LICENSE
*/
-#include "bx_p.h"
#include <bx/allocator.h>
+#include <bx/file.h>
#include <bx/hash.h>
-#include <bx/readerwriter.h>
#include <bx/string.h>
namespace bx
@@ -135,7 +134,7 @@ namespace bx
{
for (int32_t ii = 0; ii < _len; ++ii)
{
- *_inOutStr = toLower(*_inOutStr);
+ _inOutStr[ii] = toLower(_inOutStr[ii]);
}
}
@@ -154,7 +153,7 @@ namespace bx
{
for (int32_t ii = 0; ii < _len; ++ii)
{
- *_inOutStr = toUpper(*_inOutStr);
+ _inOutStr[ii] = toUpper(_inOutStr[ii]);
}
}
@@ -188,7 +187,12 @@ namespace bx
}
}
- return 0 == max && _lhsMax == _rhsMax ? 0 : fn(*_lhs) - fn(*_rhs);
+ if (0 == max)
+ {
+ return _lhsMax == _rhsMax ? 0 : _lhsMax > _rhsMax ? 1 : -1;
+ }
+
+ return fn(*_lhs) - fn(*_rhs);
}
int32_t strCmp(const StringView& _lhs, const StringView& _rhs, int32_t _max)
@@ -305,9 +309,9 @@ namespace bx
inline int32_t strCopy(char* _dst, int32_t _dstSize, const char* _src, int32_t _num)
{
- BX_CHECK(NULL != _dst, "_dst can't be NULL!");
- BX_CHECK(NULL != _src, "_src can't be NULL!");
- BX_CHECK(0 < _dstSize, "_dstSize can't be 0!");
+ BX_ASSERT(NULL != _dst, "_dst can't be NULL!");
+ BX_ASSERT(NULL != _src, "_src can't be NULL!");
+ BX_ASSERT(0 < _dstSize, "_dstSize can't be 0!");
const int32_t len = strLen(_src, _num);
const int32_t max = _dstSize-1;
@@ -325,9 +329,9 @@ namespace bx
inline int32_t strCat(char* _dst, int32_t _dstSize, const char* _src, int32_t _num)
{
- BX_CHECK(NULL != _dst, "_dst can't be NULL!");
- BX_CHECK(NULL != _src, "_src can't be NULL!");
- BX_CHECK(0 < _dstSize, "_dstSize can't be 0!");
+ BX_ASSERT(NULL != _dst, "_dst can't be NULL!");
+ BX_ASSERT(NULL != _src, "_src can't be NULL!");
+ BX_ASSERT(0 < _dstSize, "_dstSize can't be 0!");
const int32_t max = _dstSize;
const int32_t len = strLen(_dst, max);
@@ -370,7 +374,7 @@ namespace bx
inline const char* strRFindUnsafe(const char* _str, int32_t _len, char _ch)
{
- for (int32_t ii = _len; 0 <= ii; --ii)
+ for (int32_t ii = _len-1; 0 <= ii; --ii)
{
if (_str[ii] == _ch)
{
@@ -408,25 +412,16 @@ namespace bx
++ptr;
--stringLen;
- // Search pattern lenght can't be longer than the string.
+ // Search pattern length can't be longer than the string.
if (findLen > stringLen)
{
return NULL;
}
}
- // Set pointers.
- const char* string = ptr;
- const char* search = _find;
-
- // Start comparing.
- while (fn(*string++) == fn(*search++) )
+ if (0 == strCmp<fn>(ptr, _findMax, _find, _findMax) )
{
- // If end of the 'search' string is reached, all characters match.
- if ('\0' == *search)
- {
- return ptr;
- }
+ return ptr;
}
}
@@ -485,7 +480,7 @@ namespace bx
}
}
- return _str;
+ return StringView(_str.getTerm(), _str.getTerm() );
}
StringView strLTrimSpace(const StringView& _str)
@@ -528,7 +523,29 @@ namespace bx
{
return StringView(ptr, ii + 1);
}
+ }
+
+ return StringView(_str.getPtr(), _str.getPtr());
+ }
+
+ return _str;
+ }
+
+ StringView strRTrimSpace(const StringView& _str)
+ {
+ if (!_str.isEmpty() )
+ {
+ const char* ptr = _str.getPtr();
+
+ for (int32_t len = _str.getLength(), ii = len - 1; 0 <= ii; --ii)
+ {
+ if (!isSpace(ptr[ii]) )
+ {
+ return StringView(ptr, ii + 1);
+ }
}
+
+ return StringView(_str.getPtr(), _str.getPtr());
}
return _str;
@@ -539,29 +556,24 @@ namespace bx
return strLTrim(strRTrim(_str, _chars), _chars);
}
+ StringView strTrimSpace(const StringView& _str)
+ {
+ return strLTrimSpace(strRTrimSpace(_str) );
+ }
+
constexpr uint32_t kFindStep = 1024;
StringView strFindNl(const StringView& _str)
{
StringView str(_str);
- for (; str.getPtr() != _str.getTerm()
- ; str = StringView(min(str.getPtr() + kFindStep, _str.getTerm() ), min(str.getPtr() + kFindStep*2, _str.getTerm() ) )
- )
+ // This method returns the character past the \n, so
+ // there is no need to look for he \r which preceedes it.
+ StringView eol = strFind(str, "\n");
+ if (!eol.isEmpty() )
{
- StringView eol = strFind(str, "\r\n");
- if (!eol.isEmpty() )
- {
- return StringView(eol.getTerm(), _str.getTerm() );
- }
-
- eol = strFind(str, '\n');
- if (!eol.isEmpty() )
- {
- return StringView(eol.getTerm(), _str.getTerm() );
- }
+ return StringView(eol.getTerm(), str.getTerm() );
}
-
return StringView(_str.getTerm(), _str.getTerm() );
}
@@ -669,7 +681,7 @@ namespace bx
StringView ptr = strFind(_str, _word);
for (; !ptr.isEmpty(); ptr = strFind(StringView(ptr.getPtr() + len, _str.getTerm() ), _word) )
{
- char ch = *(ptr.getPtr() - 1);
+ char ch = ptr.getPtr() != _str.getPtr() ? *(ptr.getPtr() - 1) : ' ';
if (isAlphaNum(ch) || '_' == ch)
{
continue;
@@ -687,9 +699,10 @@ namespace bx
return StringView(_str.getTerm(), _str.getTerm() );
}
- StringView findIdentifierMatch(const StringView& _str, const char** _words)
+ StringView findIdentifierMatch(const StringView& _str, const char** _words, int32_t _num)
{
- for (StringView word = *_words; !word.isEmpty(); ++_words, word = *_words)
+ int32_t ii = 0;
+ for (StringView word = *_words; ii < _num && !word.isEmpty(); ++ii, ++_words, word = *_words)
{
StringView match = findIdentifierMatch(_str, word);
if (!match.isEmpty() )
@@ -733,13 +746,40 @@ namespace bx
{
int32_t size = 0;
int32_t len = (int32_t)strLen(_str, _len);
- int32_t padding = _param.width > len ? _param.width - len : 0;
- bool sign = _param.sign && len > 1 && _str[0] != '-';
- padding = padding > 0 ? padding - sign : 0;
+
+ if (_param.width > 0)
+ {
+ len = min(_param.width, len);
+ }
+
+ const bool hasMinus = (NULL != _str && '-' == _str[0]);
+ const bool hasSign = _param.sign || hasMinus;
+ char sign = hasSign ? hasMinus ? '-' : '+' : '\0';
+
+ const char* str = _str;
+ if (hasMinus)
+ {
+ str++;
+ len--;
+ }
+
+ int32_t padding = _param.width > len ? _param.width - len - hasSign: 0;
if (!_param.left)
{
- size += writeRep(_writer, _param.fill, padding, _err);
+ if (' ' != _param.fill
+ && '\0' != sign)
+ {
+ size += write(_writer, sign, _err);
+ sign = '\0';
+ }
+
+ size += writeRep(_writer, _param.fill, max(0, padding), _err);
+ }
+
+ if ('\0' != sign)
+ {
+ size += write(_writer, sign, _err);
}
if (NULL == _str)
@@ -750,17 +790,12 @@ namespace bx
{
for (int32_t ii = 0; ii < len; ++ii)
{
- size += write(_writer, toUpper(_str[ii]), _err);
+ size += write(_writer, toUpper(str[ii]), _err);
}
}
- else if (sign)
- {
- size += write(_writer, '+', _err);
- size += write(_writer, _str, len, _err);
- }
else
{
- size += write(_writer, _str, len, _err);
+ size += write(_writer, str, len, _err);
}
if (_param.left)
@@ -781,6 +816,11 @@ namespace bx
return write(_writer, _str, _param.prec, _param, _err);
}
+ static int32_t write(WriterI* _writer, const StringView& _str, const Param& _param, Error* _err)
+ {
+ return write(_writer, _str.getPtr(), min(_param.prec, _str.getLength() ), _param, _err);
+ }
+
static int32_t write(WriterI* _writer, int32_t _i, const Param& _param, Error* _err)
{
char str[33];
@@ -843,30 +883,39 @@ namespace bx
return 0;
}
- if (_param.upper)
- {
- toUpperUnsafe(str, len);
- }
-
const char* dot = strFind(str, INT32_MAX, '.');
if (NULL != dot)
{
- const int32_t prec = INT32_MAX == _param.prec ? 6 : _param.prec;
- const int32_t precLen = int32_t(
- dot
- + uint32_min(prec + _param.spec, 1)
- + prec
- - str
- );
- if (precLen > len)
+ const int32_t prec = INT32_MAX == _param.prec ? 6 : _param.prec;
+ const char* strEnd = str + len;
+ const char* exponent = strFind(str, INT32_MAX, 'e');
+ const char* fracEnd = NULL != exponent ? exponent : strEnd;
+
+ char* fracBegin = &str[dot - str + min(prec + _param.spec, 1)];
+ const int32_t curPrec = int32_t(fracEnd - fracBegin);
+
+ // Move exponent to its final location after trimming or adding extra 0s.
+ if (fracEnd != strEnd)
+ {
+ const int32_t exponentLen = int32_t(strEnd - fracEnd);
+ char* finalExponentPtr = &fracBegin[prec];
+ memMove(finalExponentPtr, fracEnd, exponentLen);
+
+ finalExponentPtr[exponentLen] = '\0';
+ len = int32_t(&finalExponentPtr[exponentLen] - str);
+ }
+ else
{
- for (int32_t ii = len; ii < precLen; ++ii)
+ len = (int32_t)(fracBegin + prec - str);
+ }
+
+ if (curPrec < prec)
+ {
+ for (int32_t ii = curPrec; ii < prec; ++ii)
{
- str[ii] = '0';
+ fracBegin[ii] = '0';
}
- str[precLen] = '\0';
}
- len = precLen;
}
return write(_writer, str, len, _param, _err);
@@ -907,17 +956,22 @@ namespace bx
}
else if ('%' == ch)
{
- // %[flags][width][.precision][length sub-specifier]specifier
- read(&reader, ch);
+ // %[Flags][Width][.Precision][Leegth]Type
+ read(&reader, ch, &err);
Param param;
- // flags
- while (' ' == ch
+ // Reference(s):
+ // - Flags field
+ // https://en.wikipedia.org/wiki/Printf_format_string#Flags_field
+ //
+ while (err.isOk()
+ && ( ' ' == ch
|| '-' == ch
|| '+' == ch
|| '0' == ch
|| '#' == ch)
+ )
{
switch (ch)
{
@@ -929,7 +983,7 @@ namespace bx
case '#': param.spec = true; break;
}
- read(&reader, ch);
+ read(&reader, ch, &err);
}
if (param.left)
@@ -937,10 +991,13 @@ namespace bx
param.fill = ' ';
}
- // width
+ // Reference(s):
+ // - Width field
+ // https://en.wikipedia.org/wiki/Printf_format_string#Width_field
+ //
if ('*' == ch)
{
- read(&reader, ch);
+ read(&reader, ch, &err);
param.width = va_arg(_argList, int32_t);
if (0 > param.width)
@@ -952,49 +1009,57 @@ namespace bx
}
else
{
- while (isNumeric(ch) )
+ while (err.isOk()
+ && isNumeric(ch) )
{
param.width = param.width * 10 + ch - '0';
- read(&reader, ch);
+ read(&reader, ch, &err);
}
}
- // .precision
+ // Reference(s):
+ // - Precision field
+ // https://en.wikipedia.org/wiki/Printf_format_string#Precision_field
if ('.' == ch)
{
- read(&reader, ch);
+ read(&reader, ch, &err);
if ('*' == ch)
{
- read(&reader, ch);
+ read(&reader, ch, &err);
param.prec = va_arg(_argList, int32_t);
}
else
{
param.prec = 0;
- while (isNumeric(ch) )
+ while (err.isOk()
+ && isNumeric(ch) )
{
param.prec = param.prec * 10 + ch - '0';
- read(&reader, ch);
+ read(&reader, ch, &err);
}
}
}
- // length sub-specifier
- while ('h' == ch
+ // Reference(s):
+ // - Length field
+ // https://en.wikipedia.org/wiki/Printf_format_string#Length_field
+ while (err.isOk()
+ && ( 'h' == ch
|| 'I' == ch
|| 'l' == ch
|| 'j' == ch
|| 't' == ch
|| 'z' == ch)
+ )
{
switch (ch)
{
default: break;
case 'j': param.bits = sizeof(intmax_t )*8; break;
- case 't': param.bits = sizeof(size_t )*8; break;
- case 'z': param.bits = sizeof(ptrdiff_t)*8; break;
+ case 't': param.bits = sizeof(ptrdiff_t)*8; break;
+ case 'z': param.bits = sizeof(size_t )*8; break;
case 'h': case 'I': case 'l':
switch (ch)
@@ -1004,14 +1069,14 @@ namespace bx
default: break;
}
- read(&reader, ch);
+ read(&reader, ch, &err);
switch (ch)
{
case 'h': param.bits = sizeof(signed char )*8; break;
case 'l': param.bits = sizeof(long long int)*8; break;
case '3':
case '6':
- read(&reader, ch);
+ read(&reader, ch, &err);
switch (ch)
{
case '2': param.bits = sizeof(int32_t)*8; break;
@@ -1025,11 +1090,18 @@ namespace bx
break;
}
- read(&reader, ch);
+ read(&reader, ch, &err);
+ }
+
+ if (!err.isOk() )
+ {
+ break;
}
- // specifier
- switch (toLower(ch) )
+ // Reference(s):
+ // - Type field
+ // https://en.wikipedia.org/wiki/Printf_format_string#Type_field
+ switch (ch)
{
case 'c':
size += write(_writer, char(va_arg(_argList, int32_t) ), param, _err);
@@ -1039,6 +1111,10 @@ namespace bx
size += write(_writer, va_arg(_argList, const char*), param, _err);
break;
+ case 'S':
+ size += write(_writer, *va_arg(_argList, const StringView*), param, _err);
+ break;
+
case 'o':
param.base = 8;
switch (param.bits)
@@ -1059,8 +1135,11 @@ namespace bx
break;
case 'e':
+ case 'E':
case 'f':
+ case 'F':
case 'g':
+ case 'G':
param.upper = isUpper(ch);
size += write(_writer, va_arg(_argList, double), param, _err);
break;
@@ -1070,6 +1149,7 @@ namespace bx
break;
case 'x':
+ case 'X':
param.base = 16;
param.upper = isUpper(ch);
switch (param.bits)
@@ -1088,6 +1168,10 @@ namespace bx
}
break;
+ case 'n':
+ *va_arg(_argList, int32_t*) = size;
+ break;
+
default:
size += write(_writer, ch, _err);
break;
@@ -1147,10 +1231,10 @@ namespace bx
SizerWriter sizer;
va_list argListCopy;
va_copy(argListCopy, _argList);
- int32_t size = write(&sizer, _format, argListCopy, &err);
+ int32_t total = write(&sizer, _format, argListCopy, &err);
va_end(argListCopy);
- return size;
+ return total;
}
int32_t snprintf(char* _out, int32_t _max, const char* _format, ...)
@@ -1159,6 +1243,28 @@ namespace bx
va_start(argList, _format);
int32_t total = vsnprintf(_out, _max, _format, argList);
va_end(argList);
+
+ return total;
+ }
+
+ int32_t vprintf(const char* _format, va_list _argList)
+ {
+ Error err;
+ va_list argListCopy;
+ va_copy(argListCopy, _argList);
+ int32_t total = write(getStdOut(), _format, argListCopy, &err);
+ va_end(argListCopy);
+
+ return total;
+ }
+
+ int32_t printf(const char* _format, ...)
+ {
+ va_list argList;
+ va_start(argList, _format);
+ int32_t total = vprintf(_format, argList);
+ va_end(argList);
+
return total;
}
diff --git a/3rdparty/bx/src/thread.cpp b/3rdparty/bx/src/thread.cpp
index f52e0bdcbf4..f5e5f81bc21 100644
--- a/3rdparty/bx/src/thread.cpp
+++ b/3rdparty/bx/src/thread.cpp
@@ -1,39 +1,45 @@
/*
- * Copyright 2010-2018 Branimir Karadzic. All rights reserved.
- * License: https://github.com/bkaradzic/bx#license-bsd-2-clause
+ * Copyright 2010-2022 Branimir Karadzic. All rights reserved.
+ * License: https://github.com/bkaradzic/bx/blob/master/LICENSE
*/
-#include "bx_p.h"
+#include <bx/os.h>
#include <bx/thread.h>
#if BX_CONFIG_SUPPORTS_THREADING
+#if BX_PLATFORM_WINDOWS && !BX_CRT_NONE
+# include <bx/string.h>
+#endif
+
#if BX_CRT_NONE
# include "crt0.h"
#elif BX_PLATFORM_ANDROID \
+ || BX_PLATFORM_BSD \
+ || BX_PLATFORM_HAIKU \
|| BX_PLATFORM_LINUX \
|| BX_PLATFORM_IOS \
|| BX_PLATFORM_OSX \
|| BX_PLATFORM_PS4 \
- || BX_PLATFORM_RPI
+ || BX_PLATFORM_RPI \
+ || BX_PLATFORM_NX
# include <pthread.h>
-# if defined(__FreeBSD__)
+# if BX_PLATFORM_BSD
# include <pthread_np.h>
-# endif
+# endif // BX_PLATFORM_BSD
# if BX_PLATFORM_LINUX && (BX_CRT_GLIBC < 21200)
# include <sys/prctl.h>
# endif // BX_PLATFORM_
#elif BX_PLATFORM_WINDOWS \
|| BX_PLATFORM_WINRT \
- || BX_PLATFORM_XBOXONE
+ || BX_PLATFORM_XBOXONE \
+ || BX_PLATFORM_WINRT
+# ifndef WIN32_LEAN_AND_MEAN
+# define WIN32_LEAN_AND_MEAN
+# endif // WIN32_LEAN_AND_MEAN
# include <windows.h>
# include <limits.h>
# include <errno.h>
-# if BX_PLATFORM_WINRT
-using namespace Platform;
-using namespace Windows::Foundation;
-using namespace Windows::System::Threading;
-# endif // BX_PLATFORM_WINRT
#endif // BX_PLATFORM_
namespace bx
@@ -122,20 +128,25 @@ namespace bx
}
}
- void Thread::init(ThreadFn _fn, void* _userData, uint32_t _stackSize, const char* _name)
+ bool Thread::init(ThreadFn _fn, void* _userData, uint32_t _stackSize, const char* _name)
{
- BX_CHECK(!m_running, "Already running!");
+ BX_ASSERT(!m_running, "Already running!");
m_fn = _fn;
m_userData = _userData;
m_stackSize = _stackSize;
- m_running = true;
ThreadInternal* ti = (ThreadInternal*)m_internal;
#if BX_CRT_NONE
ti->m_handle = crt0::threadCreate(&ti->threadFunc, _userData, m_stackSize, _name);
+
+ if (NULL == ti->m_handle)
+ {
+ return false;
+ }
#elif BX_PLATFORM_WINDOWS \
- || BX_PLATFORM_XBOXONE
+ || BX_PLATFORM_XBOXONE \
+ || BX_PLATFORM_WINRT
ti->m_handle = ::CreateThread(NULL
, m_stackSize
, (LPTHREAD_START_ROUTINE)ti->threadFunc
@@ -143,48 +154,57 @@ namespace bx
, 0
, NULL
);
-#elif BX_PLATFORM_WINRT
- ti->m_handle = CreateEventEx(nullptr, nullptr, CREATE_EVENT_MANUAL_RESET, EVENT_ALL_ACCESS);
- auto workItemHandler = ref new WorkItemHandler([=](IAsyncAction^)
- {
- m_exitCode = ti->threadFunc(this);
- SetEvent(ti->m_handle);
- }
- , CallbackContext::Any
- );
-
- ThreadPool::RunAsync(workItemHandler, WorkItemPriority::Normal, WorkItemOptions::TimeSliced);
+ if (NULL == ti->m_handle)
+ {
+ return false;
+ }
#elif BX_PLATFORM_POSIX
int result;
BX_UNUSED(result);
pthread_attr_t attr;
result = pthread_attr_init(&attr);
- BX_CHECK(0 == result, "pthread_attr_init failed! %d", result);
+ BX_WARN(0 == result, "pthread_attr_init failed! %d", result);
+ if (0 != result)
+ {
+ return false;
+ }
if (0 != m_stackSize)
{
result = pthread_attr_setstacksize(&attr, m_stackSize);
- BX_CHECK(0 == result, "pthread_attr_setstacksize failed! %d", result);
+ BX_WARN(0 == result, "pthread_attr_setstacksize failed! %d", result);
+
+ if (0 != result)
+ {
+ return false;
+ }
}
result = pthread_create(&ti->m_handle, &attr, &ti->threadFunc, this);
- BX_CHECK(0 == result, "pthread_attr_setschedparam failed! %d", result);
+ BX_WARN(0 == result, "pthread_attr_setschedparam failed! %d", result);
+ if (0 != result)
+ {
+ return false;
+ }
#else
# error "Not implemented!"
#endif // BX_PLATFORM_
+ m_running = true;
m_sem.wait();
if (NULL != _name)
{
setThreadName(_name);
}
+
+ return true;
}
void Thread::shutdown()
{
- BX_CHECK(m_running, "Not running!");
+ BX_ASSERT(m_running, "Not running!");
ThreadInternal* ti = (ThreadInternal*)m_internal;
#if BX_CRT_NONE
crt0::threadJoin(ti->m_handle, NULL);
@@ -240,33 +260,47 @@ namespace bx
# else
pthread_set_name_np(ti->m_handle, _name);
# endif // defined(__NetBSD__)
-#elif BX_PLATFORM_WINDOWS && BX_COMPILER_MSVC
-# pragma pack(push, 8)
- struct ThreadName
- {
- DWORD type;
- LPCSTR name;
- DWORD id;
- DWORD flags;
- };
-# pragma pack(pop)
- ThreadName tn;
- tn.type = 0x1000;
- tn.name = _name;
- tn.id = ti->m_threadId;
- tn.flags = 0;
-
- __try
- {
- RaiseException(0x406d1388
- , 0
- , sizeof(tn)/4
- , reinterpret_cast<ULONG_PTR*>(&tn)
- );
- }
- __except(EXCEPTION_EXECUTE_HANDLER)
+#elif BX_PLATFORM_WINDOWS
+ // Try to use the new thread naming API from Win10 Creators update onwards if we have it
+ typedef HRESULT (WINAPI *SetThreadDescriptionProc)(HANDLE, PCWSTR);
+ SetThreadDescriptionProc SetThreadDescription = dlsym<SetThreadDescriptionProc>((void*)GetModuleHandleA("Kernel32.dll"), "SetThreadDescription");
+
+ if (NULL != SetThreadDescription)
{
+ uint32_t length = (uint32_t)strLen(_name)+1;
+ uint32_t size = length*sizeof(wchar_t);
+ wchar_t* name = (wchar_t*)alloca(size);
+ mbstowcs(name, _name, size-2);
+ SetThreadDescription(ti->m_handle, name);
}
+# if BX_COMPILER_MSVC
+# pragma pack(push, 8)
+ struct ThreadName
+ {
+ DWORD type;
+ LPCSTR name;
+ DWORD id;
+ DWORD flags;
+ };
+# pragma pack(pop)
+ ThreadName tn;
+ tn.type = 0x1000;
+ tn.name = _name;
+ tn.id = ti->m_threadId;
+ tn.flags = 0;
+
+ __try
+ {
+ RaiseException(0x406d1388
+ , 0
+ , sizeof(tn)/4
+ , reinterpret_cast<ULONG_PTR*>(&tn)
+ );
+ }
+ __except(EXCEPTION_EXECUTE_HANDLER)
+ {
+ }
+# endif // BX_COMPILER_MSVC
#else
BX_UNUSED(_name);
#endif // BX_PLATFORM_
@@ -339,14 +373,14 @@ namespace bx
TlsDataInternal* ti = (TlsDataInternal*)m_internal;
ti->m_id = TlsAlloc();
- BX_CHECK(TLS_OUT_OF_INDEXES != ti->m_id, "Failed to allocated TLS index (err: 0x%08x).", GetLastError() );
+ BX_ASSERT(TLS_OUT_OF_INDEXES != ti->m_id, "Failed to allocated TLS index (err: 0x%08x).", GetLastError() );
}
TlsData::~TlsData()
{
TlsDataInternal* ti = (TlsDataInternal*)m_internal;
BOOL result = TlsFree(ti->m_id);
- BX_CHECK(0 != result, "Failed to free TLS index (err: 0x%08x).", GetLastError() ); BX_UNUSED(result);
+ BX_ASSERT(0 != result, "Failed to free TLS index (err: 0x%08x).", GetLastError() ); BX_UNUSED(result);
}
void* TlsData::get() const
@@ -369,14 +403,14 @@ namespace bx
TlsDataInternal* ti = (TlsDataInternal*)m_internal;
int result = pthread_key_create(&ti->m_id, NULL);
- BX_CHECK(0 == result, "pthread_key_create failed %d.", result); BX_UNUSED(result);
+ BX_ASSERT(0 == result, "pthread_key_create failed %d.", result); BX_UNUSED(result);
}
TlsData::~TlsData()
{
TlsDataInternal* ti = (TlsDataInternal*)m_internal;
int result = pthread_key_delete(ti->m_id);
- BX_CHECK(0 == result, "pthread_key_delete failed %d.", result); BX_UNUSED(result);
+ BX_ASSERT(0 == result, "pthread_key_delete failed %d.", result); BX_UNUSED(result);
}
void* TlsData::get() const
@@ -389,7 +423,7 @@ namespace bx
{
TlsDataInternal* ti = (TlsDataInternal*)m_internal;
int result = pthread_setspecific(ti->m_id, _ptr);
- BX_CHECK(0 == result, "pthread_setspecific failed %d.", result); BX_UNUSED(result);
+ BX_ASSERT(0 == result, "pthread_setspecific failed %d.", result); BX_UNUSED(result);
}
#endif // BX_PLATFORM_*
diff --git a/3rdparty/bx/src/timer.cpp b/3rdparty/bx/src/timer.cpp
index 8cfebdda7f5..faecf822e10 100644
--- a/3rdparty/bx/src/timer.cpp
+++ b/3rdparty/bx/src/timer.cpp
@@ -1,9 +1,8 @@
/*
- * Copyright 2010-2018 Branimir Karadzic. All rights reserved.
- * License: https://github.com/bkaradzic/bx#license-bsd-2-clause
+ * Copyright 2010-2022 Branimir Karadzic. All rights reserved.
+ * License: https://github.com/bkaradzic/bx/blob/master/LICENSE
*/
-#include "bx_p.h"
#include <bx/timer.h>
#if BX_CRT_NONE
@@ -13,6 +12,9 @@
#elif BX_PLATFORM_EMSCRIPTEN
# include <emscripten.h>
#elif BX_PLATFORM_WINDOWS || BX_PLATFORM_XBOXONE || BX_PLATFORM_WINRT
+# ifndef WIN32_LEAN_AND_MEAN
+# define WIN32_LEAN_AND_MEAN
+# endif // WIN32_LEAN_AND_MEAN
# include <windows.h>
#else
# include <sys/time.h> // gettimeofday
@@ -41,7 +43,7 @@ namespace bx
gettimeofday(&now, 0);
int64_t i64 = now.tv_sec*INT64_C(1000000) + now.tv_usec;
#else
- BX_CHECK(false, "Not implemented!");
+ BX_ASSERT(false, "Not implemented!");
int64_t i64 = UINT64_MAX;
#endif // BX_PLATFORM_
return i64;
diff --git a/3rdparty/bx/src/url.cpp b/3rdparty/bx/src/url.cpp
index f58ecf5a9c3..5421fd01a47 100644
--- a/3rdparty/bx/src/url.cpp
+++ b/3rdparty/bx/src/url.cpp
@@ -1,9 +1,8 @@
/*
- * Copyright 2011-2018 Branimir Karadzic. All rights reserved.
+ * Copyright 2011-2022 Branimir Karadzic. All rights reserved.
* License: https://github.com/bkaradzic/bnet#license-bsd-2-clause
*/
-#include "bx_p.h"
#include <bx/url.h>
namespace bx
diff --git a/3rdparty/bx/tests/allocator_test.cpp b/3rdparty/bx/tests/allocator_test.cpp
new file mode 100644
index 00000000000..635d01a3175
--- /dev/null
+++ b/3rdparty/bx/tests/allocator_test.cpp
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2010-2022 Branimir Karadzic. All rights reserved.
+ * License: https://github.com/bkaradzic/bx/blob/master/LICENSE
+ */
+
+#include "test.h"
+
+#include <bx/allocator.h>
+
+struct MockNonFreeingAllocator : public bx::AllocatorI
+{
+ MockNonFreeingAllocator()
+ : m_sbrk(1)
+ {
+ }
+
+ ~MockNonFreeingAllocator() override
+ {
+ }
+
+ void* realloc(void* _ptr, size_t _size, size_t _align, const char* _file, uint32_t _line) override
+ {
+ BX_ASSERT(_ptr == NULL, "MockNonFreeingAllocator can't realloc or free.");
+ BX_ASSERT(m_sbrk + _size < BX_COUNTOF(m_storage), "");
+ BX_UNUSED(_ptr, _file, _line);
+
+ const uint32_t sbrk = bx::alignUp(m_sbrk, bx::max(_align, 1) );
+ m_sbrk = sbrk + _size;
+
+ return &m_storage[sbrk];
+ }
+
+ uint32_t m_sbrk;
+ BX_ALIGN_DECL(256, uint8_t) m_storage[0x10000];
+};
+
+bool testAlignment(size_t _expected, void* _ptr)
+{
+ bool aligned = bx::isAligned(_ptr, _expected);
+// BX_TRACE("%p, %d", _ptr, _expected);
+ BX_WARN(aligned, "%p not aligned to %d bytes.", _ptr, _expected);
+ return aligned;
+}
+
+TEST_CASE("Allocator", "")
+{
+ MockNonFreeingAllocator mnfa;
+
+ REQUIRE(testAlignment(1, bx::alloc (&mnfa, 1, 1 ) ) );
+ REQUIRE(testAlignment(2, bx::alloc (&mnfa, 1, 2 ) ) );
+ REQUIRE(testAlignment(1, bx::alloc (&mnfa, 1, 1 ) ) );
+ REQUIRE(testAlignment(4, bx::alloc (&mnfa, 1, 4 ) ) );
+ REQUIRE(testAlignment(1, bx::alloc (&mnfa, 1, 1 ) ) );
+ REQUIRE(testAlignment(8, bx::alloc (&mnfa, 1, 8 ) ) );
+ REQUIRE(testAlignment(1, bx::alloc (&mnfa, 1, 1 ) ) );
+ REQUIRE(testAlignment(16, bx::alloc (&mnfa, 1, 16 ) ) );
+ REQUIRE(testAlignment(1, bx::alloc (&mnfa, 1, 1 ) ) );
+ REQUIRE(testAlignment(32, bx::alloc (&mnfa, 1, 32 ) ) );
+ REQUIRE(testAlignment(1, bx::alloc (&mnfa, 1, 1 ) ) );
+ REQUIRE(testAlignment(64, bx::alloc (&mnfa, 1, 64 ) ) );
+ REQUIRE(testAlignment(1, bx::alloc (&mnfa, 1, 1 ) ) );
+ REQUIRE(testAlignment(128, bx::alloc (&mnfa, 1, 128) ) );
+
+ REQUIRE(testAlignment(1, bx::alignedAlloc(&mnfa, 1, 1 ) ) );
+ REQUIRE(testAlignment(2, bx::alignedAlloc(&mnfa, 1, 2 ) ) );
+ REQUIRE(testAlignment(1, bx::alignedAlloc(&mnfa, 1, 1 ) ) );
+ REQUIRE(testAlignment(4, bx::alignedAlloc(&mnfa, 1, 4 ) ) );
+ REQUIRE(testAlignment(1, bx::alignedAlloc(&mnfa, 1, 1 ) ) );
+ REQUIRE(testAlignment(8, bx::alignedAlloc(&mnfa, 1, 8 ) ) );
+ REQUIRE(testAlignment(1, bx::alignedAlloc(&mnfa, 1, 1 ) ) );
+ REQUIRE(testAlignment(16, bx::alignedAlloc(&mnfa, 1, 16 ) ) );
+ REQUIRE(testAlignment(1, bx::alignedAlloc(&mnfa, 1, 1 ) ) );
+ REQUIRE(testAlignment(32, bx::alignedAlloc(&mnfa, 1, 32 ) ) );
+ REQUIRE(testAlignment(1, bx::alignedAlloc(&mnfa, 1, 1 ) ) );
+ REQUIRE(testAlignment(64, bx::alignedAlloc(&mnfa, 1, 64 ) ) );
+ REQUIRE(testAlignment(1, bx::alignedAlloc(&mnfa, 1, 1 ) ) );
+ REQUIRE(testAlignment(128, bx::alignedAlloc(&mnfa, 1, 128) ) );
+}
diff --git a/3rdparty/bx/tests/atomic_test.cpp b/3rdparty/bx/tests/atomic_test.cpp
index 04a623686e7..a4278f3138f 100644
--- a/3rdparty/bx/tests/atomic_test.cpp
+++ b/3rdparty/bx/tests/atomic_test.cpp
@@ -1,6 +1,6 @@
/*
- * Copyright 2010-2018 Branimir Karadzic. All rights reserved.
- * License: https://github.com/bkaradzic/bx#license-bsd-2-clause
+ * Copyright 2010-2022 Branimir Karadzic. All rights reserved.
+ * License: https://github.com/bkaradzic/bx/blob/master/LICENSE
*/
#include "test.h"
diff --git a/3rdparty/bx/tests/crt_test.cpp b/3rdparty/bx/tests/crt_test.cpp
index bda079036ee..68476a12cfa 100644
--- a/3rdparty/bx/tests/crt_test.cpp
+++ b/3rdparty/bx/tests/crt_test.cpp
@@ -1,6 +1,6 @@
/*
- * Copyright 2010-2018 Branimir Karadzic. All rights reserved.
- * License: https://github.com/bkaradzic/bx#license-bsd-2-clause
+ * Copyright 2010-2022 Branimir Karadzic. All rights reserved.
+ * License: https://github.com/bkaradzic/bx/blob/master/LICENSE
*/
#include "test.h"
@@ -23,14 +23,14 @@ TEST_CASE("memSet", "")
TEST_CASE("memMove", "")
{
- const char* orignal = "xxxxabvgd";
+ const char* original = "xxxxabvgd";
char str[] = { 'x', 'x', 'x', 'x', 'a', 'b', 'v', 'g', 'd' };
bx::memMove(&str[4], &str[4], 0);
- REQUIRE(0 == bx::memCmp(str, orignal, 9) );
+ REQUIRE(0 == bx::memCmp(str, original, 9) );
bx::memMove(&str[4], &str[4], 5);
- REQUIRE(0 == bx::memCmp(str, orignal, 9) );
+ REQUIRE(0 == bx::memCmp(str, original, 9) );
bx::memMove(str, &str[4], 5);
REQUIRE(0 == bx::memCmp(str, "abvgd", 5) );
@@ -39,5 +39,20 @@ TEST_CASE("memMove", "")
REQUIRE(str[4] == 'a' );
bx::memSet(str, 'x', 4);
- REQUIRE(0 == bx::memCmp(str, orignal, 9) );
+ REQUIRE(0 == bx::memCmp(str, original, 9) );
+}
+
+TEST_CASE("scatter/gather", "")
+{
+ const char* str = "a\0b\0v\0g\0d";
+
+ char tmp0[64];
+ bx::gather(tmp0, str, 2, 1, 5);
+ REQUIRE(0 == bx::memCmp(tmp0, "abvgd", 5) );
+
+ char tmp1[64];
+ bx::scatter(tmp1, 2, tmp0, 1, 5);
+ bx::memSet(&tmp1[1], 2, 0, 1, 5);
+ REQUIRE(0 == bx::memCmp(tmp1, str, 5) );
+
}
diff --git a/3rdparty/bx/tests/dbg.h b/3rdparty/bx/tests/dbg.h
index 243dc234afc..9aee6bb77a4 100644
--- a/3rdparty/bx/tests/dbg.h
+++ b/3rdparty/bx/tests/dbg.h
@@ -1,6 +1,6 @@
/*
- * Copyright 2011-2018 Branimir Karadzic. All rights reserved.
- * License: https://github.com/bkaradzic/bx#license-bsd-2-clause
+ * Copyright 2011-2022 Branimir Karadzic. All rights reserved.
+ * License: https://github.com/bkaradzic/bx/blob/master/LICENSE
*/
#ifndef DBG_H_HEADER_GUARD
diff --git a/3rdparty/bx/tests/easing_test.cpp b/3rdparty/bx/tests/easing_test.cpp
index 06944547f4a..44f6f7f987e 100644
--- a/3rdparty/bx/tests/easing_test.cpp
+++ b/3rdparty/bx/tests/easing_test.cpp
@@ -1,6 +1,6 @@
/*
- * Copyright 2010-2018 Branimir Karadzic. All rights reserved.
- * License: https://github.com/bkaradzic/bx#license-bsd-2-clause
+ * Copyright 2010-2022 Branimir Karadzic. All rights reserved.
+ * License: https://github.com/bkaradzic/bx/blob/master/LICENSE
*/
#include "test.h"
@@ -42,7 +42,7 @@ TEST_CASE("easing", "")
if (vv >= ys
&& vv < ye)
{
- bx::write(writer, "*");
+ bx::write(writer, &err, "*");
break;
}
}
diff --git a/3rdparty/bx/tests/filepath_test.cpp b/3rdparty/bx/tests/filepath_test.cpp
index 2662adeddf1..7484c48eab8 100644
--- a/3rdparty/bx/tests/filepath_test.cpp
+++ b/3rdparty/bx/tests/filepath_test.cpp
@@ -1,10 +1,10 @@
/*
- * Copyright 2010-2018 Branimir Karadzic. All rights reserved.
- * License: https://github.com/bkaradzic/bx#license-bsd-2-clause
+ * Copyright 2010-2022 Branimir Karadzic. All rights reserved.
+ * License: https://github.com/bkaradzic/bx/blob/master/LICENSE
*/
#include "test.h"
-#include <bx/filepath.h>
+#include <bx/file.h>
struct FilePathTest
{
@@ -96,9 +96,8 @@ TEST_CASE("FilePath", "")
const FilePathTest& test = s_filePathTest[ii];
fp.set(test.filePath);
- const bx::StringView result = fp.get();
- REQUIRE(0 == bx::strCmp(test.expected, result) );
+ REQUIRE(0 == bx::strCmp(test.expected, fp) );
}
for (uint32_t ii = 0; ii < BX_COUNTOF(s_filePathSplit); ++ii)
diff --git a/3rdparty/bx/tests/handle_bench.cpp b/3rdparty/bx/tests/handle_bench.cpp
index 4effb59758e..f6f1b203fc5 100644
--- a/3rdparty/bx/tests/handle_bench.cpp
+++ b/3rdparty/bx/tests/handle_bench.cpp
@@ -1,6 +1,6 @@
/*
- * Copyright 2010-2018 Branimir Karadzic. All rights reserved.
- * License: https://github.com/bkaradzic/bx#license-bsd-2-clause
+ * Copyright 2010-2022 Branimir Karadzic. All rights reserved.
+ * License: https://github.com/bkaradzic/bx/blob/master/LICENSE
*/
#include <bx/timer.h>
diff --git a/3rdparty/bx/tests/handle_test.cpp b/3rdparty/bx/tests/handle_test.cpp
index eb89b1f67a9..0d91e51883d 100644
--- a/3rdparty/bx/tests/handle_test.cpp
+++ b/3rdparty/bx/tests/handle_test.cpp
@@ -1,6 +1,6 @@
/*
- * Copyright 2010-2018 Branimir Karadzic. All rights reserved.
- * License: https://github.com/bkaradzic/bx#license-bsd-2-clause
+ * Copyright 2010-2022 Branimir Karadzic. All rights reserved.
+ * License: https://github.com/bkaradzic/bx/blob/master/LICENSE
*/
#include "test.h"
diff --git a/3rdparty/bx/tests/hash_test.cpp b/3rdparty/bx/tests/hash_test.cpp
index 1ec6702080e..cc827aee0fc 100644
--- a/3rdparty/bx/tests/hash_test.cpp
+++ b/3rdparty/bx/tests/hash_test.cpp
@@ -1,6 +1,6 @@
/*
- * Copyright 2010-2018 Branimir Karadzic. All rights reserved.
- * License: https://github.com/bkaradzic/bx#license-bsd-2-clause
+ * Copyright 2010-2022 Branimir Karadzic. All rights reserved.
+ * License: https://github.com/bkaradzic/bx/blob/master/LICENSE
*/
#include "test.h"
@@ -29,19 +29,22 @@ void makeCrcTable(uint32_t _poly)
struct HashTest
{
- uint32_t crc32;
+ uint32_t crc32[bx::HashCrc32::Count];
uint32_t adler32;
+ uint32_t murmur2a;
const char* input;
};
const HashTest s_hashTest[] =
{
- { 0, 1, "" },
- { 0xe8b7be43, 0x00620062, "a" },
- { 0x9e83486d, 0x012600c4, "ab" },
- { 0xc340daab, 0x06060205, "abvgd" },
- { 0x07642fe2, 0x020a00d6, "1389" },
- { 0x26d75737, 0x04530139, "555333" },
+ // Crc32 | Adler32 | Murmur2A | Input
+ // Ieee Castagnoli Koopman | | |
+ { { 0, 0, 0 }, 1, 0, "" },
+ { { 0xe8b7be43, 0xc1d04330, 0x0da2aa8a }, 0x00620062, 0x0803888b, "a" },
+ { { 0x9e83486d, 0xe2a22936, 0x31ec935a }, 0x012600c4, 0x618515af, "ab" },
+ { { 0xc340daab, 0x49e1b6e3, 0x945a1e78 }, 0x06060205, 0x94e3dc4d, "abvgd" },
+ { { 0x07642fe2, 0x45a04162, 0x3d4bf72d }, 0x020a00d6, 0xe602fc07, "1389" },
+ { { 0x26d75737, 0xb73d7b80, 0xd524eb40 }, 0x04530139, 0x58d37863, "555333" },
};
TEST_CASE("HashCrc32", "")
@@ -58,10 +61,13 @@ TEST_CASE("HashCrc32", "")
{
const HashTest& test = s_hashTest[ii];
- bx::HashCrc32 hash;
- hash.begin();
- hash.add(test.input, bx::strLen(test.input) );
- REQUIRE(test.crc32 == hash.end() );
+ for (uint32_t jj = 0; jj < bx::HashCrc32::Count; ++jj)
+ {
+ bx::HashCrc32 hash;
+ hash.begin(bx::HashCrc32::Enum(jj) );
+ hash.add(test.input, bx::strLen(test.input) );
+ REQUIRE(test.crc32[jj] == hash.end() );
+ }
}
}
@@ -77,3 +83,82 @@ TEST_CASE("HashAdler32", "")
REQUIRE(test.adler32 == hash.end() );
}
}
+
+/*-----------------------------------------------------------------------------
+// MurmurHash2A, by Austin Appleby
+//
+// This is a variant of MurmurHash2 modified to use the Merkle-Damgard
+// construction. Bulk speed should be identical to Murmur2, small-key speed
+// will be 10%-20% slower due to the added overhead at the end of the hash.
+//
+// This variant fixes a minor issue where null keys were more likely to
+// collide with each other than expected, and also makes the function
+// more amenable to incremental implementations.
+*/
+
+#define mmix(h,k) { k *= m; k ^= k >> r; k *= m; h *= m; h ^= k; }
+
+uint32_t MurmurHash2A(const void * key, int len, uint32_t seed = 0)
+{
+ const uint32_t m = 0x5bd1e995;
+ const int r = 24;
+ uint32_t l = len;
+
+ const unsigned char * data = (const unsigned char *)key;
+
+ uint32_t h = seed;
+
+ while(len >= 4)
+ {
+ uint32_t k = *(uint32_t*)data;
+
+ mmix(h,k);
+
+ data += 4;
+ len -= 4;
+ }
+
+ uint32_t t = 0;
+
+ switch(len)
+ {
+ case 3: t ^= data[2] << 16; BX_FALLTHROUGH;
+ case 2: t ^= data[1] << 8; BX_FALLTHROUGH;
+ case 1: t ^= data[0];
+ };
+
+ mmix(h,t);
+ mmix(h,l);
+
+ h ^= h >> 13;
+ h *= m;
+ h ^= h >> 15;
+
+ return h;
+}
+
+TEST_CASE("HashMurmur2A", "")
+{
+ uint32_t seed = 0;
+
+ for (uint32_t ii = 0; ii < BX_COUNTOF(s_hashTest); ++ii)
+ {
+ const HashTest& test = s_hashTest[ii];
+
+ bx::HashMurmur2A hash;
+ hash.begin(seed);
+ hash.add(test.input, bx::strLen(test.input) );
+ REQUIRE(test.murmur2a == hash.end() );
+
+ REQUIRE(test.murmur2a == MurmurHash2A(test.input, bx::strLen(test.input), seed) );
+ }
+}
+
+TEST_CASE("HashMurmur2A-Separate-Add", "")
+{
+ bx::HashMurmur2A hash;
+ hash.begin();
+ hash.add("0123456789");
+ hash.add("abvgd012345");
+ REQUIRE(MurmurHash2A("0123456789abvgd012345", 21) == hash.end() );
+}
diff --git a/3rdparty/bx/tests/macros_test.cpp b/3rdparty/bx/tests/macros_test.cpp
index e0d5ffae8b4..75081b95d70 100644
--- a/3rdparty/bx/tests/macros_test.cpp
+++ b/3rdparty/bx/tests/macros_test.cpp
@@ -1,6 +1,6 @@
/*
- * Copyright 2010-2018 Branimir Karadzic. All rights reserved.
- * License: https://github.com/bkaradzic/bx#license-bsd-2-clause
+ * Copyright 2010-2022 Branimir Karadzic. All rights reserved.
+ * License: https://github.com/bkaradzic/bx/blob/master/LICENSE
*/
#include "test.h"
@@ -13,7 +13,6 @@ BX_STATIC_ASSERT(false
|| BX_CRT_LIBCXX
|| BX_CRT_MINGW
|| BX_CRT_MSVC
- || BX_CRT_MUSL
|| BX_CRT_NEWLIB
);
@@ -24,20 +23,6 @@ BX_STATIC_ASSERT(4 == BX_VA_ARGS_COUNT(1, 2, 3, 4) );
BX_STATIC_ASSERT(5 == BX_VA_ARGS_COUNT(1, 2, 3, 4, 5) );
BX_STATIC_ASSERT(6 == BX_VA_ARGS_COUNT(1, 2, 3, 4, 5, 6) );
-BX_STATIC_ASSERT( 0 == BX_ALIGN_16( 0) );
-BX_STATIC_ASSERT( 16 == BX_ALIGN_16( 1) );
-BX_STATIC_ASSERT( 16 == BX_ALIGN_16( 15) );
-BX_STATIC_ASSERT( 16 == BX_ALIGN_16( 16) );
-BX_STATIC_ASSERT(256 == BX_ALIGN_16(255) );
-
-BX_STATIC_ASSERT( 0 == BX_ALIGN_256( 0) );
-BX_STATIC_ASSERT(256 == BX_ALIGN_256( 1) );
-BX_STATIC_ASSERT(256 == BX_ALIGN_256( 15) );
-BX_STATIC_ASSERT(256 == BX_ALIGN_256(255) );
-BX_STATIC_ASSERT(256 == BX_ALIGN_256(256) );
-BX_STATIC_ASSERT(256 == BX_ALIGN_256(256) );
-BX_STATIC_ASSERT(512 == BX_ALIGN_256(511) );
-
BX_NO_INLINE void unusedFunction()
{
CHECK(false);
@@ -62,4 +47,30 @@ TEST(macros)
CHECK_EQUAL(6, BX_VA_ARGS_COUNT(1, 2, 3, 4, 5, 6) );
CHECK_EQUAL(0, bx::strCmp(BX_STRINGIZE(TEST 1234 %^&*), "TEST 1234 %^&*") );
+
+ {
+ struct PodStruct { int32_t x, y, z; };
+ CHECK_EQUAL(0, BX_OFFSETOF(PodStruct, x) );
+ CHECK_EQUAL(4, BX_OFFSETOF(PodStruct, y) );
+ CHECK_EQUAL(8, BX_OFFSETOF(PodStruct, z) );
+ }
+
+ {
+ union PodUnion { int32_t x, y, z; };
+ CHECK_EQUAL(BX_OFFSETOF(PodUnion, x), BX_OFFSETOF(PodUnion, y) );
+ CHECK_EQUAL(BX_OFFSETOF(PodUnion, y), BX_OFFSETOF(PodUnion, z) );
+ }
+
+ {
+ struct NonPodStruct { NonPodStruct() { } int32_t x, y, z; };
+ CHECK_EQUAL(0, BX_OFFSETOF(NonPodStruct, x) );
+ CHECK_EQUAL(4, BX_OFFSETOF(NonPodStruct, y) );
+ CHECK_EQUAL(8, BX_OFFSETOF(NonPodStruct, z) );
+ }
+
+ {
+ union NonPodUnion { NonPodUnion() { } int32_t x, y, z; };
+ CHECK_EQUAL(BX_OFFSETOF(NonPodUnion, x), BX_OFFSETOF(NonPodUnion, y) );
+ CHECK_EQUAL(BX_OFFSETOF(NonPodUnion, y), BX_OFFSETOF(NonPodUnion, z) );
+ }
}
diff --git a/3rdparty/bx/tests/main_test.cpp b/3rdparty/bx/tests/main_test.cpp
index b9e9074a8ea..93ee589e601 100644
--- a/3rdparty/bx/tests/main_test.cpp
+++ b/3rdparty/bx/tests/main_test.cpp
@@ -1,17 +1,17 @@
/*
- * Copyright 2010-2018 Branimir Karadzic. All rights reserved.
- * License: https://github.com/bkaradzic/bx#license-bsd-2-clause
+ * Copyright 2010-2022 Branimir Karadzic. All rights reserved.
+ * License: https://github.com/bkaradzic/bx/blob/master/LICENSE
*/
#include "test.h"
-static const char* s_argv[] = { "bx.test" };
-
int runAllTests(int _argc, const char* _argv[]);
#if BX_PLATFORM_ANDROID
# include <android/native_activity.h>
+static const char* s_argv[] = { "bx.test" };
+
void ANativeActivity_onCreate(ANativeActivity*, void*, size_t)
{
exit(runAllTests(BX_COUNTOF(s_argv), s_argv) );
diff --git a/3rdparty/bx/tests/math_bench.cpp b/3rdparty/bx/tests/math_bench.cpp
index 50a8b3d2301..488369cad4e 100644
--- a/3rdparty/bx/tests/math_bench.cpp
+++ b/3rdparty/bx/tests/math_bench.cpp
@@ -1,6 +1,6 @@
/*
- * Copyright 2010-2018 Branimir Karadzic. All rights reserved.
- * License: https://github.com/bkaradzic/bx#license-bsd-2-clause
+ * Copyright 2010-2022 Branimir Karadzic. All rights reserved.
+ * License: https://github.com/bkaradzic/bx/blob/master/LICENSE
*/
#include <bx/math.h>
@@ -60,6 +60,10 @@ void math_bench()
mathTest<bx::sin >("bx::sin");
bx::write(writer, &err, "\n");
+ mathTest< ::sinhf>(" ::sinhf");
+ mathTest<bx::sinh >("bx::sinh");
+
+ bx::write(writer, &err, "\n");
mathTest< ::asinf>(" ::asinf");
mathTest<bx::asin >("bx::asin");
@@ -68,6 +72,10 @@ void math_bench()
mathTest<bx::cos >("bx::cos");
bx::write(writer, &err, "\n");
+ mathTest< ::coshf>(" ::coshf");
+ mathTest<bx::cosh >("bx::cosh");
+
+ bx::write(writer, &err, "\n");
mathTest< ::acosf>(" ::acosf");
mathTest<bx::acos >("bx::acos");
@@ -76,6 +84,26 @@ void math_bench()
mathTest<bx::tan >("bx::tan");
bx::write(writer, &err, "\n");
+ mathTest< ::tanhf>(" ::tanhf");
+ mathTest<bx::tanh >("bx::tanh");
+
+ bx::write(writer, &err, "\n");
mathTest< ::atanf>(" ::atanf");
mathTest<bx::atan >("bx::atan");
+
+ bx::write(writer, &err, "\n");
+ mathTest< ::expf>(" ::expf");
+ mathTest<bx::exp >("bx::exp");
+
+ bx::write(writer, &err, "\n");
+ mathTest< ::exp2f>(" ::exp2f");
+ mathTest<bx::exp2 >("bx::exp2");
+
+ bx::write(writer, &err, "\n");
+ mathTest< ::logf >(" ::logf");
+ mathTest<bx::log >("bx::log");
+
+ bx::write(writer, &err, "\n");
+ mathTest< ::log2f>(" ::log2f");
+ mathTest<bx::log2 >("bx::log2");
}
diff --git a/3rdparty/bx/tests/math_test.cpp b/3rdparty/bx/tests/math_test.cpp
index 2eeac286282..511655940df 100644
--- a/3rdparty/bx/tests/math_test.cpp
+++ b/3rdparty/bx/tests/math_test.cpp
@@ -1,6 +1,6 @@
/*
- * Copyright 2010-2018 Branimir Karadzic. All rights reserved.
- * License: https://github.com/bkaradzic/bx#license-bsd-2-clause
+ * Copyright 2010-2022 Branimir Karadzic. All rights reserved.
+ * License: https://github.com/bkaradzic/bx/blob/master/LICENSE
*/
#include "test.h"
@@ -8,6 +8,8 @@
#include <bx/file.h>
#include <math.h>
+#include <stdint.h> // intXX_t
+#include <limits.h> // UCHAR_*
#if !BX_COMPILER_MSVC || BX_COMPILER_MSVC >= 1800
TEST_CASE("isFinite, isInfinite, isNan", "")
@@ -31,11 +33,39 @@ TEST_CASE("log2", "")
{
log2_test(0.0f);
log2_test(256.0f);
+
+ REQUIRE(0.0f == bx::log2(1.0f) );
+ REQUIRE(0 == bx::log2(1) );
+
+ REQUIRE(1.0f == bx::log2(2.0f) );
+ REQUIRE(1 == bx::log2(2) );
+
+ REQUIRE(2.0f == bx::log2(4.0f) );
+ REQUIRE(2 == bx::log2(4) );
+
+ REQUIRE(3.0f == bx::log2(8.0f) );
+ REQUIRE(3 == bx::log2(8) );
+
+ REQUIRE(4.0f == bx::log2(16.0f) );
+ REQUIRE(4 == bx::log2(16) );
+
+ REQUIRE(5.0f == bx::log2(32.0f) );
+ REQUIRE(5 == bx::log2(32) );
+
+ REQUIRE(6.0f == bx::log2(64.0f) );
+ REQUIRE(6 == bx::log2(64) );
+
+ REQUIRE(7.0f == bx::log2(128.0f) );
+ REQUIRE(7 == bx::log2(128) );
+
+ REQUIRE(8.0f == bx::log2(256.0f) );
+ REQUIRE(8 == bx::log2(256) );
}
TEST_CASE("libm", "")
{
bx::WriterI* writer = bx::getNullOut();
+ bx::Error err;
REQUIRE(1389.0f == bx::abs(-1389.0f) );
REQUIRE(1389.0f == bx::abs( 1389.0f) );
@@ -43,7 +73,6 @@ TEST_CASE("libm", "")
REQUIRE( 0.0f == bx::abs( 0.0f) );
REQUIRE(389.0f == bx::mod(1389.0f, 1000.0f) );
- REQUIRE(bx::isNan(bx::mod(0.0f, 0.0f) ) );
REQUIRE( 13.0f == bx::floor( 13.89f) );
REQUIRE(-14.0f == bx::floor(-13.89f) );
@@ -52,17 +81,15 @@ TEST_CASE("libm", "")
REQUIRE( 13.0f == bx::trunc( 13.89f) );
REQUIRE(-13.0f == bx::trunc(-13.89f) );
- REQUIRE(bx::equal( 0.89f, bx::fract( 13.89f), 0.000001f) );
- REQUIRE(bx::equal(-0.89f, bx::fract(-13.89f), 0.000001f) );
-
- bx::Error err;
+ REQUIRE(bx::isEqual( 0.89f, bx::fract( 13.89f), 0.000001f) );
+ REQUIRE(bx::isEqual(-0.89f, bx::fract(-13.89f), 0.000001f) );
for (int32_t yy = -10; yy < 10; ++yy)
{
for (float xx = -100.0f; xx < 100.0f; xx += 0.1f)
{
bx::write(writer, &err, "ldexp(%f, %d) == %f (expected: %f)\n", xx, yy, bx::ldexp(xx, yy), ::ldexpf(xx, yy) );
- REQUIRE(bx::equal(bx::ldexp(xx, yy), ::ldexpf(xx, yy), 0.00001f) );
+ REQUIRE(bx::isEqual(bx::ldexp(xx, yy), ::ldexpf(xx, yy), 0.00001f) );
}
}
@@ -70,85 +97,116 @@ TEST_CASE("libm", "")
{
bx::write(writer, &err, "exp(%f) == %f (expected: %f)\n", xx, bx::exp(xx), ::expf(xx) );
REQUIRE(err.isOk() );
- REQUIRE(bx::equal(bx::exp(xx), ::expf(xx), 0.00001f) );
+ REQUIRE(bx::isEqual(bx::exp(xx), ::expf(xx), 0.00001f) );
}
for (float xx = 0.0f; xx < 100.0f; xx += 0.1f)
{
bx::write(writer, &err, "rsqrt(%f) == %f (expected: %f)\n", xx, bx::rsqrt(xx), 1.0f/::sqrtf(xx) );
REQUIRE(err.isOk() );
- REQUIRE(bx::equal(bx::rsqrt(xx), 1.0f/::sqrtf(xx), 0.00001f) );
+ REQUIRE(bx::isEqual(bx::rsqrt(xx), 1.0f/::sqrtf(xx), 0.00001f) );
+ }
+
+ for (float xx = 0.0f; xx < 1000000.0f; xx += 1000.f)
+ {
+ bx::write(writer, &err, "sqrt(%f) == %f (expected: %f)\n", xx, bx::sqrt(xx), ::sqrtf(xx) );
+ REQUIRE(err.isOk() );
+ REQUIRE(bx::isEqual(bx::sqrt(xx), ::sqrtf(xx), 0.00001f) );
}
for (float xx = 0.0f; xx < 100.0f; xx += 0.1f)
{
bx::write(writer, &err, "sqrt(%f) == %f (expected: %f)\n", xx, bx::sqrt(xx), ::sqrtf(xx) );
REQUIRE(err.isOk() );
- REQUIRE(bx::equal(bx::sqrt(xx), ::sqrtf(xx), 0.00001f) );
+ REQUIRE(bx::isEqual(bx::sqrt(xx), ::sqrtf(xx), 0.00001f) );
}
for (float xx = -100.0f; xx < 100.0f; xx += 0.1f)
{
bx::write(writer, &err, "pow(1.389f, %f) == %f (expected: %f)\n", xx, bx::pow(1.389f, xx), ::powf(1.389f, xx) );
REQUIRE(err.isOk() );
- REQUIRE(bx::equal(bx::pow(1.389f, xx), ::powf(1.389f, xx), 0.00001f) );
+ REQUIRE(bx::isEqual(bx::pow(1.389f, xx), ::powf(1.389f, xx), 0.00001f) );
}
for (float xx = -1.0f; xx < 1.0f; xx += 0.001f)
{
bx::write(writer, &err, "asin(%f) == %f (expected: %f)\n", xx, bx::asin(xx), ::asinf(xx) );
REQUIRE(err.isOk() );
- REQUIRE(bx::equal(bx::asin(xx), ::asinf(xx), 0.0001f) );
+ REQUIRE(bx::isEqual(bx::asin(xx), ::asinf(xx), 0.0001f) );
}
for (float xx = -100.0f; xx < 100.0f; xx += 0.1f)
{
bx::write(writer, &err, "sin(%f) == %f (expected: %f)\n", xx, bx::sin(xx), ::sinf(xx) );
REQUIRE(err.isOk() );
- REQUIRE(bx::equal(bx::sin(xx), ::sinf(xx), 0.00001f) );
+ REQUIRE(bx::isEqual(bx::sin(xx), ::sinf(xx), 0.00001f) );
+ }
+
+ for (float xx = -bx::kPi2; xx < bx::kPi2; xx += 0.0001f)
+ {
+ bx::write(writer, &err, "sin(%f) == %f (expected: %f)\n", xx, bx::sin(xx), ::sinf(xx) );
+ REQUIRE(err.isOk() );
+ REQUIRE(bx::isEqual(bx::sin(xx), ::sinf(xx), 0.00001f) );
}
for (float xx = -1.0f; xx < 1.0f; xx += 0.1f)
{
bx::write(writer, &err, "sinh(%f) == %f (expected: %f)\n", xx, bx::sinh(xx), ::sinhf(xx) );
REQUIRE(err.isOk() );
- REQUIRE(bx::equal(bx::sinh(xx), ::sinhf(xx), 0.00001f) );
+ REQUIRE(bx::isEqual(bx::sinh(xx), ::sinhf(xx), 0.00001f) );
}
for (float xx = -1.0f; xx < 1.0f; xx += 0.001f)
{
bx::write(writer, &err, "acos(%f) == %f (expected: %f\n)", xx, bx::acos(xx), ::acosf(xx) );
REQUIRE(err.isOk() );
- REQUIRE(bx::equal(bx::acos(xx), ::acosf(xx), 0.0001f) );
+ REQUIRE(bx::isEqual(bx::acos(xx), ::acosf(xx), 0.0001f) );
}
for (float xx = -100.0f; xx < 100.0f; xx += 0.1f)
{
bx::write(writer, &err, "cos(%f) == %f (expected: %f)\n", xx, bx::cos(xx), ::cosf(xx) );
REQUIRE(err.isOk() );
- REQUIRE(bx::equal(bx::cos(xx), ::cosf(xx), 0.00001f) );
+ REQUIRE(bx::isEqual(bx::cos(xx), ::cosf(xx), 0.00001f) );
+ }
+
+ for (float xx = -bx::kPi2; xx < bx::kPi2; xx += 0.0001f)
+ {
+ bx::write(writer, &err, "cos(%f) == %f (expected: %f)\n", xx, bx::cos(xx), ::cosf(xx) );
+ REQUIRE(err.isOk() );
+ REQUIRE(bx::isEqual(bx::cos(xx), ::cosf(xx), 0.00001f) );
}
for (float xx = -100.0f; xx < 100.0f; xx += 0.1f)
{
bx::write(writer, &err, "tan(%f) == %f (expected: %f)\n", xx, bx::tan(xx), ::tanf(xx) );
REQUIRE(err.isOk() );
- REQUIRE(bx::equal(bx::tan(xx), ::tanf(xx), 0.001f) );
+ REQUIRE(bx::isEqual(bx::tan(xx), ::tanf(xx), 0.001f) );
}
for (float xx = -1.0f; xx < 1.0f; xx += 0.1f)
{
bx::write(writer, &err, "tanh(%f) == %f (expected: %f\n", xx, bx::tanh(xx), ::tanhf(xx) );
REQUIRE(err.isOk() );
- REQUIRE(bx::equal(bx::tanh(xx), ::tanhf(xx), 0.00001f) );
+ REQUIRE(bx::isEqual(bx::tanh(xx), ::tanhf(xx), 0.00001f) );
}
for (float xx = -100.0f; xx < 100.0f; xx += 0.1f)
{
bx::write(writer, &err, "atan(%f) == %f (expected: %f)\n", xx, bx::atan(xx), ::atanf(xx) );
REQUIRE(err.isOk() );
- REQUIRE(bx::equal(bx::atan(xx), ::atanf(xx), 0.00001f) );
+ REQUIRE(bx::isEqual(bx::atan(xx), ::atanf(xx), 0.00001f) );
}
+}
+
+TEST_CASE("atan2", "")
+{
+ bx::WriterI* writer = bx::getNullOut();
+ bx::Error err;
+
+ REQUIRE(bx::isEqual(bx::atan2(0.0f, 0.0f), ::atan2f(0.0f, 0.0f), 0.00001f) );
+ REQUIRE(bx::isEqual(bx::atan2(0.0f, 1.0f), ::atan2f(0.0f, 1.0f), 0.00001f) );
+ REQUIRE(bx::isEqual(bx::atan2(0.0f, -1.0f), ::atan2f(0.0f, -1.0f), 0.00001f) );
for (float yy = -100.0f; yy < 100.0f; yy += 0.1f)
{
@@ -156,11 +214,16 @@ TEST_CASE("libm", "")
{
bx::write(writer, &err, "atan2(%f, %f) == %f (expected: %f)\n", yy, xx, bx::atan2(yy, xx), ::atan2f(yy, xx) );
REQUIRE(err.isOk() );
- REQUIRE(bx::equal(bx::atan2(yy, xx), ::atan2f(yy, xx), 0.00001f) );
+ REQUIRE(bx::isEqual(bx::atan2(yy, xx), ::atan2f(yy, xx), 0.00001f) );
}
}
+}
- REQUIRE(bx::equal(bx::atan2(0.0f, 0.0f), ::atan2f(0.0f, 0.0f), 0.00001f) );
+TEST_CASE("sign", "")
+{
+ REQUIRE(-1 == bx::sign(-0.1389f) );
+ REQUIRE( 0 == bx::sign( 0.0000f) );
+ REQUIRE( 1 == bx::sign( 0.1389f) );
}
TEST_CASE("ToBits", "")
@@ -169,9 +232,16 @@ TEST_CASE("ToBits", "")
REQUIRE(UINT64_C(0x123456789abcdef0) == bx::doubleToBits(bx::bitsToDouble(UINT32_C(0x123456789abcdef0) ) ) );
}
+TEST_CASE("lerp", "")
+{
+ REQUIRE(1389.0f == bx::lerp(1389.0f, 1453.0f, 0.0f) );
+ REQUIRE(1453.0f == bx::lerp(1389.0f, 1453.0f, 1.0f) );
+ REQUIRE(0.5f == bx::lerp(0.0f, 1.0f, 0.5f) );
+}
+
void mtxCheck(const float* _a, const float* _b)
{
- if (!bx::equal(_a, _b, 16, 0.01f) )
+ if (!bx::isEqual(_a, _b, 16, 0.01f) )
{
DBG("\n"
"A:\n"
@@ -194,7 +264,7 @@ void mtxCheck(const float* _a, const float* _b)
, _b[12], _b[13], _b[14], _b[15]
);
- CHECK(false);
+ REQUIRE(false);
}
}
@@ -203,8 +273,14 @@ TEST_CASE("quaternion", "")
float mtxQ[16];
float mtx[16];
- float quat[4] = { 0.0f, 0.0f, 0.0f, 1.0f };
- bx::mtxQuat(mtxQ, quat);
+ bx::Quaternion quat = bx::init::Identity;
+ bx::Quaternion q2 = bx::init::None;
+
+ bx::Vec3 axis = bx::init::None;
+ bx::Vec3 euler = bx::init::None;
+ float angle;
+
+ bx::mtxFromQuaternion(mtxQ, quat);
bx::mtxIdentity(mtx);
mtxCheck(mtxQ, mtx);
@@ -212,28 +288,87 @@ TEST_CASE("quaternion", "")
float ay = bx::kPi/13.0f;
float az = bx::kPi/7.0f;
- bx::quatRotateX(quat, ax);
- bx::mtxQuat(mtxQ, quat);
- bx::mtxRotateX(mtx, ax);
- mtxCheck(mtxQ, mtx);
+ { // x
+ quat = bx::rotateX(ax);
+ bx::mtxFromQuaternion(mtxQ, quat);
+ bx::mtxRotateX(mtx, ax);
+ mtxCheck(mtxQ, mtx);
- float euler[3];
- bx::quatToEuler(euler, quat);
- CHECK(bx::equal(euler[0], ax, 0.001f) );
+ bx::toAxisAngle(axis, angle, quat);
+ REQUIRE(bx::isEqual(axis, bx::Vec3{1.0f, 0.0f, 0.0f}, 0.01f) );
+ REQUIRE(bx::isEqual(angle, ax, 0.01f) );
- bx::quatRotateY(quat, ay);
- bx::mtxQuat(mtxQ, quat);
- bx::mtxRotateY(mtx, ay);
- mtxCheck(mtxQ, mtx);
+ euler = bx::toEuler(quat);
+ REQUIRE(bx::isEqual(euler.x, ax, 0.001f) );
+ q2 = bx::fromEuler(euler);
+ REQUIRE(bx::isEqual(quat, q2, 0.001f) );
+ }
- bx::quatToEuler(euler, quat);
- CHECK(bx::equal(euler[1], ay, 0.001f) );
+ { // y
+ quat = bx::rotateY(ay);
+ bx::mtxFromQuaternion(mtxQ, quat);
+ bx::mtxRotateY(mtx, ay);
+ mtxCheck(mtxQ, mtx);
- bx::quatRotateZ(quat, az);
- bx::mtxQuat(mtxQ, quat);
- bx::mtxRotateZ(mtx, az);
- mtxCheck(mtxQ, mtx);
+ bx::toAxisAngle(axis, angle, quat);
+ REQUIRE(bx::isEqual(axis, bx::Vec3{0.0f, 1.0f, 0.0f}, 0.01f) );
+ REQUIRE(bx::isEqual(angle, ay, 0.01f) );
+ euler = bx::toEuler(quat);
+ REQUIRE(bx::isEqual(euler.y, ay, 0.001f) );
+ q2 = bx::fromEuler(euler);
+ REQUIRE(bx::isEqual(quat, q2, 0.001f) );
+
+ }
+
+ { // z
+ quat = bx::rotateZ(az);
+ bx::mtxFromQuaternion(mtxQ, quat);
+ bx::mtxRotateZ(mtx, az);
+ mtxCheck(mtxQ, mtx);
+
+ bx::toAxisAngle(axis, angle, quat);
+ REQUIRE(bx::isEqual(axis, bx::Vec3{0.0f, 0.0f, 1.0f}, 0.01f) );
+ REQUIRE(bx::isEqual(angle, az, 0.01f) );
+
+ euler = bx::toEuler(quat);
+ REQUIRE(bx::isEqual(euler.z, az, 0.001f) );
+ q2 = bx::fromEuler(euler);
+ REQUIRE(bx::isEqual(quat, q2, 0.001f) );
+ }
+}
+
+TEST_CASE("limits", "")
+{
+ STATIC_REQUIRE(bx::LimitsT<int8_t>::min == INT8_MIN);
+ STATIC_REQUIRE(bx::LimitsT<int8_t>::max == INT8_MAX);
+
+ STATIC_REQUIRE(bx::LimitsT<signed char>::min == CHAR_MIN);
+ STATIC_REQUIRE(bx::LimitsT<signed char>::max == CHAR_MAX);
+
+ STATIC_REQUIRE(bx::LimitsT<unsigned char>::min == 0);
+ STATIC_REQUIRE(bx::LimitsT<unsigned char>::max == UCHAR_MAX);
+
+ STATIC_REQUIRE(bx::LimitsT<int16_t>::min == INT16_MIN);
+ STATIC_REQUIRE(bx::LimitsT<int16_t>::max == INT16_MAX);
+
+ STATIC_REQUIRE(bx::LimitsT<uint16_t>::min == 0);
+ STATIC_REQUIRE(bx::LimitsT<uint16_t>::max == UINT16_MAX);
+
+ STATIC_REQUIRE(bx::LimitsT<int32_t>::min == INT32_MIN);
+ STATIC_REQUIRE(bx::LimitsT<int32_t>::max == INT32_MAX);
+
+ STATIC_REQUIRE(bx::LimitsT<uint32_t>::min == 0);
+ STATIC_REQUIRE(bx::LimitsT<uint32_t>::max == UINT32_MAX);
+
+ STATIC_REQUIRE(bx::LimitsT<int64_t>::min == INT64_MIN);
+ STATIC_REQUIRE(bx::LimitsT<int64_t>::max == INT64_MAX);
+
+ STATIC_REQUIRE(bx::LimitsT<uint64_t>::min == 0);
+ STATIC_REQUIRE(bx::LimitsT<uint64_t>::max == UINT64_MAX);
+
+ STATIC_REQUIRE(bx::LimitsT<float>::min == std::numeric_limits<float>::lowest() );
+ STATIC_REQUIRE(bx::LimitsT<float>::max == std::numeric_limits<float>::max() );
- bx::quatToEuler(euler, quat);
- CHECK(bx::equal(euler[2], az, 0.001f) );
+ STATIC_REQUIRE(bx::LimitsT<double>::min == std::numeric_limits<double>::lowest() );
+ STATIC_REQUIRE(bx::LimitsT<double>::max == std::numeric_limits<double>::max() );
}
diff --git a/3rdparty/bx/tests/nlalloc_test.cpp b/3rdparty/bx/tests/nlalloc_test.cpp
deleted file mode 100644
index 91b0354926f..00000000000
--- a/3rdparty/bx/tests/nlalloc_test.cpp
+++ /dev/null
@@ -1,195 +0,0 @@
-/*
- * Copyright 2010-2018 Branimir Karadzic. All rights reserved.
- * License: https://github.com/bkaradzic/bx#license-bsd-2-clause
- */
-
-#include "test.h"
-#include <bx/sort.h>
-#include <bx/allocator.h>
-
-bx::DefaultAllocator g_allocator0;
-
-struct TinyStlAllocator
-{
- static void* static_allocate(size_t _bytes)
- {
- return BX_ALLOC(&g_allocator0, _bytes);
- }
-
- static void static_deallocate(void* _ptr, size_t /*_bytes*/)
- {
- if (NULL != _ptr)
- {
- BX_FREE(&g_allocator0, _ptr);
- }
- }
-};
-
-#define TINYSTL_ALLOCATOR ::TinyStlAllocator
-#include <tinystl/vector.h>
-
-namespace stl = tinystl;
-
-namespace bx
-{
- struct Blk
- {
- static const uint64_t kInvalid = UINT64_MAX;
-
- Blk()
- : ptr(kInvalid)
- , size(0)
- {
- }
-
- Blk(uint64_t _ptr, uint32_t _size)
- : ptr(_ptr)
- , size(_size)
- {
- }
-
- uint64_t ptr;
- uint32_t size;
- };
-
- inline bool operator<(const Blk& _lhs, const Blk& _rhs)
- {
- return _lhs.ptr < _rhs.ptr;
- }
-
- inline bool isValid(const Blk& _blk)
- {
- return Blk::kInvalid != _blk.ptr;
- }
-
- // First-fit non-local allocator.
- class NonLocalAllocator
- {
- public:
- NonLocalAllocator()
- {
- reset();
- }
-
- ~NonLocalAllocator()
- {
- }
-
- void reset()
- {
- m_free.clear();
- m_used = 0;
- }
-
- void add(const Blk& _blk)
- {
- m_free.push_back(_blk);
- }
-
- Blk remove()
- {
- BX_CHECK(0 == m_used, "");
-
- if (0 < m_free.size() )
- {
- Blk freeBlock = m_free.back();
- m_free.pop_back();
- return freeBlock;
- }
-
- return Blk{};
- }
-
- Blk alloc(uint32_t _size)
- {
- _size = max(_size, 16u);
-
- for (FreeList::iterator it = m_free.begin(), itEnd = m_free.end(); it != itEnd; ++it)
- {
- if (it->size >= _size)
- {
- uint64_t ptr = it->ptr;
-
- if (it->size != _size)
- {
- it->size -= _size;
- it->ptr += _size;
- }
- else
- {
- m_free.erase(it);
- }
-
- m_used += _size;
- return Blk{ ptr, _size };
- }
- }
-
- // there is no block large enough.
- return Blk{};
- }
-
- void free(const Blk& _blk)
- {
- m_used -= _blk.size;
- m_free.push_back(_blk);
- compact();
- }
-
- bool compact()
- {
- bx::quickSort(
- m_free.begin()
- , uint32_t(m_free.end() - m_free.begin() )
- , sizeof(Blk)
- , [](const void* _a, const void* _b) -> int32_t {
- const Blk& lhs = *(const Blk*)(_a);
- const Blk& rhs = *(const Blk*)(_b);
- return lhs < rhs ? -1 : 1;
- });
-
- for (FreeList::iterator it = m_free.begin(), next = it, itEnd = m_free.end(); next != itEnd;)
- {
- if ( (it->ptr + it->size) == next->ptr)
- {
- it->size += next->size;
- next = m_free.erase(next);
- }
- else
- {
- it = next;
- ++next;
- }
- }
-
- return 0 == m_used;
- }
-
- uint32_t getUsed() const
- {
- return m_used;
- }
-
- private:
- typedef stl::vector<Blk> FreeList;
- FreeList m_free;
- uint32_t m_used;
- };
-} // namespace bx
-
-TEST_CASE("nlalloc")
-{
- bx::NonLocalAllocator nla;
-
- bx::Blk blk;
-
- blk = nla.alloc(100);
- REQUIRE(!isValid(blk) );
- nla.add(bx::Blk{0x1000, 100});
-
- blk = nla.alloc(100);
- REQUIRE(isValid(blk) );
-
- nla.free(blk);
- REQUIRE(0 == nla.getUsed() );
-}
diff --git a/3rdparty/bx/tests/os_test.cpp b/3rdparty/bx/tests/os_test.cpp
index bf51c725e05..6f1151558c3 100644
--- a/3rdparty/bx/tests/os_test.cpp
+++ b/3rdparty/bx/tests/os_test.cpp
@@ -1,6 +1,6 @@
/*
- * Copyright 2010-2018 Branimir Karadzic. All rights reserved.
- * License: https://github.com/bkaradzic/bx#license-bsd-2-clause
+ * Copyright 2010-2022 Branimir Karadzic. All rights reserved.
+ * License: https://github.com/bkaradzic/bx/blob/master/LICENSE
*/
#include "test.h"
@@ -14,15 +14,19 @@ TEST_CASE("getProcessMemoryUsed", "")
// DBG("bx::getProcessMemoryUsed %d", bx::getProcessMemoryUsed() );
}
+#if BX_CONFIG_SUPPORTS_THREADING
+
TEST_CASE("semaphore_timeout", "")
{
bx::Semaphore sem;
- int64_t start = bx::getHPCounter();
- bool ok = sem.wait(900);
- int64_t elapsed = bx::getHPCounter() - start;
+ int64_t start = bx::getHPCounter();
+ bool ok = sem.wait(900);
+ int64_t elapsed = bx::getHPCounter() - start;
int64_t frequency = bx::getHPFrequency();
- double ms = double(elapsed) / double(frequency) * 1000;
- printf("%f\n", ms);
+ double ms = double(elapsed) / double(frequency) * 1000;
+ bx::printf("%f\n", ms);
REQUIRE(!ok);
}
+
+#endif // BX_CONFIG_SUPPORTS_THREADING
diff --git a/3rdparty/bx/tests/queue_test.cpp b/3rdparty/bx/tests/queue_test.cpp
index 4a4d5c9a325..253b52667f0 100644
--- a/3rdparty/bx/tests/queue_test.cpp
+++ b/3rdparty/bx/tests/queue_test.cpp
@@ -1,6 +1,6 @@
/*
- * Copyright 2010-2018 Branimir Karadzic. All rights reserved.
- * License: https://github.com/bkaradzic/bx#license-bsd-2-clause
+ * Copyright 2010-2022 Branimir Karadzic. All rights reserved.
+ * License: https://github.com/bkaradzic/bx/blob/master/LICENSE
*/
#include "test.h"
diff --git a/3rdparty/bx/tests/readerwriter_test.cpp b/3rdparty/bx/tests/readerwriter_test.cpp
new file mode 100644
index 00000000000..96e77a0a098
--- /dev/null
+++ b/3rdparty/bx/tests/readerwriter_test.cpp
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2010-2022 Branimir Karadzic. All rights reserved.
+ * License: https://github.com/bkaradzic/bx/blob/master/LICENSE
+ */
+
+#include "test.h"
+#include <bx/readerwriter.h>
+
+TEST_CASE("writeLE", "")
+{
+ bx::SizerWriter writer;
+
+ bx::Error err;
+
+ int32_t total = bx::writeLE(&writer, 1.0f, &err);
+
+ REQUIRE(err.isOk() );
+ REQUIRE(total == 4);
+}
+
+TEST_CASE("writeBE", "")
+{
+ bx::SizerWriter writer;
+
+ bx::Error err;
+
+ int32_t total = bx::writeBE(&writer, 1.0f, &err);
+
+ REQUIRE(err.isOk() );
+ REQUIRE(total == 4);
+}
diff --git a/3rdparty/bx/tests/ringbuffer_test.cpp b/3rdparty/bx/tests/ringbuffer_test.cpp
index d0d2a426572..11629fc6c14 100644
--- a/3rdparty/bx/tests/ringbuffer_test.cpp
+++ b/3rdparty/bx/tests/ringbuffer_test.cpp
@@ -1,6 +1,6 @@
/*
- * Copyright 2010-2018 Branimir Karadzic. All rights reserved.
- * License: https://github.com/bkaradzic/bx#license-bsd-2-clause
+ * Copyright 2010-2022 Branimir Karadzic. All rights reserved.
+ * License: https://github.com/bkaradzic/bx/blob/master/LICENSE
*/
#include "test.h"
diff --git a/3rdparty/bx/tests/rng_test.cpp b/3rdparty/bx/tests/rng_test.cpp
index b5161f7167e..a06b7747f17 100644
--- a/3rdparty/bx/tests/rng_test.cpp
+++ b/3rdparty/bx/tests/rng_test.cpp
@@ -1,6 +1,6 @@
/*
- * Copyright 2010-2018 Branimir Karadzic. All rights reserved.
- * License: https://github.com/bkaradzic/bx#license-bsd-2-clause
+ * Copyright 2010-2022 Branimir Karadzic. All rights reserved.
+ * License: https://github.com/bkaradzic/bx/blob/master/LICENSE
*/
#include "test.h"
diff --git a/3rdparty/bx/tests/run_test.cpp b/3rdparty/bx/tests/run_test.cpp
index 090c1186c0c..b2b43d8fede 100644
--- a/3rdparty/bx/tests/run_test.cpp
+++ b/3rdparty/bx/tests/run_test.cpp
@@ -1,6 +1,6 @@
/*
- * Copyright 2010-2018 Branimir Karadzic. All rights reserved.
- * License: https://github.com/bkaradzic/bx#license-bsd-2-clause
+ * Copyright 2010-2022 Branimir Karadzic. All rights reserved.
+ * License: https://github.com/bkaradzic/bx/blob/master/LICENSE
*/
#define CATCH_CONFIG_RUNNER
@@ -15,6 +15,17 @@ int runAllTests(int _argc, const char* _argv[])
", CRT: " BX_CRT_NAME
", Date: " __DATE__
", Time: " __TIME__
+ ", C++: " BX_CPP_NAME
);
- return Catch::Session().run(_argc, _argv);
+
+ using namespace Catch;
+
+ Session session;
+
+ ConfigData config;
+ config.defaultColourMode = BX_PLATFORM_EMSCRIPTEN ? ColourMode::None : ColourMode::PlatformDefault;
+
+ session.useConfigData(config);
+
+ return session.run(_argc, _argv);
}
diff --git a/3rdparty/bx/tests/settings_test.cpp b/3rdparty/bx/tests/settings_test.cpp
index 584397ad143..46fa3ad6c9a 100644
--- a/3rdparty/bx/tests/settings_test.cpp
+++ b/3rdparty/bx/tests/settings_test.cpp
@@ -1,6 +1,6 @@
/*
- * Copyright 2010-2018 Branimir Karadzic. All rights reserved.
- * License: https://github.com/bkaradzic/bx#license-bsd-2-clause
+ * Copyright 2010-2022 Branimir Karadzic. All rights reserved.
+ * License: https://github.com/bkaradzic/bx/blob/master/LICENSE
*/
#include "test.h"
@@ -21,9 +21,9 @@ TEST_CASE("Settings", "")
settings.set("test/foo/bar/abvgd", "1389");
bx::FileWriter writer;
- if (bx::open(&writer, filePath) )
+ if (bx::open(&writer, filePath, false, bx::ErrorIgnore{}) )
{
- bx::write(&writer, settings);
+ bx::write(&writer, settings, bx::ErrorIgnore{});
bx::close(&writer);
}
@@ -37,9 +37,9 @@ TEST_CASE("Settings", "")
settings.clear();
bx::FileReader reader;
- if (bx::open(&reader, filePath) )
+ if (bx::open(&reader, filePath, bx::ErrorIgnore{}) )
{
- bx::read(&reader, settings);
+ bx::read(&reader, settings, bx::ErrorIgnore{});
bx::close(&reader);
}
diff --git a/3rdparty/bx/tests/simd_bench.cpp b/3rdparty/bx/tests/simd_bench.cpp
index 66e26297aaf..668a8df6120 100644
--- a/3rdparty/bx/tests/simd_bench.cpp
+++ b/3rdparty/bx/tests/simd_bench.cpp
@@ -1,6 +1,6 @@
/*
- * Copyright 2010-2018 Branimir Karadzic. All rights reserved.
- * License: https://github.com/bkaradzic/bx#license-bsd-2-clause
+ * Copyright 2010-2022 Branimir Karadzic. All rights reserved.
+ * License: https://github.com/bkaradzic/bx/blob/master/LICENSE
*/
#include <bx/allocator.h>
diff --git a/3rdparty/bx/tests/simd_test.cpp b/3rdparty/bx/tests/simd_test.cpp
index 3a211ca1054..65cbfb7bd3c 100644
--- a/3rdparty/bx/tests/simd_test.cpp
+++ b/3rdparty/bx/tests/simd_test.cpp
@@ -1,6 +1,6 @@
/*
- * Copyright 2010-2018 Branimir Karadzic. All rights reserved.
- * License: https://github.com/bkaradzic/bx#license-bsd-2-clause
+ * Copyright 2010-2022 Branimir Karadzic. All rights reserved.
+ * License: https://github.com/bkaradzic/bx/blob/master/LICENSE
*/
#include "test.h"
@@ -162,10 +162,10 @@ void simd_check_float(
, _0, _1, _2, _3
);
- CHECK(bx::equal(c.f[0], _0, 0.0001f) );
- CHECK(bx::equal(c.f[1], _1, 0.0001f) );
- CHECK(bx::equal(c.f[2], _2, 0.0001f) );
- CHECK(bx::equal(c.f[3], _3, 0.0001f) );
+ CHECK(bx::isEqual(c.f[0], _0, 0.0001f) );
+ CHECK(bx::isEqual(c.f[1], _1, 0.0001f) );
+ CHECK(bx::isEqual(c.f[2], _2, 0.0001f) );
+ CHECK(bx::isEqual(c.f[3], _3, 0.0001f) );
}
void simd_check_float(
@@ -189,14 +189,14 @@ void simd_check_float(
, _0, _1, _2, _3, _4, _5, _6, _7
);
- CHECK(bx::equal(c.f[0], _0, 0.0001f) );
- CHECK(bx::equal(c.f[1], _1, 0.0001f) );
- CHECK(bx::equal(c.f[2], _2, 0.0001f) );
- CHECK(bx::equal(c.f[3], _3, 0.0001f) );
- CHECK(bx::equal(c.f[4], _4, 0.0001f) );
- CHECK(bx::equal(c.f[5], _5, 0.0001f) );
- CHECK(bx::equal(c.f[6], _6, 0.0001f) );
- CHECK(bx::equal(c.f[7], _7, 0.0001f) );
+ CHECK(bx::isEqual(c.f[0], _0, 0.0001f) );
+ CHECK(bx::isEqual(c.f[1], _1, 0.0001f) );
+ CHECK(bx::isEqual(c.f[2], _2, 0.0001f) );
+ CHECK(bx::isEqual(c.f[3], _3, 0.0001f) );
+ CHECK(bx::isEqual(c.f[4], _4, 0.0001f) );
+ CHECK(bx::isEqual(c.f[5], _5, 0.0001f) );
+ CHECK(bx::isEqual(c.f[6], _6, 0.0001f) );
+ CHECK(bx::isEqual(c.f[7], _7, 0.0001f) );
}
void simd_check_string(const char* _str, bx::simd128_t _a)
diff --git a/3rdparty/bx/tests/sort_test.cpp b/3rdparty/bx/tests/sort_test.cpp
index e2a5a25449d..4abb76db334 100644
--- a/3rdparty/bx/tests/sort_test.cpp
+++ b/3rdparty/bx/tests/sort_test.cpp
@@ -1,14 +1,15 @@
/*
- * Copyright 2010-2018 Branimir Karadzic. All rights reserved.
- * License: https://github.com/bkaradzic/bx#license-bsd-2-clause
+ * Copyright 2010-2022 Branimir Karadzic. All rights reserved.
+ * License: https://github.com/bkaradzic/bx/blob/master/LICENSE
*/
#include "test.h"
+#include <bx/bx.h>
#include <bx/sort.h>
#include <bx/string.h>
#include <bx/rng.h>
-TEST_CASE("quickSort", "")
+TEST_CASE("sort-quickSort", "")
{
const char* str[] =
{
@@ -18,19 +19,43 @@ TEST_CASE("quickSort", "")
"jagoda",
};
- bx::quickSort(str, BX_COUNTOF(str), sizeof(void*)
- , [](const void* _lhs, const void* _rhs)
- {
- const char* lhs = *(const char**)_lhs;
- const char* rhs = *(const char**)_rhs;
- return bx::strCmp(lhs, rhs);
- });
+ REQUIRE(!bx::isSorted(str, BX_COUNTOF(str) ) );
+
+ bx::quickSort(str, BX_COUNTOF(str) );
REQUIRE(0 == bx::strCmp(str[0], "jabuka") );
REQUIRE(0 == bx::strCmp(str[1], "jagoda") );
REQUIRE(0 == bx::strCmp(str[2], "kruska") );
REQUIRE(0 == bx::strCmp(str[3], "malina") );
+ REQUIRE(bx::isSorted(str, BX_COUNTOF(str) ) );
+
+ auto bsearchStrCmpFn = [](const void* _lhs, const void* _rhs)
+ {
+ const char* lhs = (const char*)_lhs;
+ const char* rhs = *(const char**)_rhs;
+ return bx::strCmp(lhs, rhs);
+ };
+
+ REQUIRE(~4 == bx::binarySearch("sljiva", str, BX_COUNTOF(str), sizeof(str[0]), bsearchStrCmpFn) );
+ REQUIRE( 0 == bx::binarySearch("jabuka", str, BX_COUNTOF(str), sizeof(str[0]), bsearchStrCmpFn) );
+ REQUIRE( 1 == bx::binarySearch("jagoda", str, BX_COUNTOF(str), sizeof(str[0]), bsearchStrCmpFn) );
+ REQUIRE( 2 == bx::binarySearch("kruska", str, BX_COUNTOF(str), sizeof(str[0]), bsearchStrCmpFn) );
+ REQUIRE( 3 == bx::binarySearch("malina", str, BX_COUNTOF(str), sizeof(str[0]), bsearchStrCmpFn) );
+ REQUIRE(~3 == bx::binarySearch("kupina", str, BX_COUNTOF(str), sizeof(str[0]), bsearchStrCmpFn) );
+
+ REQUIRE( 0 == bx::lowerBound("jabuka", str, BX_COUNTOF(str), sizeof(str[0]), bsearchStrCmpFn) );
+ REQUIRE( 1 == bx::upperBound("jabuka", str, BX_COUNTOF(str), sizeof(str[0]), bsearchStrCmpFn) );
+
+ REQUIRE( 1 == bx::lowerBound("jagoda", str, BX_COUNTOF(str), sizeof(str[0]), bsearchStrCmpFn) );
+ REQUIRE( 2 == bx::upperBound("jagoda", str, BX_COUNTOF(str), sizeof(str[0]), bsearchStrCmpFn) );
+
+ REQUIRE( 2 == bx::lowerBound("kruska", str, BX_COUNTOF(str), sizeof(str[0]), bsearchStrCmpFn) );
+ REQUIRE( 3 == bx::upperBound("kruska", str, BX_COUNTOF(str), sizeof(str[0]), bsearchStrCmpFn) );
+
+ REQUIRE( 3 == bx::lowerBound("malina", str, BX_COUNTOF(str), sizeof(str[0]), bsearchStrCmpFn) );
+ REQUIRE( 4 == bx::upperBound("malina", str, BX_COUNTOF(str), sizeof(str[0]), bsearchStrCmpFn) );
+
int8_t byte[128];
bx::RngMwc rng;
for (uint32_t ii = 0; ii < BX_COUNTOF(byte); ++ii)
@@ -38,16 +63,105 @@ TEST_CASE("quickSort", "")
byte[ii] = rng.gen()&0xff;
}
- bx::quickSort(byte, BX_COUNTOF(byte), 1
- , [](const void* _lhs, const void* _rhs)
- {
- int8_t lhs = *(const int8_t*)_lhs;
- int8_t rhs = *(const int8_t*)_rhs;
- return lhs - rhs;
- });
+ REQUIRE(!bx::isSorted(byte, BX_COUNTOF(byte) ) );
+
+ bx::quickSort(byte, BX_COUNTOF(byte) );
for (uint32_t ii = 1; ii < BX_COUNTOF(byte); ++ii)
{
REQUIRE(byte[ii-1] <= byte[ii]);
}
+
+ REQUIRE(bx::isSorted(byte, BX_COUNTOF(byte) ) );
+}
+
+TEST_CASE("sort-unique", "")
+{
+ // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 | 14
+ int32_t test[] = { 100, 101, 101, 101, 103, 104, 105, 105, 105, 106, 106, 107, 108, 109 };
+ REQUIRE(bx::isSorted(test, BX_COUNTOF(test) ) );
+
+ REQUIRE(0 == bx::unique(test, 0) );
+ REQUIRE(1 == bx::unique(test, 1) );
+
+ REQUIRE(2 == bx::unique(test, 4) );
+ bx::quickSort(test, BX_COUNTOF(test) );
+
+ REQUIRE(3 == bx::unique(test, 5) );
+ bx::quickSort(test, BX_COUNTOF(test) );
+
+ uint32_t last = bx::unique(test, BX_COUNTOF(test) );
+ REQUIRE(9 == last);
+
+ REQUIRE(9 == bx::unique(test, last) );
+}
+
+TEST_CASE("sort-lower/upperBound int32_t", "")
+{
+ // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 | 14
+ const int32_t test[] = { 100, 101, 101, 101, 103, 104, 105, 105, 105, 106, 106, 107, 108, 109 };
+ REQUIRE(bx::isSorted(test, BX_COUNTOF(test) ) );
+
+ const uint32_t resultLowerBound[] = { 0, 1, 4, 4, 5, 6, 9, 11, 12, 13 };
+ const uint32_t resultUpperBound[] = { 1, 4, 4, 5, 6, 9, 11, 12, 13, 14 };
+
+ STATIC_REQUIRE(10 == BX_COUNTOF(resultLowerBound) );
+ STATIC_REQUIRE(10 == BX_COUNTOF(resultUpperBound) );
+
+ for (int32_t key = test[0], keyMax = test[BX_COUNTOF(test)-1], ii = 0; key <= keyMax; ++key, ++ii)
+ {
+ REQUIRE(resultLowerBound[ii] == bx::lowerBound(key, test, BX_COUNTOF(test) ) );
+ REQUIRE(resultUpperBound[ii] == bx::upperBound(key, test, BX_COUNTOF(test) ) );
+ }
+}
+
+template<typename Ty>
+int32_t compareAscendingTest(const Ty& _lhs, const Ty& _rhs)
+{
+ return bx::compareAscending<Ty>(&_lhs, &_rhs);
+}
+
+template<typename Ty>
+int32_t compareDescendingTest(const Ty& _lhs, const Ty& _rhs)
+{
+ return bx::compareDescending<Ty>(&_lhs, &_rhs);
+}
+
+template<typename Ty>
+void compareTest(const Ty& _min, const Ty& _max)
+{
+ REQUIRE(_min < _max);
+
+ REQUIRE(-1 == compareAscendingTest<Ty>(bx::min<Ty>(), bx::max<Ty>() ) );
+ REQUIRE(-1 == compareAscendingTest<Ty>(Ty(0), bx::max<Ty>() ) );
+ REQUIRE( 0 == compareAscendingTest<Ty>(bx::min<Ty>(), bx::min<Ty>() ) );
+ REQUIRE( 0 == compareAscendingTest<Ty>(bx::max<Ty>(), bx::max<Ty>() ) );
+ REQUIRE( 1 == compareAscendingTest<Ty>(bx::max<Ty>(), Ty(0) ) );
+ REQUIRE( 1 == compareAscendingTest<Ty>(bx::max<Ty>(), bx::min<Ty>() ) );
+
+ REQUIRE(-1 == compareAscendingTest<Ty>(_min, _max) );
+ REQUIRE( 0 == compareAscendingTest<Ty>(_min, _min) );
+ REQUIRE( 0 == compareAscendingTest<Ty>(_max, _max) );
+ REQUIRE( 1 == compareAscendingTest<Ty>(_max, _min) );
+
+ REQUIRE( 1 == compareDescendingTest<Ty>(_min, _max) );
+ REQUIRE( 0 == compareDescendingTest<Ty>(_min, _min) );
+ REQUIRE( 0 == compareDescendingTest<Ty>(_max, _max) );
+ REQUIRE(-1 == compareDescendingTest<Ty>(_max, _min) );
+}
+
+TEST_CASE("sort-ComparisonFn", "")
+{
+ compareTest< int8_t>( -13, 89);
+ compareTest<int16_t>(-1389, 1389);
+ compareTest<int32_t>(-1389, 1389);
+ compareTest<int64_t>(-1389, 1389);
+
+ compareTest< uint8_t>( 13, 89);
+ compareTest<uint16_t>( 13, 1389);
+ compareTest<uint32_t>( 13, 1389);
+ compareTest<uint64_t>( 13, 1389);
+
+ compareTest< float>(-13.89f, 1389.0f);
+ compareTest<double>(-13.89f, 1389.0f);
}
diff --git a/3rdparty/bx/tests/string_test.cpp b/3rdparty/bx/tests/string_test.cpp
index b7c4ed8ab52..cbcb50e8b5a 100644
--- a/3rdparty/bx/tests/string_test.cpp
+++ b/3rdparty/bx/tests/string_test.cpp
@@ -1,6 +1,6 @@
/*
- * Copyright 2010-2018 Branimir Karadzic. All rights reserved.
- * License: https://github.com/bkaradzic/bx#license-bsd-2-clause
+ * Copyright 2010-2022 Branimir Karadzic. All rights reserved.
+ * License: https://github.com/bkaradzic/bx/blob/master/LICENSE
*/
#include "test.h"
@@ -16,7 +16,7 @@ TEST_CASE("stringPrintfTy", "")
{
std::string test;
bx::stringPrintf(test, "printf into std::string.");
- REQUIRE(0 == bx::strCmp(bx::StringView(test), "printf into std::string.") );
+ REQUIRE(0 == bx::strCmp(bx::StringView(test.data(), int32_t(test.length() ) ), "printf into std::string.") );
}
TEST_CASE("prettify", "")
@@ -91,6 +91,10 @@ TEST_CASE("strCat", "")
TEST_CASE("strCmp", "")
{
+ REQUIRE(0 < bx::strCmp("abvgd", "abv") );
+ REQUIRE(0 < bx::strCmp("abvgd", "") );
+ REQUIRE(0 > bx::strCmp("", "abvgd") );
+ REQUIRE(0 != bx::strCmp(".tar.gz", ".") );
REQUIRE(0 != bx::strCmp("meh", "meh/") );
}
@@ -184,6 +188,7 @@ TEST_CASE("strRFind", "")
REQUIRE(bx::strRFind(bx::StringView(test, 0), 's').isEmpty() );
REQUIRE(bx::strRFind(bx::StringView(test, 1), 's').isEmpty() );
REQUIRE(&test[2] == bx::strRFind(test, 's').getPtr() );
+ REQUIRE(&test[3] == bx::strRFind(test, 't').getPtr() );
}
TEST_CASE("strFindI", "")
@@ -221,6 +226,18 @@ TEST_CASE("strFind", "")
REQUIRE(bx::strFind("vgd", 'a').isEmpty() );
}
+
+ {
+ bx::StringView test = bx::strFind("a", "a");
+ REQUIRE(test.getLength() == 1);
+ REQUIRE(*test.getPtr() == 'a');
+ }
+
+ {
+ bx::StringView test = bx::strFind("a", bx::StringView("a ", 1) );
+ REQUIRE(test.getLength() == 1);
+ REQUIRE(*test.getPtr() == 'a');
+ }
}
TEST_CASE("strSkip", "")
@@ -316,6 +333,7 @@ TEST_CASE("toString double", "")
REQUIRE(testToString(-270.000000, "-270.0") );
REQUIRE(testToString(2.225073858507201e-308, "2.225073858507201e-308") );
REQUIRE(testToString(-79.39773355813419, "-79.39773355813419") );
+ REQUIRE(testToString(-1.234567e-9, "-1.234567e-9") );
}
template<typename Ty>
@@ -457,12 +475,26 @@ TEST_CASE("StringView", "")
TEST_CASE("Trim", "")
{
+ REQUIRE(bx::strLTrim("a", "a").isEmpty() );
+ REQUIRE(0 == bx::strCmp(bx::strLTrim("aba", "a"), "ba") );
+
+ REQUIRE(bx::strRTrim("a", "a").isEmpty() );
+ REQUIRE(0 == bx::strCmp(bx::strRTrim("aba", "a"), "ab") );
+
+ REQUIRE(bx::strTrim("a", "a").isEmpty() );
+ REQUIRE(0 == bx::strCmp(bx::strTrim("aba", "a"), "b") );
+
REQUIRE(0 == bx::strCmp(bx::strLTrim("abvgd", "ab"), "vgd") );
- REQUIRE(0 == bx::strCmp(bx::strLTrim("abvgd", "vagbd"), "abvgd") );
+
+ REQUIRE(0 == bx::strCmp(bx::strLTrim("abvgd", "vagbd"), "") );
+ REQUIRE(0 == bx::strCmp(bx::strTrimPrefix("abvgd", "vagbd"), "abvgd") );
+
REQUIRE(0 == bx::strCmp(bx::strLTrim("abvgd", "vgd"), "abvgd") );
REQUIRE(0 == bx::strCmp(bx::strLTrim("/555333/podmac/", "/"), "555333/podmac/") );
- REQUIRE(0 == bx::strCmp(bx::strRTrim("abvgd", "vagbd"), "abvgd") );
+ REQUIRE(0 == bx::strCmp(bx::strRTrim("abvgd", "vagbd"), "") );
+ REQUIRE(0 == bx::strCmp(bx::strTrimSuffix("abvgd", "vagbd"), "abvgd") );
+
REQUIRE(0 == bx::strCmp(bx::strRTrim("abvgd", "abv"), "abvgd") );
REQUIRE(0 == bx::strCmp(bx::strRTrim("/555333/podmac/", "/"), "/555333/podmac") );
@@ -477,6 +509,37 @@ TEST_CASE("Trim", "")
REQUIRE(0 == bx::strCmp(bx::strTrim(uri.getPath(), "/"), "555333/podmac") );
}
+TEST_CASE("TrimSpace", "")
+{
+ REQUIRE(bx::strLTrimSpace("").isEmpty() );
+ REQUIRE(bx::strRTrimSpace("").isEmpty() );
+ REQUIRE(bx::strTrimSpace( "").isEmpty() );
+
+ REQUIRE(bx::strLTrimSpace("\n").isEmpty() );
+ REQUIRE(bx::strRTrimSpace("\n").isEmpty() );
+ REQUIRE(bx::strTrimSpace( "\n").isEmpty() );
+
+ const bx::StringView t0("1389");
+ const bx::StringView t1(" 1389");
+ const bx::StringView t2("1389 ");
+ const bx::StringView t3(" 1389 ");
+
+ REQUIRE(0 == bx::strCmp(bx::strLTrimSpace(t0), t0) );
+ REQUIRE(0 == bx::strCmp(bx::strLTrimSpace(t1), t0) );
+ REQUIRE(0 == bx::strCmp(bx::strLTrimSpace(t2), t2) );
+ REQUIRE(0 == bx::strCmp(bx::strLTrimSpace(t3), "1389 ") );
+
+ REQUIRE(0 == bx::strCmp(bx::strRTrimSpace(t0), t0) );
+ REQUIRE(0 == bx::strCmp(bx::strRTrimSpace(t1), t1) );
+ REQUIRE(0 == bx::strCmp(bx::strRTrimSpace(t2), t0) );
+ REQUIRE(0 == bx::strCmp(bx::strRTrimSpace(t3), " 1389") );
+
+ REQUIRE(0 == bx::strCmp(bx::strTrimSpace(t0), t0) );
+ REQUIRE(0 == bx::strCmp(bx::strTrimSpace(t1), t0) );
+ REQUIRE(0 == bx::strCmp(bx::strTrimSpace(t2), t0) );
+ REQUIRE(0 == bx::strCmp(bx::strTrimSpace(t3), t0) );
+}
+
TEST_CASE("strWord", "")
{
REQUIRE(bx::strWord(" abvgd-1389.0").isEmpty() );
@@ -491,3 +554,49 @@ TEST_CASE("strFindBlock", "")
bx::StringView result = bx::strFindBlock(test1, '{', '}');
REQUIRE(19 == result.getLength() );
}
+
+TEST_CASE("prefix", "")
+{
+ REQUIRE( bx::hasPrefix("abvgd-1389.0", "abv") );
+ REQUIRE(!bx::hasPrefix("abvgd-1389.0", "bvg") );
+ REQUIRE( bx::hasPrefix("abvgd-1389.0", "") );
+
+ REQUIRE(0 == bx::strCmp(bx::strTrimPrefix("abvgd-1389.0", "abv"), "gd-1389.0") );
+ REQUIRE(0 == bx::strCmp(bx::strTrimPrefix("abvgd-1389.0", "xyz"), "abvgd-1389.0") );
+}
+
+TEST_CASE("suffix", "")
+{
+ REQUIRE( bx::hasSuffix("abvgd-1389.0", "389.0") );
+ REQUIRE(!bx::hasSuffix("abvgd-1389.0", "1389") );
+ REQUIRE( bx::hasSuffix("abvgd-1389.0", "") );
+
+ REQUIRE(0 == bx::strCmp(bx::strTrimSuffix("abvgd-1389.0", "389.0"), "abvgd-1") );
+ REQUIRE(0 == bx::strCmp(bx::strTrimSuffix("abvgd-1389.0", "xyz"), "abvgd-1389.0") );
+}
+
+TEST_CASE("0terminated", "")
+{
+ const bx::StringView t0("1389");
+ REQUIRE(t0.is0Terminated() );
+ const bx::StringView t1(strTrimPrefix(t0, "13") );
+ REQUIRE(!t1.is0Terminated() );
+ const bx::StringView t2(strTrimSuffix(t0, "89") );
+ REQUIRE(!t2.is0Terminated() );
+
+ bx::DefaultAllocator crt;
+ g_allocator = &crt;
+
+ typedef bx::StringT<&g_allocator> String;
+
+ String st;
+ REQUIRE(st.is0Terminated() );
+
+ st = strTrimPrefix(t0, "13");
+ REQUIRE(2 == st.getLength() );
+ REQUIRE(st.is0Terminated() );
+
+ st = strTrimSuffix(t0, "89");
+ REQUIRE(2 == st.getLength() );
+ REQUIRE(st.is0Terminated() );
+}
diff --git a/3rdparty/bx/tests/test.h b/3rdparty/bx/tests/test.h
index 43da95a56d2..7157174de59 100644
--- a/3rdparty/bx/tests/test.h
+++ b/3rdparty/bx/tests/test.h
@@ -1,16 +1,16 @@
/*
- * Copyright 2010-2018 Branimir Karadzic. All rights reserved.
- * License: https://github.com/bkaradzic/bx#license-bsd-2-clause
+ * Copyright 2010-2022 Branimir Karadzic. All rights reserved.
+ * License: https://github.com/bkaradzic/bx/blob/master/LICENSE
*/
-#ifndef __TEST_H__
-#define __TEST_H__
+#ifndef BX_TEST_H_HEADER_GUARD
+#define BX_TEST_H_HEADER_GUARD
#include <bx/bx.h>
BX_PRAGMA_DIAGNOSTIC_PUSH();
BX_PRAGMA_DIAGNOSTIC_IGNORED_MSVC(4312); // warning C4312 : 'reinterpret_cast' : conversion from 'int' to 'const char *' of greater size
-#include <catch/catch.hpp>
+#include <catch/catch_amalgamated.hpp>
BX_PRAGMA_DIAGNOSTIC_POP();
#define TEST(_x) TEST_CASE(#_x, "")
@@ -18,4 +18,4 @@ BX_PRAGMA_DIAGNOSTIC_POP();
#include "dbg.h"
-#endif // __TEST_H__
+#endif // BX_TEST_H_HEADER_GUARD
diff --git a/3rdparty/bx/tests/thread_test.cpp b/3rdparty/bx/tests/thread_test.cpp
index 80db9b5b969..b517eac069f 100644
--- a/3rdparty/bx/tests/thread_test.cpp
+++ b/3rdparty/bx/tests/thread_test.cpp
@@ -1,11 +1,13 @@
/*
- * Copyright 2010-2018 Branimir Karadzic. All rights reserved.
- * License: https://github.com/bkaradzic/bx#license-bsd-2-clause
+ * Copyright 2010-2022 Branimir Karadzic. All rights reserved.
+ * License: https://github.com/bkaradzic/bx/blob/master/LICENSE
*/
#include "test.h"
#include <bx/thread.h>
+#if BX_CONFIG_SUPPORTS_THREADING
+
bx::DefaultAllocator s_allocator;
bx::MpScUnboundedBlockingQueue<void> s_mpsc(&s_allocator);
@@ -42,7 +44,9 @@ TEST_CASE("Thread", "")
REQUIRE(!th.isRunning() );
- th.init(threadExit0);
+ bool init = th.init(threadExit0, NULL, 0, NULL);
+ REQUIRE(init);
+
REQUIRE(th.isRunning() );
th.push(NULL);
th.shutdown();
@@ -67,3 +71,5 @@ TEST_CASE("MpScUnboundedBlockingQueue", "")
REQUIRE(result == 0x1389);
}
+
+#endif // BX_CONFIG_SUPPORTS_THREADING
diff --git a/3rdparty/bx/tests/tokenizecmd_test.cpp b/3rdparty/bx/tests/tokenizecmd_test.cpp
index e0910fef087..6490a750f7c 100644
--- a/3rdparty/bx/tests/tokenizecmd_test.cpp
+++ b/3rdparty/bx/tests/tokenizecmd_test.cpp
@@ -1,6 +1,6 @@
/*
- * Copyright 2012-2018 Branimir Karadzic. All rights reserved.
- * License: https://github.com/bkaradzic/bx#license-bsd-2-clause
+ * Copyright 2012-2022 Branimir Karadzic. All rights reserved.
+ * License: https://github.com/bkaradzic/bx/blob/master/LICENSE
*/
#include "test.h"
diff --git a/3rdparty/bx/tests/typetraits_test.cpp b/3rdparty/bx/tests/typetraits_test.cpp
new file mode 100644
index 00000000000..aef3e084731
--- /dev/null
+++ b/3rdparty/bx/tests/typetraits_test.cpp
@@ -0,0 +1,688 @@
+/*
+ * Copyright 2010-2022 Branimir Karadzic. All rights reserved.
+ * License: https://github.com/bkaradzic/bx/blob/master/LICENSE
+ */
+
+#include "test.h"
+#include <bx/typetraits.h>
+
+struct TestClass { };
+struct TestClassFinal final { };
+struct TestClassMember { int32_t x; };
+struct TestClassMemberPrivate { int32_t x; private: int32_t y; };
+struct TestClassStaticOnly { static int32_t x; };
+struct TestClassCtor { TestClassCtor (const TestClassCtor&) {} };
+struct TestClassDefaultCtor { TestClassDefaultCtor (const TestClassDefaultCtor&) = default; };
+struct TestClassDefaultDtor { ~TestClassDefaultDtor () = default; };
+struct TestClassVirtualDtor { virtual ~TestClassVirtualDtor () = default; };
+struct TestClassAbstractBase { virtual ~TestClassAbstractBase() = 0; };
+struct TestClassPolymorphic { virtual int32_t x() { return 1389; } };
+struct TestClassDerivedA /* */
+ : TestClass { };
+struct TestClassDerivedB /* */
+ : TestClassDerivedA { };
+struct TestClassDerivedX /* */
+ : TestClassVirtualDtor { };
+union TestUnionEmpty { };
+union TestUnion { int32_t x; float y; };
+enum TestEnumEmpty { };
+enum TestEnum { Enum };
+
+TEST_CASE("type-traits isReference", "")
+{
+ STATIC_REQUIRE(!bx::isReference<TestClass >() );
+ STATIC_REQUIRE( bx::isReference<TestClass& >() );
+ STATIC_REQUIRE( bx::isReference<TestClass&& >() );
+ STATIC_REQUIRE(!bx::isReference<long >() );
+ STATIC_REQUIRE( bx::isReference<long& >() );
+ STATIC_REQUIRE( bx::isReference<long&& >() );
+ STATIC_REQUIRE(!bx::isReference<double* >() );
+ STATIC_REQUIRE( bx::isReference<double*& >() );
+ STATIC_REQUIRE( bx::isReference<double*&& >() );;
+}
+
+TEST_CASE("type-traits isLvalueReference", "")
+{
+ STATIC_REQUIRE(!bx::isLvalueReference<TestClass >() );
+ STATIC_REQUIRE( bx::isLvalueReference<TestClass& >() );
+ STATIC_REQUIRE(!bx::isLvalueReference<TestClass&& >() );
+ STATIC_REQUIRE(!bx::isLvalueReference<long >() );
+ STATIC_REQUIRE( bx::isLvalueReference<long& >() );
+ STATIC_REQUIRE(!bx::isLvalueReference<long&& >() );
+ STATIC_REQUIRE(!bx::isLvalueReference<double* >() );
+ STATIC_REQUIRE( bx::isLvalueReference<double*& >() );
+ STATIC_REQUIRE(!bx::isLvalueReference<double*&& >() );;
+}
+
+TEST_CASE("type-traits isRvalueReference", "")
+{
+ STATIC_REQUIRE(!bx::isRvalueReference<TestClass >() );
+ STATIC_REQUIRE(!bx::isRvalueReference<TestClass& >() );
+ STATIC_REQUIRE( bx::isRvalueReference<TestClass&& >() );
+ STATIC_REQUIRE(!bx::isRvalueReference<long >() );
+ STATIC_REQUIRE(!bx::isRvalueReference<long& >() );
+ STATIC_REQUIRE( bx::isRvalueReference<long&& >() );
+ STATIC_REQUIRE(!bx::isRvalueReference<double* >() );
+ STATIC_REQUIRE(!bx::isRvalueReference<double*& >() );
+ STATIC_REQUIRE( bx::isRvalueReference<double*&& >() );;
+}
+
+TEST_CASE("type-traits isPointer", "")
+{
+ STATIC_REQUIRE(!bx::isPointer<TestClass >() );
+ STATIC_REQUIRE(!bx::isPointer<TestClass& >() );
+ STATIC_REQUIRE( bx::isPointer<TestClass* >() );
+ STATIC_REQUIRE( bx::isPointer<TestClass const * volatile >() );
+ STATIC_REQUIRE(!bx::isPointer<int32_t >() );
+ STATIC_REQUIRE( bx::isPointer<int32_t* >() );
+ STATIC_REQUIRE(!bx::isPointer<int32_t[1389] >() );
+}
+
+TEST_CASE("type-traits AddLvalueReferenceT", "")
+{
+ STATIC_REQUIRE( bx::isSame<bx::AddLvalueReferenceType<TestClass >, TestClass& >() );
+ STATIC_REQUIRE( bx::isSame<bx::AddLvalueReferenceType<TestClass& >, TestClass& >() );
+ STATIC_REQUIRE( bx::isSame<bx::AddLvalueReferenceType<TestClass&&>, TestClass& >() );
+
+ STATIC_REQUIRE( bx::isLvalueReference<bx::AddLvalueReferenceType<TestClass> >() );
+ STATIC_REQUIRE( bx::isLvalueReference<bx::AddLvalueReferenceType<TestClass&> >() );
+ STATIC_REQUIRE( bx::isLvalueReference<bx::AddLvalueReferenceType<TestClass&&> >() );
+}
+
+TEST_CASE("type-traits AddRvalueReferenceT", "")
+{
+ STATIC_REQUIRE( bx::isSame<bx::AddRvalueReferenceType<TestClass >, TestClass&& >() );
+ STATIC_REQUIRE( bx::isSame<bx::AddRvalueReferenceType<TestClass& >, TestClass& >() );
+ STATIC_REQUIRE( bx::isSame<bx::AddRvalueReferenceType<TestClass&&>, TestClass&& >() );
+
+ STATIC_REQUIRE( bx::isRvalueReference<bx::AddRvalueReferenceType<TestClass> >() );
+ STATIC_REQUIRE(!bx::isRvalueReference<bx::AddRvalueReferenceType<TestClass&> >() );
+ STATIC_REQUIRE( bx::isRvalueReference<bx::AddRvalueReferenceType<TestClass&&> >() );
+}
+
+TEST_CASE("type-traits RemoveReferenceT", "")
+{
+ STATIC_REQUIRE( bx::isSame<bx::RemoveReferenceType<TestClass >, TestClass >() );
+ STATIC_REQUIRE( bx::isSame<bx::RemoveReferenceType<TestClass& >, TestClass >() );
+ STATIC_REQUIRE( bx::isSame<bx::RemoveReferenceType<TestClass&&>, TestClass >() );
+
+ STATIC_REQUIRE(!bx::isReference<bx::RemoveReferenceType<TestClass> >() );
+ STATIC_REQUIRE(!bx::isReference<bx::RemoveReferenceType<TestClass&> >() );
+ STATIC_REQUIRE(!bx::isReference<bx::RemoveReferenceType<TestClass&&> >() );
+}
+
+TEST_CASE("type-traits AddPointerT", "")
+{
+ STATIC_REQUIRE( bx::isSame<bx::AddPointerType<TestClass >, TestClass* >() );
+ STATIC_REQUIRE( bx::isSame<bx::AddPointerType<TestClass* >, TestClass** >() );
+ STATIC_REQUIRE( bx::isSame<bx::AddPointerType<TestClass& >, TestClass* >() );
+ STATIC_REQUIRE( bx::isSame<bx::AddPointerType<TestClass**>, TestClass*** >() );
+
+ STATIC_REQUIRE( bx::isPointer<bx::AddPointerType<TestClass> >() );
+ STATIC_REQUIRE( bx::isPointer<bx::AddPointerType<TestClass*> >() );
+ STATIC_REQUIRE( bx::isPointer<bx::AddPointerType<TestClass&> >() );
+ STATIC_REQUIRE( bx::isPointer<bx::AddPointerType<TestClass**> >() );
+}
+
+TEST_CASE("type-traits RemovePointerT", "")
+{
+ STATIC_REQUIRE( bx::isSame<bx::RemovePointerType<TestClass >, TestClass >() );
+ STATIC_REQUIRE( bx::isSame<bx::RemovePointerType<TestClass* >, TestClass >() );
+ STATIC_REQUIRE( bx::isSame<bx::RemovePointerType<TestClass**>, TestClass* >() );
+ STATIC_REQUIRE( bx::isSame<bx::RemovePointerType<bx::RemovePointerType<TestClass**>>, TestClass >() );
+
+ STATIC_REQUIRE(!bx::isPointer<bx::RemovePointerType<TestClass> >() );
+ STATIC_REQUIRE(!bx::isPointer<bx::RemovePointerType<TestClass*> >() );
+ STATIC_REQUIRE( bx::isPointer<bx::RemovePointerType<TestClass**> >() );
+ STATIC_REQUIRE(!bx::isPointer<bx::RemovePointerType<bx::RemovePointerType<TestClass**>> >() );
+}
+
+TEST_CASE("type-traits AddConstT", "")
+{
+ STATIC_REQUIRE( bx::isSame<bx::AddConstType< TestClass >, const TestClass >() );
+ STATIC_REQUIRE( bx::isSame<bx::AddConstType<const TestClass >, const TestClass >() );
+ STATIC_REQUIRE( bx::isSame<bx::AddConstType< volatile TestClass >, const volatile TestClass >() );
+ STATIC_REQUIRE( bx::isSame<bx::AddConstType<const volatile TestClass >, const volatile TestClass >() );
+ STATIC_REQUIRE( bx::isSame<bx::AddConstType<const volatile TestClass*>, const volatile TestClass* const >() );
+ STATIC_REQUIRE( bx::isSame<bx::AddConstType<TestClass* const volatile>, TestClass* const volatile >() );
+}
+
+TEST_CASE("type-traits RemoveConstT", "")
+{
+ STATIC_REQUIRE( bx::isSame<bx::RemoveConstType< TestClass >, TestClass >() );
+ STATIC_REQUIRE( bx::isSame<bx::RemoveConstType<const TestClass >, TestClass >() );
+ STATIC_REQUIRE( bx::isSame<bx::RemoveConstType< volatile TestClass >, volatile TestClass >() );
+ STATIC_REQUIRE( bx::isSame<bx::RemoveConstType<const volatile TestClass >, volatile TestClass >() );
+ STATIC_REQUIRE(!bx::isSame<bx::RemoveConstType<const volatile TestClass*>, volatile TestClass*>() );
+ STATIC_REQUIRE( bx::isSame<bx::RemoveConstType<TestClass* const volatile>, TestClass* volatile>() );
+}
+
+TEST_CASE("type-traits AddVolatileT", "")
+{
+ STATIC_REQUIRE( bx::isSame<bx::AddVolatileType< TestClass >, volatile TestClass >() );
+ STATIC_REQUIRE( bx::isSame<bx::AddVolatileType<const TestClass >, const volatile TestClass >() );
+ STATIC_REQUIRE( bx::isSame<bx::AddVolatileType< volatile TestClass >, volatile TestClass >() );
+ STATIC_REQUIRE( bx::isSame<bx::AddVolatileType<const volatile TestClass >, const volatile TestClass >() );
+ STATIC_REQUIRE( bx::isSame<bx::AddVolatileType<const volatile TestClass*>, const volatile TestClass* volatile >() );
+ STATIC_REQUIRE( bx::isSame<bx::AddVolatileType<TestClass* const volatile>, TestClass* const volatile >() );
+}
+
+TEST_CASE("type-traits RemoveVolatileT", "")
+{
+ STATIC_REQUIRE( bx::isSame<bx::RemoveVolatileType< TestClass >, TestClass >() );
+ STATIC_REQUIRE( bx::isSame<bx::RemoveVolatileType<const TestClass >, const TestClass >() );
+ STATIC_REQUIRE( bx::isSame<bx::RemoveVolatileType< volatile TestClass >, TestClass >() );
+ STATIC_REQUIRE( bx::isSame<bx::RemoveVolatileType<const volatile TestClass >, const TestClass >() );
+ STATIC_REQUIRE(!bx::isSame<bx::RemoveVolatileType<const volatile TestClass*>, const TestClass* >() );
+ STATIC_REQUIRE( bx::isSame<bx::RemoveVolatileType<TestClass* const volatile>, TestClass* const >() );
+}
+
+TEST_CASE("type-traits AddCvT", "")
+{
+ STATIC_REQUIRE( bx::isSame<bx::AddCvType< TestClass >, const volatile TestClass >() );
+ STATIC_REQUIRE( bx::isSame<bx::AddCvType<const TestClass >, const volatile TestClass >() );
+ STATIC_REQUIRE( bx::isSame<bx::AddCvType< volatile TestClass >, const volatile TestClass >() );
+ STATIC_REQUIRE( bx::isSame<bx::AddCvType<const volatile TestClass >, const volatile TestClass >() );
+ STATIC_REQUIRE( bx::isSame<bx::AddCvType<const volatile TestClass*>, const volatile TestClass* const volatile >() );
+ STATIC_REQUIRE( bx::isSame<bx::AddCvType<TestClass* const volatile>, TestClass* const volatile >() );
+}
+
+TEST_CASE("type-traits RemoveCvT", "")
+{
+ STATIC_REQUIRE( bx::isSame<bx::RemoveCvType< TestClass >, TestClass >() );
+ STATIC_REQUIRE( bx::isSame<bx::RemoveCvType<const TestClass >, TestClass >() );
+ STATIC_REQUIRE( bx::isSame<bx::RemoveCvType< volatile TestClass >, TestClass >() );
+ STATIC_REQUIRE( bx::isSame<bx::RemoveCvType<const volatile TestClass >, TestClass >() );
+ STATIC_REQUIRE(!bx::isSame<bx::RemoveCvType<const volatile TestClass*>, TestClass* >() );
+ STATIC_REQUIRE( bx::isSame<bx::RemoveCvType<TestClass* const volatile>, TestClass* >() );
+}
+
+TEST_CASE("type-traits isTriviallyCopyable", "")
+{
+ STATIC_REQUIRE( bx::isTriviallyCopyable<int32_t >() );
+ STATIC_REQUIRE( bx::isTriviallyCopyable<TestClass >() );
+ STATIC_REQUIRE(!bx::isTriviallyCopyable<TestClassCtor >() );
+ STATIC_REQUIRE( bx::isTriviallyCopyable<TestClassDefaultCtor >() );
+ STATIC_REQUIRE( bx::isTriviallyCopyable<TestClassDefaultDtor >() );
+ STATIC_REQUIRE(!bx::isTriviallyCopyable<TestClassVirtualDtor >() );
+}
+
+TEST_CASE("type-traits isTriviallyConstructible", "")
+{
+ STATIC_REQUIRE( bx::isTriviallyConstructible<int32_t >() );
+ STATIC_REQUIRE( bx::isTriviallyConstructible<TestClass >() );
+ STATIC_REQUIRE(!bx::isTriviallyConstructible<TestClassCtor >() );
+ STATIC_REQUIRE(!bx::isTriviallyConstructible<TestClassDefaultCtor >() );
+ STATIC_REQUIRE( bx::isTriviallyConstructible<TestClassDefaultDtor >() );
+ STATIC_REQUIRE(!bx::isTriviallyConstructible<TestClassVirtualDtor >() );
+}
+
+TEST_CASE("type-traits isTriviallyDestructible", "")
+{
+ STATIC_REQUIRE( bx::isTriviallyDestructible<int32_t >() );
+ STATIC_REQUIRE( bx::isTriviallyDestructible<TestClass >() );
+ STATIC_REQUIRE( bx::isTriviallyDestructible<TestClassCtor >() );
+ STATIC_REQUIRE( bx::isTriviallyDestructible<TestClassDefaultCtor >() );
+ STATIC_REQUIRE( bx::isTriviallyDestructible<TestClassDefaultDtor >() );
+ STATIC_REQUIRE(!bx::isTriviallyDestructible<TestClassVirtualDtor >() );
+}
+
+TEST_CASE("type-traits isSigned", "")
+{
+ STATIC_REQUIRE(!bx::isSigned<bool >() );
+ STATIC_REQUIRE( bx::isSigned<char >() );
+ STATIC_REQUIRE( bx::isSigned<signed char >() );
+ STATIC_REQUIRE(!bx::isSigned<unsigned char >() );
+ STATIC_REQUIRE( bx::isSigned<short >() );
+ STATIC_REQUIRE(!bx::isSigned<unsigned short >() );
+ STATIC_REQUIRE( bx::isSigned<int >() );
+ STATIC_REQUIRE(!bx::isSigned<unsigned int >() );
+ STATIC_REQUIRE( bx::isSigned<long >() );
+ STATIC_REQUIRE(!bx::isSigned<unsigned long >() );
+ STATIC_REQUIRE( bx::isSigned<long long >() );
+ STATIC_REQUIRE(!bx::isSigned<unsigned long long >() );
+ STATIC_REQUIRE( bx::isSigned<long long int >() );
+ STATIC_REQUIRE(!bx::isSigned<unsigned long long int >() );
+
+ STATIC_REQUIRE( bx::isSigned<int8_t >() );
+ STATIC_REQUIRE(!bx::isSigned<uint8_t >() );
+ STATIC_REQUIRE( bx::isSigned<int16_t >() );
+ STATIC_REQUIRE(!bx::isSigned<uint16_t >() );
+ STATIC_REQUIRE( bx::isSigned<int32_t >() );
+ STATIC_REQUIRE(!bx::isSigned<uint32_t >() );
+ STATIC_REQUIRE( bx::isSigned<int64_t >() );
+ STATIC_REQUIRE(!bx::isSigned<uint64_t >() );
+ STATIC_REQUIRE( bx::isSigned<intmax_t >() );
+ STATIC_REQUIRE(!bx::isSigned<uintmax_t >() );
+ STATIC_REQUIRE(!bx::isSigned<uintptr_t >() );
+ STATIC_REQUIRE( bx::isSigned<ptrdiff_t >() );
+ STATIC_REQUIRE(!bx::isSigned<size_t >() );
+
+ STATIC_REQUIRE( bx::isSigned<float >() );
+ STATIC_REQUIRE( bx::isSigned<double >() );
+ STATIC_REQUIRE( bx::isSigned<long double >() );
+}
+
+TEST_CASE("type-traits isUnsigned", "")
+{
+ STATIC_REQUIRE( bx::isUnsigned<bool >() );
+ STATIC_REQUIRE(!bx::isUnsigned<char >() );
+ STATIC_REQUIRE(!bx::isUnsigned<signed char >() );
+ STATIC_REQUIRE( bx::isUnsigned<unsigned char >() );
+ STATIC_REQUIRE(!bx::isUnsigned<short >() );
+ STATIC_REQUIRE( bx::isUnsigned<unsigned short >() );
+ STATIC_REQUIRE(!bx::isUnsigned<int >() );
+ STATIC_REQUIRE( bx::isUnsigned<unsigned int >() );
+ STATIC_REQUIRE(!bx::isUnsigned<long >() );
+ STATIC_REQUIRE( bx::isUnsigned<unsigned long >() );
+ STATIC_REQUIRE(!bx::isUnsigned<long long >() );
+ STATIC_REQUIRE( bx::isUnsigned<unsigned long long >() );
+ STATIC_REQUIRE(!bx::isUnsigned<long long int >() );
+ STATIC_REQUIRE( bx::isUnsigned<unsigned long long int >() );
+
+ STATIC_REQUIRE(!bx::isUnsigned<int8_t >() );
+ STATIC_REQUIRE( bx::isUnsigned<uint8_t >() );
+ STATIC_REQUIRE(!bx::isUnsigned<int16_t >() );
+ STATIC_REQUIRE( bx::isUnsigned<uint16_t >() );
+ STATIC_REQUIRE(!bx::isUnsigned<int32_t >() );
+ STATIC_REQUIRE( bx::isUnsigned<uint32_t >() );
+ STATIC_REQUIRE(!bx::isUnsigned<int64_t >() );
+ STATIC_REQUIRE( bx::isUnsigned<uint64_t >() );
+ STATIC_REQUIRE(!bx::isUnsigned<intmax_t >() );
+ STATIC_REQUIRE( bx::isUnsigned<uintmax_t >() );
+ STATIC_REQUIRE( bx::isUnsigned<uintptr_t >() );
+ STATIC_REQUIRE(!bx::isUnsigned<ptrdiff_t >() );
+ STATIC_REQUIRE( bx::isUnsigned<size_t >() );
+
+ STATIC_REQUIRE(!bx::isUnsigned<float >() );
+ STATIC_REQUIRE(!bx::isUnsigned<double >() );
+ STATIC_REQUIRE(!bx::isUnsigned<long double >() );
+}
+
+TEST_CASE("type-traits isInteger", "")
+{
+ STATIC_REQUIRE( bx::isInteger<bool >() );
+ STATIC_REQUIRE( bx::isInteger<char >() );
+ STATIC_REQUIRE( bx::isInteger<signed char >() );
+ STATIC_REQUIRE( bx::isInteger<unsigned char >() );
+ STATIC_REQUIRE( bx::isInteger<short >() );
+ STATIC_REQUIRE( bx::isInteger<unsigned short >() );
+ STATIC_REQUIRE( bx::isInteger<int >() );
+ STATIC_REQUIRE( bx::isInteger<unsigned int >() );
+ STATIC_REQUIRE( bx::isInteger<long >() );
+ STATIC_REQUIRE( bx::isInteger<unsigned long >() );
+ STATIC_REQUIRE( bx::isInteger<long long >() );
+ STATIC_REQUIRE( bx::isInteger<unsigned long long >() );
+ STATIC_REQUIRE( bx::isInteger<long long int >() );
+ STATIC_REQUIRE( bx::isInteger<unsigned long long int >() );
+
+ STATIC_REQUIRE( bx::isInteger<int8_t >() );
+ STATIC_REQUIRE( bx::isInteger<uint8_t >() );
+ STATIC_REQUIRE( bx::isInteger<int16_t >() );
+ STATIC_REQUIRE( bx::isInteger<uint16_t >() );
+ STATIC_REQUIRE( bx::isInteger<int32_t >() );
+ STATIC_REQUIRE( bx::isInteger<uint32_t >() );
+ STATIC_REQUIRE( bx::isInteger<int64_t >() );
+ STATIC_REQUIRE( bx::isInteger<uint64_t >() );
+ STATIC_REQUIRE( bx::isInteger<intmax_t >() );
+ STATIC_REQUIRE( bx::isInteger<uintmax_t >() );
+ STATIC_REQUIRE( bx::isInteger<uintptr_t >() );
+ STATIC_REQUIRE( bx::isInteger<ptrdiff_t >() );
+ STATIC_REQUIRE( bx::isInteger<size_t >() );
+
+ STATIC_REQUIRE(!bx::isInteger<float >() );
+ STATIC_REQUIRE(!bx::isInteger<double >() );
+ STATIC_REQUIRE(!bx::isInteger<long double >() );
+
+ STATIC_REQUIRE(!bx::isInteger<TestClass >() );
+ STATIC_REQUIRE(!bx::isInteger<TestClassCtor >() );
+ STATIC_REQUIRE(!bx::isInteger<TestClassDefaultCtor >() );
+ STATIC_REQUIRE(!bx::isInteger<TestClassDefaultDtor >() );
+ STATIC_REQUIRE(!bx::isInteger<TestClassVirtualDtor >() );
+}
+
+TEST_CASE("type-traits isFloatingPoint", "")
+{
+ STATIC_REQUIRE(!bx::isFloatingPoint<bool >() );
+ STATIC_REQUIRE(!bx::isFloatingPoint<char >() );
+ STATIC_REQUIRE(!bx::isFloatingPoint<signed char >() );
+ STATIC_REQUIRE(!bx::isFloatingPoint<unsigned char >() );
+ STATIC_REQUIRE(!bx::isFloatingPoint<short >() );
+ STATIC_REQUIRE(!bx::isFloatingPoint<unsigned short >() );
+ STATIC_REQUIRE(!bx::isFloatingPoint<int >() );
+ STATIC_REQUIRE(!bx::isFloatingPoint<unsigned int >() );
+ STATIC_REQUIRE(!bx::isFloatingPoint<long >() );
+ STATIC_REQUIRE(!bx::isFloatingPoint<unsigned long >() );
+ STATIC_REQUIRE(!bx::isFloatingPoint<long long >() );
+ STATIC_REQUIRE(!bx::isFloatingPoint<unsigned long long >() );
+ STATIC_REQUIRE(!bx::isFloatingPoint<long long int >() );
+ STATIC_REQUIRE(!bx::isFloatingPoint<unsigned long long int >() );
+
+ STATIC_REQUIRE(!bx::isFloatingPoint<int8_t >() );
+ STATIC_REQUIRE(!bx::isFloatingPoint<uint8_t >() );
+ STATIC_REQUIRE(!bx::isFloatingPoint<int16_t >() );
+ STATIC_REQUIRE(!bx::isFloatingPoint<uint16_t >() );
+ STATIC_REQUIRE(!bx::isFloatingPoint<int32_t >() );
+ STATIC_REQUIRE(!bx::isFloatingPoint<uint32_t >() );
+ STATIC_REQUIRE(!bx::isFloatingPoint<int64_t >() );
+ STATIC_REQUIRE(!bx::isFloatingPoint<uint64_t >() );
+
+ STATIC_REQUIRE(!bx::isFloatingPoint<intmax_t >() );
+ STATIC_REQUIRE(!bx::isFloatingPoint<uintmax_t >() );
+ STATIC_REQUIRE(!bx::isFloatingPoint<uintptr_t >() );
+ STATIC_REQUIRE(!bx::isFloatingPoint<ptrdiff_t >() );
+ STATIC_REQUIRE(!bx::isFloatingPoint<size_t >() );
+
+ STATIC_REQUIRE( bx::isFloatingPoint<float >() );
+ STATIC_REQUIRE( bx::isFloatingPoint<double >() );
+ STATIC_REQUIRE( bx::isFloatingPoint<long double >() );
+
+ STATIC_REQUIRE(!bx::isFloatingPoint<TestClass >() );
+ STATIC_REQUIRE(!bx::isFloatingPoint<TestClassCtor >() );
+ STATIC_REQUIRE(!bx::isFloatingPoint<TestClassDefaultCtor >() );
+ STATIC_REQUIRE(!bx::isFloatingPoint<TestClassDefaultDtor >() );
+ STATIC_REQUIRE(!bx::isFloatingPoint<TestClassVirtualDtor >() );
+}
+
+TEST_CASE("type-traits isArithmetic", "")
+{
+ STATIC_REQUIRE( bx::isArithmetic<bool >() );
+ STATIC_REQUIRE( bx::isArithmetic<char >() );
+ STATIC_REQUIRE( bx::isArithmetic<signed char >() );
+ STATIC_REQUIRE( bx::isArithmetic<unsigned char >() );
+ STATIC_REQUIRE( bx::isArithmetic<short >() );
+ STATIC_REQUIRE( bx::isArithmetic<unsigned short >() );
+ STATIC_REQUIRE( bx::isArithmetic<int >() );
+ STATIC_REQUIRE( bx::isArithmetic<unsigned int >() );
+ STATIC_REQUIRE( bx::isArithmetic<long >() );
+ STATIC_REQUIRE( bx::isArithmetic<unsigned long >() );
+ STATIC_REQUIRE( bx::isArithmetic<long long >() );
+ STATIC_REQUIRE( bx::isArithmetic<unsigned long long >() );
+ STATIC_REQUIRE( bx::isArithmetic<long long int >() );
+ STATIC_REQUIRE( bx::isArithmetic<unsigned long long int >() );
+
+ STATIC_REQUIRE( bx::isArithmetic<int8_t >() );
+ STATIC_REQUIRE( bx::isArithmetic<uint8_t >() );
+ STATIC_REQUIRE( bx::isArithmetic<int16_t >() );
+ STATIC_REQUIRE( bx::isArithmetic<uint16_t >() );
+ STATIC_REQUIRE( bx::isArithmetic<int32_t >() );
+ STATIC_REQUIRE( bx::isArithmetic<uint32_t >() );
+ STATIC_REQUIRE( bx::isArithmetic<int64_t >() );
+ STATIC_REQUIRE( bx::isArithmetic<uint64_t >() );
+ STATIC_REQUIRE( bx::isArithmetic<intmax_t >() );
+ STATIC_REQUIRE( bx::isArithmetic<uintmax_t >() );
+ STATIC_REQUIRE( bx::isArithmetic<uintptr_t >() );
+ STATIC_REQUIRE( bx::isArithmetic<ptrdiff_t >() );
+ STATIC_REQUIRE( bx::isArithmetic<size_t >() );
+
+ STATIC_REQUIRE( bx::isArithmetic<float >() );
+ STATIC_REQUIRE( bx::isArithmetic<double >() );
+ STATIC_REQUIRE( bx::isArithmetic<long double >() );
+
+ STATIC_REQUIRE(!bx::isArithmetic<TestClass >() );
+ STATIC_REQUIRE(!bx::isArithmetic<TestClassCtor >() );
+ STATIC_REQUIRE(!bx::isArithmetic<TestClassDefaultCtor >() );
+ STATIC_REQUIRE(!bx::isArithmetic<TestClassDefaultDtor >() );
+ STATIC_REQUIRE(!bx::isArithmetic<TestClassVirtualDtor >() );
+}
+
+TEST_CASE("type-traits isBoundedArray", "")
+{
+ STATIC_REQUIRE(!bx::isBoundedArray<TestClass >() );
+ STATIC_REQUIRE(!bx::isBoundedArray<TestClass[] >() );
+ STATIC_REQUIRE( bx::isBoundedArray<TestClass[1389] >() );
+ STATIC_REQUIRE(!bx::isBoundedArray<float >() );
+ STATIC_REQUIRE(!bx::isBoundedArray<int >() );
+ STATIC_REQUIRE(!bx::isBoundedArray<int[] >() );
+ STATIC_REQUIRE( bx::isBoundedArray<int[1389] >() );
+}
+
+TEST_CASE("type-traits isUnboundedArray", "")
+{
+ STATIC_REQUIRE(!bx::isUnboundedArray<TestClass >() );
+ STATIC_REQUIRE( bx::isUnboundedArray<TestClass[] >() );
+ STATIC_REQUIRE(!bx::isUnboundedArray<TestClass[1389] >() );
+ STATIC_REQUIRE(!bx::isUnboundedArray<float >() );
+ STATIC_REQUIRE(!bx::isUnboundedArray<int32_t >() );
+ STATIC_REQUIRE( bx::isUnboundedArray<int32_t[] >() );
+ STATIC_REQUIRE(!bx::isUnboundedArray<int32_t[1389] >() );
+}
+
+TEST_CASE("type-traits isArray", "")
+{
+ STATIC_REQUIRE(!bx::isArray<TestClass >() );
+ STATIC_REQUIRE( bx::isArray<TestClass[] >() );
+ STATIC_REQUIRE( bx::isArray<TestClass[1389] >() );
+ STATIC_REQUIRE(!bx::isArray<float >() );
+ STATIC_REQUIRE(!bx::isArray<int32_t >() );
+ STATIC_REQUIRE( bx::isArray<int32_t[] >() );
+ STATIC_REQUIRE( bx::isArray<int32_t[1389] >() );
+ STATIC_REQUIRE( bx::isArray<TestUnion[] >() );
+}
+
+TEST_CASE("type-traits isEnum", "")
+{
+ STATIC_REQUIRE(!bx::isEnum<TestClass >() );
+ STATIC_REQUIRE(!bx::isEnum<TestUnion >() );
+ STATIC_REQUIRE(!bx::isEnum<TestUnionEmpty >() );
+ STATIC_REQUIRE(!bx::isEnum<TestUnion[] >() );
+ STATIC_REQUIRE(!bx::isEnum<int32_t[] >() );
+ STATIC_REQUIRE( bx::isEnum<TestEnumEmpty >() );
+ STATIC_REQUIRE( bx::isEnum<TestEnum >() );
+}
+
+TEST_CASE("type-traits isUnion", "")
+{
+ STATIC_REQUIRE(!bx::isUnion<TestClass >() );
+ STATIC_REQUIRE( bx::isUnion<TestUnion >() );
+ STATIC_REQUIRE( bx::isUnion<TestUnionEmpty >() );
+ STATIC_REQUIRE(!bx::isUnion<TestUnion[] >() );
+ STATIC_REQUIRE(!bx::isUnion<int32_t[] >() );
+ STATIC_REQUIRE(!bx::isUnion<TestEnumEmpty >() );
+ STATIC_REQUIRE(!bx::isUnion<TestEnum >() );
+}
+
+TEST_CASE("type-traits isClass", "")
+{
+ STATIC_REQUIRE( bx::isClass<TestClass >() );
+ STATIC_REQUIRE( bx::isClass<TestClassFinal >() );
+ STATIC_REQUIRE( bx::isClass<TestClassCtor >() );
+ STATIC_REQUIRE( bx::isClass<TestClassMember >() );
+ STATIC_REQUIRE( bx::isClass<TestClassMemberPrivate >() );
+ STATIC_REQUIRE( bx::isClass<TestClassStaticOnly >() );
+ STATIC_REQUIRE( bx::isClass<TestClassDefaultCtor >() );
+ STATIC_REQUIRE( bx::isClass<TestClassDefaultDtor >() );
+ STATIC_REQUIRE( bx::isClass<TestClassVirtualDtor >() );
+ STATIC_REQUIRE( bx::isClass<TestClassAbstractBase >() );
+ STATIC_REQUIRE( bx::isClass<TestClassDerivedA >() );
+ STATIC_REQUIRE( bx::isClass<TestClassDerivedB >() );
+ STATIC_REQUIRE(!bx::isClass<TestUnion >() );
+ STATIC_REQUIRE(!bx::isClass<TestUnion[] >() );
+ STATIC_REQUIRE(!bx::isClass<int32_t[] >() );
+}
+
+TEST_CASE("type-traits isFinal", "")
+{
+ STATIC_REQUIRE(!bx::isFinal<TestClass >() );
+ STATIC_REQUIRE( bx::isFinal<TestClassFinal >() );
+ STATIC_REQUIRE(!bx::isFinal<TestClassCtor >() );
+ STATIC_REQUIRE(!bx::isFinal<TestClassMember >() );
+ STATIC_REQUIRE(!bx::isFinal<TestClassMemberPrivate >() );
+ STATIC_REQUIRE(!bx::isFinal<TestClassStaticOnly >() );
+ STATIC_REQUIRE(!bx::isFinal<TestClassDefaultCtor >() );
+ STATIC_REQUIRE(!bx::isFinal<TestClassDefaultDtor >() );
+ STATIC_REQUIRE(!bx::isFinal<TestClassVirtualDtor >() );
+ STATIC_REQUIRE(!bx::isFinal<TestClassAbstractBase >() );
+ STATIC_REQUIRE(!bx::isFinal<TestClassPolymorphic >() );
+ STATIC_REQUIRE(!bx::isFinal<TestClassDerivedA >() );
+ STATIC_REQUIRE(!bx::isFinal<TestClassDerivedB >() );
+ STATIC_REQUIRE(!bx::isFinal<TestUnion >() );
+ STATIC_REQUIRE(!bx::isFinal<TestUnionEmpty >() );
+ STATIC_REQUIRE(!bx::isFinal<TestUnion[] >() );
+ STATIC_REQUIRE(!bx::isFinal<int32_t[] >() );
+}
+
+TEST_CASE("type-traits isEmpty", "")
+{
+ STATIC_REQUIRE( bx::isEmpty<TestClass >() );
+ STATIC_REQUIRE( bx::isEmpty<TestClassFinal >() );
+ STATIC_REQUIRE( bx::isEmpty<TestClassCtor >() );
+ STATIC_REQUIRE( bx::isEmpty<TestClassDefaultCtor >() );
+ STATIC_REQUIRE( bx::isEmpty<TestClassDefaultDtor >() );
+ STATIC_REQUIRE(!bx::isEmpty<TestClassVirtualDtor >() );
+ STATIC_REQUIRE(!bx::isEmpty<TestClassAbstractBase >() );
+ STATIC_REQUIRE(!bx::isEmpty<TestClassPolymorphic >() );
+ STATIC_REQUIRE(!bx::isEmpty<TestUnion >() );
+ STATIC_REQUIRE(!bx::isEmpty<TestUnionEmpty >() );
+ STATIC_REQUIRE(!bx::isEmpty<TestUnion[] >() );
+ STATIC_REQUIRE(!bx::isEmpty<int32_t[] >() );
+}
+
+TEST_CASE("type-traits isStandardLayout", "")
+{
+ STATIC_REQUIRE( bx::isStandardLayout<TestClass >() );
+ STATIC_REQUIRE( bx::isStandardLayout<TestClassFinal >() );
+ STATIC_REQUIRE( bx::isStandardLayout<TestClassCtor >() );
+ STATIC_REQUIRE( bx::isStandardLayout<TestClassMember >() );
+ STATIC_REQUIRE(!bx::isStandardLayout<TestClassMemberPrivate >() );
+ STATIC_REQUIRE( bx::isStandardLayout<TestClassStaticOnly >() );
+ STATIC_REQUIRE( bx::isStandardLayout<TestClassDefaultCtor >() );
+ STATIC_REQUIRE( bx::isStandardLayout<TestClassDefaultDtor >() );
+ STATIC_REQUIRE(!bx::isStandardLayout<TestClassVirtualDtor >() );
+ STATIC_REQUIRE(!bx::isStandardLayout<TestClassAbstractBase >() );
+ STATIC_REQUIRE(!bx::isStandardLayout<TestClassPolymorphic >() );
+ STATIC_REQUIRE( bx::isStandardLayout<TestClassDerivedA >() );
+ STATIC_REQUIRE( bx::isStandardLayout<TestClassDerivedB >() );
+ STATIC_REQUIRE( bx::isStandardLayout<TestUnion >() );
+ STATIC_REQUIRE( bx::isStandardLayout<TestUnionEmpty >() );
+ STATIC_REQUIRE( bx::isStandardLayout<TestUnion[] >() );
+ STATIC_REQUIRE( bx::isStandardLayout<int32_t[] >() );
+}
+
+TEST_CASE("type-traits isTrivial", "")
+{
+ STATIC_REQUIRE( bx::isTrivial<TestClass >() );
+ STATIC_REQUIRE( bx::isTrivial<TestClassFinal >() );
+ STATIC_REQUIRE(!bx::isTrivial<TestClassCtor >() );
+ STATIC_REQUIRE( bx::isTrivial<TestClassMember >() );
+ STATIC_REQUIRE( bx::isTrivial<TestClassMemberPrivate >() );
+ STATIC_REQUIRE( bx::isTrivial<TestClassStaticOnly >() );
+ STATIC_REQUIRE(!bx::isTrivial<TestClassDefaultCtor >() );
+ STATIC_REQUIRE( bx::isTrivial<TestClassDefaultDtor >() );
+ STATIC_REQUIRE(!bx::isTrivial<TestClassVirtualDtor >() );
+ STATIC_REQUIRE(!bx::isTrivial<TestClassAbstractBase >() );
+ STATIC_REQUIRE(!bx::isTrivial<TestClassPolymorphic >() );
+ STATIC_REQUIRE( bx::isTrivial<TestClassDerivedA >() );
+ STATIC_REQUIRE( bx::isTrivial<TestClassDerivedB >() );
+ STATIC_REQUIRE( bx::isTrivial<TestUnion >() );
+ STATIC_REQUIRE( bx::isTrivial<TestUnionEmpty >() );
+ STATIC_REQUIRE( bx::isTrivial<TestUnion[] >() );
+ STATIC_REQUIRE( bx::isTrivial<int32_t[] >() );
+}
+
+TEST_CASE("type-traits isPod", "")
+{
+ STATIC_REQUIRE( bx::isPod<TestClass >() );
+ STATIC_REQUIRE( bx::isPod<TestClassFinal >() );
+ STATIC_REQUIRE(!bx::isPod<TestClassCtor >() );
+ STATIC_REQUIRE( bx::isPod<TestClassMember >() );
+ STATIC_REQUIRE(!bx::isPod<TestClassMemberPrivate >() );
+ STATIC_REQUIRE( bx::isPod<TestClassStaticOnly >() );
+ STATIC_REQUIRE(!bx::isPod<TestClassDefaultCtor >() );
+ STATIC_REQUIRE( bx::isPod<TestClassDefaultDtor >() );
+ STATIC_REQUIRE(!bx::isPod<TestClassVirtualDtor >() );
+ STATIC_REQUIRE(!bx::isPod<TestClassPolymorphic >() );
+ STATIC_REQUIRE(!bx::isPod<TestClassAbstractBase >() );
+ STATIC_REQUIRE( bx::isPod<TestClassDerivedA >() );
+ STATIC_REQUIRE( bx::isPod<TestClassDerivedB >() );
+ STATIC_REQUIRE( bx::isPod<TestUnion >() );
+ STATIC_REQUIRE( bx::isPod<TestUnionEmpty >() );
+ STATIC_REQUIRE( bx::isPod<TestUnion[] >() );
+ STATIC_REQUIRE( bx::isPod<int32_t[] >() );
+}
+
+TEST_CASE("type-traits isPolymorphic", "")
+{
+ STATIC_REQUIRE(!bx::isPolymorphic<TestClass >() );
+ STATIC_REQUIRE(!bx::isPolymorphic<TestClassFinal >() );
+ STATIC_REQUIRE(!bx::isPolymorphic<TestClassCtor >() );
+ STATIC_REQUIRE(!bx::isPolymorphic<TestClassMember >() );
+ STATIC_REQUIRE(!bx::isPolymorphic<TestClassMemberPrivate >() );
+ STATIC_REQUIRE(!bx::isPolymorphic<TestClassStaticOnly >() );
+ STATIC_REQUIRE(!bx::isPolymorphic<TestClassDefaultCtor >() );
+ STATIC_REQUIRE(!bx::isPolymorphic<TestClassDefaultDtor >() );
+ STATIC_REQUIRE( bx::isPolymorphic<TestClassVirtualDtor >() );
+ STATIC_REQUIRE( bx::isPolymorphic<TestClassAbstractBase >() );
+ STATIC_REQUIRE( bx::isPolymorphic<TestClassPolymorphic >() );
+ STATIC_REQUIRE(!bx::isPolymorphic<TestClassDerivedA >() );
+ STATIC_REQUIRE(!bx::isPolymorphic<TestClassDerivedB >() );
+ STATIC_REQUIRE( bx::isPolymorphic<TestClassDerivedX >() );
+ STATIC_REQUIRE(!bx::isPolymorphic<TestUnion >() );
+ STATIC_REQUIRE(!bx::isPolymorphic<TestUnionEmpty >() );
+ STATIC_REQUIRE(!bx::isPolymorphic<TestUnion[] >() );
+ STATIC_REQUIRE(!bx::isPolymorphic<int32_t[] >() );
+}
+
+TEST_CASE("type-traits isDestructorVirtual", "")
+{
+ STATIC_REQUIRE(!bx::isDestructorVirtual<TestClass >() );
+ STATIC_REQUIRE(!bx::isDestructorVirtual<TestClassFinal >() );
+ STATIC_REQUIRE(!bx::isDestructorVirtual<TestClassCtor >() );
+ STATIC_REQUIRE(!bx::isDestructorVirtual<TestClassMember >() );
+ STATIC_REQUIRE(!bx::isDestructorVirtual<TestClassMemberPrivate >() );
+ STATIC_REQUIRE(!bx::isDestructorVirtual<TestClassStaticOnly >() );
+ STATIC_REQUIRE(!bx::isDestructorVirtual<TestClassDefaultCtor >() );
+ STATIC_REQUIRE(!bx::isDestructorVirtual<TestClassDefaultDtor >() );
+ STATIC_REQUIRE( bx::isDestructorVirtual<TestClassVirtualDtor >() );
+ STATIC_REQUIRE( bx::isDestructorVirtual<TestClassAbstractBase >() );
+ STATIC_REQUIRE(!bx::isDestructorVirtual<TestClassPolymorphic >() );
+ STATIC_REQUIRE(!bx::isDestructorVirtual<TestClassDerivedA >() );
+ STATIC_REQUIRE(!bx::isDestructorVirtual<TestClassDerivedB >() );
+ STATIC_REQUIRE( bx::isDestructorVirtual<TestClassDerivedX >() );
+ STATIC_REQUIRE(!bx::isDestructorVirtual<TestUnion >() );
+ STATIC_REQUIRE(!bx::isDestructorVirtual<TestUnionEmpty >() );
+ STATIC_REQUIRE(!bx::isDestructorVirtual<TestUnion[] >() );
+ STATIC_REQUIRE(!bx::isDestructorVirtual<int32_t[] >() );
+}
+
+TEST_CASE("type-traits isBaseOf", "")
+{
+ STATIC_REQUIRE( bx::isBaseOf<TestClass, TestClass >() );
+ STATIC_REQUIRE( bx::isBaseOf<TestClass, TestClassDerivedA >() );
+ STATIC_REQUIRE( bx::isBaseOf<TestClass, TestClassDerivedB >() );
+ STATIC_REQUIRE(!bx::isBaseOf<TestClass, TestClassFinal >() );
+ STATIC_REQUIRE(!bx::isBaseOf<TestClassDerivedB, TestClassDerivedA >() );
+ STATIC_REQUIRE(!bx::isBaseOf<TestClassDerivedB, TestClassDerivedX >() );
+ STATIC_REQUIRE(!bx::isBaseOf<int32_t, int32_t >() );
+}
+
+TEST_CASE("type-traits isAggregate", "")
+{
+ STATIC_REQUIRE( bx::isAggregate<TestClass >() );
+ STATIC_REQUIRE( bx::isAggregate<TestClassFinal >() );
+ STATIC_REQUIRE(!bx::isAggregate<TestClassCtor >() );
+ STATIC_REQUIRE( bx::isAggregate<TestClassMember >() );
+ STATIC_REQUIRE(!bx::isAggregate<TestClassMemberPrivate >() );
+ STATIC_REQUIRE( bx::isAggregate<TestClassStaticOnly >() );
+#if __cplusplus < BX_LANGUAGE_CPP20
+ STATIC_REQUIRE( bx::isAggregate<TestClassDefaultCtor >() );
+#else
+ STATIC_REQUIRE(!bx::isAggregate<TestClassDefaultCtor >() );
+#endif
+ STATIC_REQUIRE( bx::isAggregate<TestClassDefaultDtor >() );
+ STATIC_REQUIRE(!bx::isAggregate<TestClassVirtualDtor >() );
+ STATIC_REQUIRE(!bx::isAggregate<TestClassAbstractBase >() );
+ STATIC_REQUIRE(!bx::isAggregate<TestClassPolymorphic >() );
+#if __cplusplus < BX_LANGUAGE_CPP17
+ STATIC_REQUIRE(!bx::isAggregate<TestClassDerivedA >() );
+ STATIC_REQUIRE(!bx::isAggregate<TestClassDerivedB >() );
+#else
+ STATIC_REQUIRE( bx::isAggregate<TestClassDerivedA >() );
+ STATIC_REQUIRE( bx::isAggregate<TestClassDerivedB >() );
+#endif
+ STATIC_REQUIRE(!bx::isAggregate<TestClassDerivedX >() );
+ STATIC_REQUIRE( bx::isAggregate<TestUnion >() );
+ STATIC_REQUIRE( bx::isAggregate<TestUnionEmpty >() );
+ STATIC_REQUIRE( bx::isAggregate<TestUnion[] >() );
+ STATIC_REQUIRE( bx::isAggregate<int32_t[] >() );
+}
diff --git a/3rdparty/bx/tests/uint32_test.cpp b/3rdparty/bx/tests/uint32_test.cpp
index bb7e0dccacd..572bcdf4880 100644
--- a/3rdparty/bx/tests/uint32_test.cpp
+++ b/3rdparty/bx/tests/uint32_test.cpp
@@ -1,6 +1,6 @@
/*
- * Copyright 2010-2018 Branimir Karadzic. All rights reserved.
- * License: https://github.com/bkaradzic/bx#license-bsd-2-clause
+ * Copyright 2010-2022 Branimir Karadzic. All rights reserved.
+ * License: https://github.com/bkaradzic/bx/blob/master/LICENSE
*/
#include "test.h"
@@ -14,28 +14,57 @@ TEST_CASE("StrideAlign")
REQUIRE(12 == bx::strideAlign(ii+1, 12) );
}
- REQUIRE(0 == bx::strideAlign16(0, 12) );
+ REQUIRE(0 == bx::strideAlign<16>(0, 12) );
for (uint32_t ii = 0; ii < 12; ++ii)
{
- REQUIRE(48 == bx::strideAlign16(ii+1, 12) );
+ REQUIRE(48 == bx::strideAlign<16>(ii+1, 12) );
}
+
+ uint32_t offset = 11;
+ offset = bx::strideAlign(offset, 32);
+ REQUIRE(offset == 32);
+
+ offset = bx::strideAlign(offset, 24);
+ REQUIRE(offset == 48);
}
TEST_CASE("uint32_cnt")
{
- REQUIRE( 0 == bx::uint32_cnttz(UINT32_C(1) ) );
-
- REQUIRE(31 == bx::uint32_cntlz(UINT32_C(1) ) );
-
- REQUIRE( 0 == bx::uint64_cnttz(UINT64_C(1) ) );
-
- REQUIRE(63 == bx::uint64_cntlz(UINT64_C(1) ) );
-
+ REQUIRE( 0 == bx::uint32_cnttz<uint8_t >(1) );
+ REQUIRE( 7 == bx::uint32_cnttz<uint8_t >(1<<7) );
+ REQUIRE( 8 == bx::uint32_cnttz<uint8_t >(0) );
+ REQUIRE( 1 == bx::uint32_cnttz<uint8_t >(0x3e) );
+ REQUIRE( 0 == bx::uint32_cnttz<uint16_t>(1) );
+ REQUIRE(15 == bx::uint32_cnttz<uint16_t>(1<<15) );
+ REQUIRE(16 == bx::uint32_cnttz<uint16_t>(0) );
+ REQUIRE( 0 == bx::uint32_cnttz<uint32_t>(1) );
+ REQUIRE(32 == bx::uint32_cnttz<uint32_t>(0) );
+ REQUIRE(31 == bx::uint32_cnttz<uint32_t>(1u<<31) );
+ REQUIRE( 0 == bx::uint32_cnttz<uint64_t>(1) );
+ REQUIRE(64 == bx::uint32_cnttz<uint64_t>(0) );
+
+ REQUIRE( 7 == bx::uint32_cntlz<uint8_t >(1) );
+ REQUIRE( 8 == bx::uint32_cntlz<uint8_t >(0) );
+ REQUIRE( 2 == bx::uint32_cntlz<uint8_t >(0x3e) );
+ REQUIRE(15 == bx::uint32_cntlz<uint16_t>(1) );
+ REQUIRE(16 == bx::uint32_cntlz<uint16_t>(0) );
+ REQUIRE(31 == bx::uint32_cntlz<uint32_t>(1) );
+ REQUIRE(32 == bx::uint32_cntlz<uint32_t>(0) );
+ REQUIRE(63 == bx::uint32_cntlz<uint64_t>(1) );
+ REQUIRE(64 == bx::uint32_cntlz<uint64_t>(0) );
+
+ REQUIRE( 0 == bx::uint32_cntbits(0) );
REQUIRE( 1 == bx::uint32_cntbits(1) );
- REQUIRE(16 == bx::uint32_cntbits(UINT16_MAX) );
+ REQUIRE( 4 == bx::uint32_cntbits<uint8_t>(0x55) );
+ REQUIRE( 8 == bx::uint32_cntbits<uint16_t>(0x5555) );
+ REQUIRE(16 == bx::uint32_cntbits<uint32_t>(0x55555555) );
+ REQUIRE(32 == bx::uint32_cntbits<uint64_t>(0x5555555555555555) );
+ REQUIRE( 8 == bx::uint32_cntbits(UINT8_MAX) );
+ REQUIRE(16 == bx::uint32_cntbits(UINT16_MAX) );
REQUIRE(32 == bx::uint32_cntbits(UINT32_MAX) );
+ REQUIRE(64 == bx::uint32_cntbits(UINT64_MAX) );
}
TEST_CASE("uint32_part")
@@ -88,3 +117,35 @@ TEST_CASE("uint64_roX", "")
REQUIRE(bx::uint64_rol(0x8000000000000000, 1) == 1);
REQUIRE(bx::uint64_ror(1, 1) == 0x8000000000000000);
}
+
+TEST_CASE("align", "")
+{
+ REQUIRE( bx::isAligned(0, 8) );
+ REQUIRE(!bx::isAligned(7, 8) );
+ REQUIRE( bx::isAligned(64, 8) );
+ REQUIRE(!bx::isAligned(63, 8) );
+
+ REQUIRE( 0 == bx::alignUp( 0, 16) );
+ REQUIRE( 16 == bx::alignUp( 1, 16) );
+ REQUIRE( 16 == bx::alignUp( 15, 16) );
+ REQUIRE( 16 == bx::alignUp( 16, 16) );
+ REQUIRE(256 == bx::alignUp(255, 16) );
+ REQUIRE( 0 == bx::alignUp(-1, 16) );
+ REQUIRE(-16 == bx::alignUp(-31, 16) );
+
+ REQUIRE( 0 == bx::alignUp( 0, 256) );
+ REQUIRE(256 == bx::alignUp( 1, 256) );
+ REQUIRE(256 == bx::alignUp( 15, 256) );
+ REQUIRE(256 == bx::alignUp(255, 256) );
+ REQUIRE(256 == bx::alignUp(256, 256) );
+ REQUIRE(256 == bx::alignUp(256, 256) );
+ REQUIRE(512 == bx::alignUp(511, 256) );
+
+ REQUIRE( 0 == bx::alignDown( 0, 16) );
+ REQUIRE( 0 == bx::alignDown( 1, 16) );
+ REQUIRE( 0 == bx::alignDown( 15, 16) );
+ REQUIRE( 16 == bx::alignDown( 16, 16) );
+ REQUIRE(240 == bx::alignDown(255, 16) );
+ REQUIRE(-16 == bx::alignDown(-1, 16) );
+ REQUIRE(-32 == bx::alignDown(-31, 16) );
+}
diff --git a/3rdparty/bx/tests/url_test.cpp b/3rdparty/bx/tests/url_test.cpp
index 50d2c3924d5..a488ae9e545 100644
--- a/3rdparty/bx/tests/url_test.cpp
+++ b/3rdparty/bx/tests/url_test.cpp
@@ -1,6 +1,6 @@
/*
- * Copyright 2010-2018 Branimir Karadzic. All rights reserved.
- * License: https://github.com/bkaradzic/bx#license-bsd-2-clause
+ * Copyright 2010-2022 Branimir Karadzic. All rights reserved.
+ * License: https://github.com/bkaradzic/bx/blob/master/LICENSE
*/
#include "test.h"
diff --git a/3rdparty/bx/tests/vsnprintf_test.cpp b/3rdparty/bx/tests/vsnprintf_test.cpp
index 844f6363ce2..de7649b74f5 100644
--- a/3rdparty/bx/tests/vsnprintf_test.cpp
+++ b/3rdparty/bx/tests/vsnprintf_test.cpp
@@ -1,6 +1,6 @@
/*
- * Copyright 2010-2018 Branimir Karadzic. All rights reserved.
- * License: https://github.com/bkaradzic/bx#license-bsd-2-clause
+ * Copyright 2010-2022 Branimir Karadzic. All rights reserved.
+ * License: https://github.com/bkaradzic/bx/blob/master/LICENSE
*/
#include "test.h"
@@ -66,6 +66,76 @@ TEST_CASE("vsnprintf f")
REQUIRE(test(" inf", "%8f", std::numeric_limits<double>::infinity() ) );
REQUIRE(test("inf ", "%-8f", std::numeric_limits<double>::infinity() ) );
REQUIRE(test(" -INF", "%8F", -std::numeric_limits<double>::infinity() ) );
+
+ REQUIRE(test(" 1.0", "%4.1f", 1.0) );
+ REQUIRE(test(" 1.500", "%6.3f", 1.5) );
+ REQUIRE(test("0001.500", "%08.3f", 1.5) );
+ REQUIRE(test("+001.500", "%+08.3f", 1.5) );
+ REQUIRE(test("-001.500", "%+08.3f", -1.5) );
+ REQUIRE(test("0.0039", "%.4f", 0.00390625) );
+
+ REQUIRE(test("0.003906", "%f", 0.00390625) );
+ REQUIRE(test("-1.234567e-9", "%f", -1.234567e-9) );
+
+ REQUIRE(test("-1e-9", "%.0f", -1.234567e-9) );
+ REQUIRE(test("-1.2e-9", "%.1f", -1.234567e-9) );
+ REQUIRE(test("-1.23e-9", "%.2f", -1.234567e-9) );
+ REQUIRE(test("-1.234e-9", "%.3f", -1.234567e-9) );
+ REQUIRE(test("-1.2345e-9", "%.4f", -1.234567e-9) );
+ REQUIRE(test("-1.23456e-9", "%.5f", -1.234567e-9) );
+ REQUIRE(test("-1.234567e-9", "%.6f", -1.234567e-9) );
+ REQUIRE(test("-1.2345670e-9", "%.7f", -1.234567e-9) );
+ REQUIRE(test("-1.23456700e-9", "%.8f", -1.234567e-9) );
+ REQUIRE(test("-1.234567000e-9", "%.9f", -1.234567e-9) );
+ REQUIRE(test("-1.2345670000e-9", "%.10f", -1.234567e-9) );
+
+ REQUIRE(test("3.141592", "%f", 3.1415926535897932) );
+ REQUIRE(test("3.141592", "%F", 3.1415926535897932) );
+ REQUIRE(test("3", "%.0f", 3.1415926535897932) );
+ REQUIRE(test("3.1", "%.1f", 3.1415926535897932) );
+ REQUIRE(test("3.14", "%.2f", 3.1415926535897932) );
+ REQUIRE(test("3.141", "%.3f", 3.1415926535897932) );
+ REQUIRE(test("3.1415", "%.4f", 3.1415926535897932) );
+ REQUIRE(test("3.14159", "%.5f", 3.1415926535897932) );
+ REQUIRE(test("3.141592", "%.6f", 3.1415926535897932) );
+ REQUIRE(test("3.1415926", "%.7f", 3.1415926535897932) );
+ REQUIRE(test("3.14159265", "%.8f", 3.1415926535897932) );
+ REQUIRE(test("3.141592653", "%.9f", 3.1415926535897932) );
+ REQUIRE(test("3.1415926535", "%.10f", 3.1415926535897932) );
+ REQUIRE(test("3.14159265358", "%.11f", 3.1415926535897932) );
+ REQUIRE(test("3.141592653589", "%.12f", 3.1415926535897932) );
+ REQUIRE(test("3.1415926535897", "%.13f", 3.1415926535897932) );
+ REQUIRE(test("3.14159265358979", "%.14f", 3.1415926535897932) );
+ REQUIRE(test("3.141592653589793", "%.15f", 3.1415926535897932) );
+ REQUIRE(test("3.1415926535897930", "%.16f", 3.1415926535897932) );
+ REQUIRE(test("3.1415926535897930", "%.16F", 3.1415926535897932) );
+
+ REQUIRE(test("-3.141592e-9", "%f", -3.1415926535897932e-9) );
+ REQUIRE(test("-3.141592E-9", "%F", -3.1415926535897932e-9) );
+ REQUIRE(test("-3e-9", "%.0f", -3.1415926535897932e-9) );
+ REQUIRE(test("-3.1e-9", "%.1f", -3.1415926535897932e-9) );
+ REQUIRE(test("-3.14e-9", "%.2f", -3.1415926535897932e-9) );
+ REQUIRE(test("-3.141e-9", "%.3f", -3.1415926535897932e-9) );
+ REQUIRE(test("-3.1415e-9", "%.4f", -3.1415926535897932e-9) );
+ REQUIRE(test("-3.14159e-9", "%.5f", -3.1415926535897932e-9) );
+ REQUIRE(test("-3.141592e-9", "%.6f", -3.1415926535897932e-9) );
+ REQUIRE(test("-3.1415926e-9", "%.7f", -3.1415926535897932e-9) );
+ REQUIRE(test("-3.14159265e-9", "%.8f", -3.1415926535897932e-9) );
+ REQUIRE(test("-3.141592653e-9", "%.9f", -3.1415926535897932e-9) );
+ REQUIRE(test("-3.1415926535e-9", "%.10f", -3.1415926535897932e-9) );
+ REQUIRE(test("-3.14159265358e-9", "%.11f", -3.1415926535897932e-9) );
+ REQUIRE(test("-3.141592653589e-9", "%.12f", -3.1415926535897932e-9) );
+ REQUIRE(test("-3.1415926535897e-9", "%.13f", -3.1415926535897932e-9) );
+ REQUIRE(test("-3.14159265358979e-9", "%.14f", -3.1415926535897932e-9) );
+ REQUIRE(test("-3.141592653589793e-9", "%.15f", -3.1415926535897932e-9) );
+ REQUIRE(test("-3.1415926535897930e-9", "%.16f", -3.1415926535897932e-9) );
+ REQUIRE(test("-3.1415926535897930E-9", "%.16F", -3.1415926535897932e-9) );
+
+ REQUIRE(test("1e-12", "%f", 1e-12));
+
+ REQUIRE(test("0.00390625", "%.8f", 0.00390625) );
+ REQUIRE(test("-0.00390625", "%.8f", -0.00390625) );
+ REQUIRE(test("1.50000000000000000", "%.17f", 1.5) );
}
TEST_CASE("vsnprintf d/i/o/u/x")
@@ -82,6 +152,8 @@ TEST_CASE("vsnprintf d/i/o/u/x")
REQUIRE(test("2471", "%o", 1337) );
REQUIRE(test("1337 ", "%-20o", 01337) );
REQUIRE(test("37777776441 ", "%-20o", -01337) );
+ REQUIRE(test(" 2471", "%20o", 1337) );
+ REQUIRE(test("00000000000000002471", "%020o", 1337) );
REQUIRE(test("1337", "%u", 1337) );
REQUIRE(test("1337 ", "%-20u", 1337) );
@@ -92,11 +164,40 @@ TEST_CASE("vsnprintf d/i/o/u/x")
REQUIRE(test("1234ABCD ", "%-20X", 0x1234abcd) );
REQUIRE(test("edcb5433 ", "%-20x", -0x1234abcd) );
REQUIRE(test("EDCB5433 ", "%-20X", -0x1234abcd) );
+ REQUIRE(test(" 1234abcd", "% 20x", 0x1234abcd) );
+ REQUIRE(test(" 1234ABCD", "% 20X", 0x1234abcd) );
+ REQUIRE(test(" edcb5433", "% 20x", -0x1234abcd) );
+ REQUIRE(test(" EDCB5433", "% 20X", -0x1234abcd) );
REQUIRE(test("0000000000001234abcd", "%020x", 0x1234abcd) );
REQUIRE(test("0000000000001234ABCD", "%020X", 0x1234abcd) );
REQUIRE(test("000000000000edcb5433", "%020x", -0x1234abcd) );
REQUIRE(test("000000000000EDCB5433", "%020X", -0x1234abcd) );
+ REQUIRE(test("0xf", "0x%01x", -1) );
+ REQUIRE(test("0xff", "0x%02x", -1) );
+ REQUIRE(test("0xfff", "0x%03x", -1) );
+ REQUIRE(test("0xffff", "0x%04x", -1) );
+ REQUIRE(test("0xfffff", "0x%05x", -1) );
+ REQUIRE(test("0xffffff", "0x%06x", -1) );
+ REQUIRE(test("0xfffffff", "0x%07x", -1) );
+ REQUIRE(test("0xffffffff", "0x%08x", -1) );
+
+ REQUIRE(test(" -1", "% 4i", -1) );
+ REQUIRE(test(" -1", "% 4i", -1) );
+ REQUIRE(test(" 0", "% 4i", 0) );
+ REQUIRE(test(" 1", "% 4i", 1) );
+ REQUIRE(test(" 1", "% 4o", 1) );
+ REQUIRE(test(" +1", "%+4i", 1) );
+ REQUIRE(test(" +1", "%+4o", 1) );
+ REQUIRE(test(" +0", "%+4i", 0) );
+ REQUIRE(test(" -1", "%+4i", -1) );
+ REQUIRE(test("0001", "%04i", 1) );
+ REQUIRE(test("0001", "%04o", 1) );
+ REQUIRE(test("0000", "%04i", 0) );
+ REQUIRE(test("0000", "%04o", 0) );
+ REQUIRE(test("-001", "%04i", -1) );
+ REQUIRE(test("+001", "%+04i", 1) );
+
if (BX_ENABLED(BX_ARCH_32BIT) )
{
REQUIRE(test("2147483647", "%jd", INTMAX_MAX) );
@@ -136,6 +237,29 @@ TEST_CASE("vsnprintf s")
REQUIRE(test("(null)", "%s", NULL) );
}
+TEST_CASE("vsnprintf t")
+{
+ size_t size = size_t(-1);
+
+ REQUIRE(test("-1", "%td", size) );
+
+ REQUIRE(test("3221225472", "%td", size_t(3221225472) ) );
+}
+
+TEST_CASE("vsnprintf n")
+{
+ char temp[64];
+
+ int32_t p0, p1, p2;
+ bx::snprintf(temp, sizeof(temp), "%n", &p0);
+ REQUIRE(0 == p0);
+
+ bx::snprintf(temp, sizeof(temp), "01%n23%n45%n", &p0, &p1, &p2);
+ REQUIRE(2 == p0);
+ REQUIRE(4 == p1);
+ REQUIRE(6 == p2);
+}
+
TEST_CASE("vsnprintf g")
{
REQUIRE(test(" 0.01", "%7.2g", .01) );
@@ -152,6 +276,12 @@ TEST_CASE("vsnprintf")
REQUIRE(test("hello ", "%-20s", "hello") );
REQUIRE(test("hello, world!", "%s, %s!", "hello", "world") );
+ REQUIRE(test("h", "%1s", "hello") );
+ REQUIRE(test("he", "%2s", "hello") );
+ REQUIRE(test("hel", "%3s", "hello") );
+ REQUIRE(test("hell", "%4s", "hello") );
+ REQUIRE(test("hello", "%5s", "hello") );
+
bx::StringView str("0hello1world2");
bx::StringView hello(str, 1, 5);
bx::StringView world(str, 7, 5);
@@ -159,6 +289,11 @@ TEST_CASE("vsnprintf")
, hello.getLength(), hello.getPtr()
, world.getLength(), world.getPtr()
) );
+
+ REQUIRE(test("hello, world!", "%S, %S!"
+ , &hello
+ , &world
+ ) );
}
TEST_CASE("vsnprintf write")
@@ -175,3 +310,15 @@ TEST_CASE("vsnprintf write")
bx::StringView str(tmp, len);
REQUIRE(0 == bx::strCmp(str, "1389") );
}
+
+TEST_CASE("snprintf invalid")
+{
+ char temp[64];
+ REQUIRE(0 == bx::snprintf(temp, sizeof(temp), "%", 1) );
+ REQUIRE(0 == bx::snprintf(temp, sizeof(temp), "%-", 1) );
+ REQUIRE(0 == bx::snprintf(temp, sizeof(temp), "%-0", 1) );
+ REQUIRE(0 == bx::snprintf(temp, sizeof(temp), "%-03", 1) );
+ REQUIRE(0 == bx::snprintf(temp, sizeof(temp), "%-03.", 1) );
+ REQUIRE(0 == bx::snprintf(temp, sizeof(temp), "%-03.0", 1) );
+ REQUIRE(0 == bx::snprintf(temp, sizeof(temp), "%-03.0t", 1) );
+}
diff --git a/3rdparty/bx/tools/bin/darwin/bin2c b/3rdparty/bx/tools/bin/darwin/bin2c
index cb1acca8021..7aa45d00061 100644..100755
--- a/3rdparty/bx/tools/bin/darwin/bin2c
+++ b/3rdparty/bx/tools/bin/darwin/bin2c
Binary files differ
diff --git a/3rdparty/bx/tools/bin/darwin/genie b/3rdparty/bx/tools/bin/darwin/genie
index fd3624037ce..db20768b961 100755
--- a/3rdparty/bx/tools/bin/darwin/genie
+++ b/3rdparty/bx/tools/bin/darwin/genie
Binary files differ
diff --git a/3rdparty/bx/tools/bin/darwin/lemon b/3rdparty/bx/tools/bin/darwin/lemon
index f8cfcebbc1b..c00a276b405 100644..100755
--- a/3rdparty/bx/tools/bin/darwin/lemon
+++ b/3rdparty/bx/tools/bin/darwin/lemon
Binary files differ
diff --git a/3rdparty/bx/tools/bin/darwin/lempar.c b/3rdparty/bx/tools/bin/darwin/lempar.c
index da81ddd4bc0..5e2024fffb0 100644
--- a/3rdparty/bx/tools/bin/darwin/lempar.c
+++ b/3rdparty/bx/tools/bin/darwin/lempar.c
@@ -13,7 +13,7 @@
**
** The "lemon" program processes an LALR(1) input grammar file, then uses
** this template to construct a parser. The "lemon" program inserts text
-** at each "%%" line. Also, any "P-a-r-s-e" identifer prefix (without the
+** at each "%%" line. Also, any "P-a-r-s-e" identifier prefix (without the
** interstitial "-" characters) contained in this template is changed into
** the value of the %name directive from the grammar. Otherwise, the content
** of this template is copied straight through into the generate parser
diff --git a/3rdparty/bx/tools/bin/darwin/ninja b/3rdparty/bx/tools/bin/darwin/ninja
index d26afc28e73..d26afc28e73 100644..100755
--- a/3rdparty/bx/tools/bin/darwin/ninja
+++ b/3rdparty/bx/tools/bin/darwin/ninja
Binary files differ
diff --git a/3rdparty/bx/tools/bin/linux/bin2c b/3rdparty/bx/tools/bin/linux/bin2c
index ca595d9f82a..a79a17d9182 100644..100755
--- a/3rdparty/bx/tools/bin/linux/bin2c
+++ b/3rdparty/bx/tools/bin/linux/bin2c
Binary files differ
diff --git a/3rdparty/bx/tools/bin/linux/genie b/3rdparty/bx/tools/bin/linux/genie
index 6c662eada50..f7bc6a12336 100755
--- a/3rdparty/bx/tools/bin/linux/genie
+++ b/3rdparty/bx/tools/bin/linux/genie
Binary files differ
diff --git a/3rdparty/bx/tools/bin/linux/lemon b/3rdparty/bx/tools/bin/linux/lemon
index 64d24ce47ab..6c5e3bdcdff 100644..100755
--- a/3rdparty/bx/tools/bin/linux/lemon
+++ b/3rdparty/bx/tools/bin/linux/lemon
Binary files differ
diff --git a/3rdparty/bx/tools/bin/linux/lempar.c b/3rdparty/bx/tools/bin/linux/lempar.c
index da81ddd4bc0..5e2024fffb0 100644
--- a/3rdparty/bx/tools/bin/linux/lempar.c
+++ b/3rdparty/bx/tools/bin/linux/lempar.c
@@ -13,7 +13,7 @@
**
** The "lemon" program processes an LALR(1) input grammar file, then uses
** this template to construct a parser. The "lemon" program inserts text
-** at each "%%" line. Also, any "P-a-r-s-e" identifer prefix (without the
+** at each "%%" line. Also, any "P-a-r-s-e" identifier prefix (without the
** interstitial "-" characters) contained in this template is changed into
** the value of the %name directive from the grammar. Otherwise, the content
** of this template is copied straight through into the generate parser
diff --git a/3rdparty/bx/tools/bin/linux/ninja b/3rdparty/bx/tools/bin/linux/ninja
index 189832fdb4b..189832fdb4b 100644..100755
--- a/3rdparty/bx/tools/bin/linux/ninja
+++ b/3rdparty/bx/tools/bin/linux/ninja
Binary files differ
diff --git a/3rdparty/bx/tools/bin/windows/bin2c.exe b/3rdparty/bx/tools/bin/windows/bin2c.exe
index 2c01cdd8065..d93eff18e60 100644..100755
--- a/3rdparty/bx/tools/bin/windows/bin2c.exe
+++ b/3rdparty/bx/tools/bin/windows/bin2c.exe
Binary files differ
diff --git a/3rdparty/bx/tools/bin/windows/genie.exe b/3rdparty/bx/tools/bin/windows/genie.exe
index 4b0426c3ddb..f6304b1f4cf 100644
--- a/3rdparty/bx/tools/bin/windows/genie.exe
+++ b/3rdparty/bx/tools/bin/windows/genie.exe
Binary files differ
diff --git a/3rdparty/bx/tools/bin/windows/lemon.exe b/3rdparty/bx/tools/bin/windows/lemon.exe
index 5de0c8d6fda..ea46fecf996 100644
--- a/3rdparty/bx/tools/bin/windows/lemon.exe
+++ b/3rdparty/bx/tools/bin/windows/lemon.exe
Binary files differ
diff --git a/3rdparty/bx/tools/bin/windows/lempar.c b/3rdparty/bx/tools/bin/windows/lempar.c
index da81ddd4bc0..5e2024fffb0 100644
--- a/3rdparty/bx/tools/bin/windows/lempar.c
+++ b/3rdparty/bx/tools/bin/windows/lempar.c
@@ -13,7 +13,7 @@
**
** The "lemon" program processes an LALR(1) input grammar file, then uses
** this template to construct a parser. The "lemon" program inserts text
-** at each "%%" line. Also, any "P-a-r-s-e" identifer prefix (without the
+** at each "%%" line. Also, any "P-a-r-s-e" identifier prefix (without the
** interstitial "-" characters) contained in this template is changed into
** the value of the %name directive from the grammar. Otherwise, the content
** of this template is copied straight through into the generate parser
diff --git a/3rdparty/bx/tools/bin/windows/ninja.exe b/3rdparty/bx/tools/bin/windows/ninja.exe
index 1b30c1eb432..1b30c1eb432 100644..100755
--- a/3rdparty/bx/tools/bin/windows/ninja.exe
+++ b/3rdparty/bx/tools/bin/windows/ninja.exe
Binary files differ
diff --git a/3rdparty/bx/tools/bin2c/bin2c.cpp b/3rdparty/bx/tools/bin2c/bin2c.cpp
index 2c7f48d1de0..8d152ff6b80 100644
--- a/3rdparty/bx/tools/bin2c/bin2c.cpp
+++ b/3rdparty/bx/tools/bin2c/bin2c.cpp
@@ -1,6 +1,6 @@
/*
- * Copyright 2011-2018 Branimir Karadzic. All rights reserved.
- * License: https://github.com/bkaradzic/bx#license-bsd-2-clause
+ * Copyright 2011-2022 Branimir Karadzic. All rights reserved.
+ * License: https://github.com/bkaradzic/bx/blob/master/LICENSE
*/
#include <bx/allocator.h>
@@ -8,6 +8,8 @@
#include <bx/file.h>
#include <bx/string.h>
+#include <bx/debug.h>
+
class Bin2cWriter : public bx::WriterI
{
public:
@@ -15,6 +17,7 @@ public:
: m_mb(_allocator)
, m_mw(&m_mb)
, m_name(_name)
+ , m_outputAsCStr(false)
{
}
@@ -24,23 +27,102 @@ public:
virtual int32_t write(const void* _data, int32_t _size, bx::Error* _err) override
{
+ bool asCStr = true;
+
+ const char* data = (const char*)_data;
+ for (int32_t ii = 0; ii < _size && asCStr; ++ii)
+ {
+ char ch = data[ii];
+
+ asCStr &= false
+ | bx::isPrint(ch)
+ | bx::isSpace(ch)
+ ;
+ }
+
+ m_outputAsCStr = asCStr;
+
return bx::write(&m_mw, _data, _size, _err);
}
- void output(bx::WriterI* m_writer)
+ void output(bx::WriterI* _writer)
+ {
+ if (m_outputAsCStr)
+ {
+ outputString(_writer);
+ }
+ else
+ {
+ outputHex(_writer);
+ }
+ }
+
+ void outputString(bx::WriterI* _writer)
+ {
+ const uint8_t* data = (const uint8_t*)m_mb.more(0);
+ uint32_t size = uint32_t(bx::seek(&m_mw) );
+
+ bx::Error err;
+
+ bx::write(
+ _writer
+ , &err
+ , "static const char* %.*s = /* Generated with bin2c. */\n\t\""
+ , m_name.getLength()
+ , m_name.getPtr()
+ );
+
+ if (NULL != data)
+ {
+ bool escaped = false;
+
+ for (uint32_t ii = 0; ii < size; ++ii)
+ {
+ const char ch = char(data[ii]);
+
+ if (!escaped)
+ {
+ switch (ch)
+ {
+ case '\"': bx::write(_writer, "\\\"", &err); break;
+ case '\n': bx::write(_writer, "\\n\"\n\t\"", &err); break;
+ case '\r': bx::write(_writer, "\\r", &err); break;
+ case '\\': escaped = true; BX_FALLTHROUGH;
+ default: bx::write(_writer, ch, &err); break;
+ }
+ }
+ else
+ {
+ switch (ch)
+ {
+ case '\n': bx::write(_writer, "\\\"\n\t\"", &err); break;
+ case '\r': BX_FALLTHROUGH;
+ case '\t': bx::write(_writer, "\\", &err); BX_FALLTHROUGH;
+ default : bx::write(_writer, ch, &err); break;
+ }
+
+ escaped = false;
+ }
+ }
+ }
+
+ bx::write(_writer, &err, "\"\n\t;\n");
+ }
+
+ void outputHex(bx::WriterI* _writer)
{
#define HEX_DUMP_WIDTH 16
#define HEX_DUMP_SPACE_WIDTH 96
#define HEX_DUMP_FORMAT "%-" BX_STRINGIZE(HEX_DUMP_SPACE_WIDTH) "." BX_STRINGIZE(HEX_DUMP_SPACE_WIDTH) "s"
- const char* data = (const char*)m_mb.more(0);
+ const uint8_t* data = (const uint8_t*)m_mb.more(0);
uint32_t size = uint32_t(bx::seek(&m_mw) );
bx::Error err;
bx::write(
- m_writer
+ _writer
, &err
- , "static const uint8_t %.*s[%d] =\n{\n"
+ , "static const uint8_t %.*s[%d] = /* Generated with bin2c. */\n{\n"
, m_name.getLength()
, m_name.getPtr()
, size
@@ -63,7 +145,7 @@ public:
if (HEX_DUMP_WIDTH == asciiPos)
{
ascii[asciiPos] = '\0';
- bx::write(m_writer, &err, "\t" HEX_DUMP_FORMAT "// %s\n", hex, ascii);
+ bx::write(_writer, &err, "\t" HEX_DUMP_FORMAT "// %s\n", hex, ascii);
data += asciiPos;
hexPos = 0;
asciiPos = 0;
@@ -73,11 +155,11 @@ public:
if (0 != asciiPos)
{
ascii[asciiPos] = '\0';
- bx::write(m_writer, &err, "\t" HEX_DUMP_FORMAT "// %s\n", hex, ascii);
+ bx::write(_writer, &err, "\t" HEX_DUMP_FORMAT "// %s\n", hex, ascii);
}
}
- bx::write(m_writer, &err, "};\n");
+ bx::write(_writer, &err, "};\n");
#undef HEX_DUMP_WIDTH
#undef HEX_DUMP_SPACE_WIDTH
#undef HEX_DUMP_FORMAT
@@ -86,8 +168,22 @@ public:
bx::MemoryBlock m_mb;
bx::MemoryWriter m_mw;
bx::StringView m_name;
+ bool m_outputAsCStr;
};
+void error(const char* _format, ...)
+{
+ bx::WriterI* stdOut = bx::getStdOut();
+ bx::Error err;
+
+ va_list argList;
+ va_start(argList, _format);
+ bx::write(stdOut, &err, "Error:\n");
+ bx::write(stdOut, _format, argList, &err);
+ bx::write(stdOut, &err, "\n\n");
+ va_end(argList);
+}
+
void help(const char* _error = NULL)
{
bx::WriterI* stdOut = bx::getStdOut();
@@ -95,13 +191,13 @@ void help(const char* _error = NULL)
if (NULL != _error)
{
- bx::write(stdOut, &err, "Error:\n%s\n\n", _error);
+ error(_error);
}
bx::write(stdOut, &err
, "bin2c, binary to C\n"
- "Copyright 2011-2018 Branimir Karadzic. All rights reserved.\n"
- "License: https://github.com/bkaradzic/bx#license-bsd-2-clause\n\n"
+ "Copyright 2011-2022 Branimir Karadzic. All rights reserved.\n"
+ "License: https://github.com/bkaradzic/bx/blob/master/LICENSE\n\n"
);
bx::write(stdOut, &err
@@ -156,21 +252,31 @@ int main(int _argc, const char* _argv[])
bx::DefaultAllocator allocator;
data = BX_ALLOC(&allocator, size);
- bx::read(&fr, data, size);
+ bx::read(&fr, data, size, bx::ErrorAssert{});
bx::close(&fr);
bx::FileWriter fw;
if (bx::open(&fw, outFilePath) )
{
Bin2cWriter writer(&allocator, name);
- bx::write(&writer, data, size);
+ bx::write(&writer, data, size, bx::ErrorAssert{});
writer.output(&fw);
bx::close(&fw);
}
+ else
+ {
+ bx::StringView path = outFilePath;
+ error("Failed to open output file '%.*s'.\n", path.getLength(), path.getPtr() );
+ }
BX_FREE(&allocator, data);
}
+ else
+ {
+ bx::StringView path = filePath;
+ error("Failed to open input file '%.*s'.\n", path.getLength(), path.getPtr() );
+ }
return 0;
}
diff --git a/3rdparty/bx/tools/lemon/lemon.c b/3rdparty/bx/tools/lemon/lemon.c
index acc5450c993..acf2483ef23 100644
--- a/3rdparty/bx/tools/lemon/lemon.c
+++ b/3rdparty/bx/tools/lemon/lemon.c
@@ -980,7 +980,7 @@ PRIVATE void buildshifts(struct lemon *lemp, struct state *stp)
struct symbol *bsp; /* Symbol following the dot in configuration "bcfp" */
struct state *newstp; /* A pointer to a successor state */
- /* Each configuration becomes complete after it contibutes to a successor
+ /* Each configuration becomes complete after it contributes to a successor
** state. Initially, all configurations are incomplete */
for(cfp=stp->cfp; cfp; cfp=cfp->next) cfp->status = INCOMPLETE;
@@ -1819,7 +1819,7 @@ static char *merge(
**
** Return Value:
** A pointer to the head of a sorted list containing the elements
-** orginally in list.
+** originally in list.
**
** Side effects:
** The "next" pointers for elements in list are changed.
@@ -3266,7 +3266,7 @@ void ReportOutput(struct lemon *lemp)
}
/* Search for the file "name" which is in the same directory as
-** the exacutable */
+** the executable */
PRIVATE char *pathsearch(char *argv0, char *name, int modemask)
{
const char *pathlist;
diff --git a/3rdparty/bx/tools/lemon/lempar.c b/3rdparty/bx/tools/lemon/lempar.c
index da81ddd4bc0..5e2024fffb0 100644
--- a/3rdparty/bx/tools/lemon/lempar.c
+++ b/3rdparty/bx/tools/lemon/lempar.c
@@ -13,7 +13,7 @@
**
** The "lemon" program processes an LALR(1) input grammar file, then uses
** this template to construct a parser. The "lemon" program inserts text
-** at each "%%" line. Also, any "P-a-r-s-e" identifer prefix (without the
+** at each "%%" line. Also, any "P-a-r-s-e" identifier prefix (without the
** interstitial "-" characters) contained in this template is changed into
** the value of the %name directive from the grammar. Otherwise, the content
** of this template is copied straight through into the generate parser