kfr

Fast, modern C++ DSP framework, FFT, Sample Rate Conversion, FIR/IIR/Biquad Filters (SSE, AVX, AVX-512, ARM NEON)
Log | Files | Refs | README

commit 2e6c26a92e2b3d5210c7d67fc2650f18efd29634
parent 9df24c55285dd6eb23491cb7e06b35aefc705be4
Author: d.levin256@gmail.com <d.levin256@gmail.com>
Date:   Fri, 31 Mar 2017 23:22:16 +0300

Testo: add ASSERT, refactor comparisons

Diffstat:
Ainclude/kfr/testo/assert.hpp | 70++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ainclude/kfr/testo/comparison.hpp | 225+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Minclude/kfr/testo/testo.hpp | 229+++----------------------------------------------------------------------------
Msources.cmake | 2++
4 files changed, 303 insertions(+), 223 deletions(-)

diff --git a/include/kfr/testo/assert.hpp b/include/kfr/testo/assert.hpp @@ -0,0 +1,70 @@ +#pragma once + +#include "comparison.hpp" + +#if defined(CMT_COMPILER_MSVC) +#include <intrin.h> +#define TESTO_BREAKPOINT __debugbreak() +#else +#if defined(__i386__) || defined(__x86_64__) +#define TESTO_BREAKPOINT __asm__ __volatile__("int $0x03") +#else +#define TESTO_BREAKPOINT __builtin_trap() +#endif +#endif + +namespace testo +{ + +inline void assertion_failed(const std::string& string, const char* file, int line) +{ + errorln("Assertion failed at ", file, ":", line); + errorln(string); + errorln(); +} + +template <typename Op, typename L, typename R> +bool check_assertion(const comparison<Op, L, R>& comparison, const char* expr, const char* file, int line) +{ + bool result = comparison(); + if (!result) + { + assertion_failed( + as_string(padleft(22, expr), " | ", comparison.left, " ", Op::op(), " ", comparison.right), file, + line); + } + return result; +} + +template <typename L> +bool check_assertion(const half_comparison<L>& comparison, const char* expr, const char* file, int line) +{ + bool result = static_cast<bool>(comparison.left); + if (!result) + { + assertion_failed(as_string(padleft(22, expr), " | ", comparison.left), file, line); + } + return false; +} + +#if defined(TESTO_ASSERTION_ON) || !(defined(NDEBUG) || defined(TESTO_ASSERTION_OFF)) + +#define TESTO_ASSERT(...) \ + do \ + { \ + if (!::testo::check_assertion(::testo::make_comparison() <= __VA_ARGS__, #__VA_ARGS__, __FILE__, \ + __LINE__)) \ + TESTO_BREAKPOINT; \ + } while (0) + +#else +#define TESTO_ASSERT(...) \ + do \ + { \ + } while (false && (__VA_ARGS__)) +#endif + +#ifndef TESTO_NO_SHORT_MACROS +#define ASSERT TESTO_ASSERT +#endif +} diff --git a/include/kfr/testo/comparison.hpp b/include/kfr/testo/comparison.hpp @@ -0,0 +1,225 @@ +#pragma once + +#include "../cometa/tuple.hpp" + +#include "../cometa.hpp" +#include "../cometa/range.hpp" +#include "../cometa/string.hpp" +#include <cmath> + +CMT_PRAGMA_GNU(GCC diagnostic push) +CMT_PRAGMA_GNU(GCC diagnostic ignored "-Wexit-time-destructors") +CMT_PRAGMA_GNU(GCC diagnostic ignored "-Wpadded") +CMT_PRAGMA_GNU(GCC diagnostic ignored "-Wshadow") + +namespace testo +{ + +using namespace cometa; + +template <typename Fn, typename L, typename R> +struct comparison +{ + L left; + R right; + Fn cmp; + + comparison(L&& left, R&& right) : left(std::forward<L>(left)), right(std::forward<R>(right)) {} + + bool operator()() const { return cmp(left, right); } +}; + +template <typename Left, typename Right> +struct static_assert_type_eq +{ + static_assert(std::is_same<Left, Right>::value, "std::is_same<Left, Right>::value"); +}; + +template <typename T, T left, T right> +struct static_assert_eq +{ + static_assert(left == right, "left == right"); +}; + +template <typename L, typename R, typename = void> +struct equality_comparer +{ + bool operator()(const L& l, const R& r) const { return l == r; } +}; + +CMT_PRAGMA_GNU(GCC diagnostic push) +CMT_PRAGMA_GNU(GCC diagnostic ignored "-Wfloat-equal") + +template <typename T> +inline T& epsilon() +{ + static T value = std::numeric_limits<T>::epsilon(); + return value; +} + +template <> +struct equality_comparer<float, float> +{ + bool operator()(const float& l, const float& r) const { return !(std::abs(l - r) > epsilon<float>()); } +}; +template <> +struct equality_comparer<double, double> +{ + bool operator()(const double& l, const double& r) const { return !(std::abs(l - r) > epsilon<double>()); } +}; +template <> +struct equality_comparer<long double, long double> +{ + bool operator()(const long double& l, const long double& r) const + { + return !(std::abs(l - r) > epsilon<long double>()); + } +}; + +CMT_PRAGMA_GNU(GCC diagnostic pop) + +template <typename L, typename R> +struct equality_comparer<L, R, void_t<enable_if<!compound_type_traits<L>::is_scalar>>> +{ + using Tsubtype = subtype<L>; + constexpr static static_assert_type_eq<subtype<L>, subtype<R>> assert{}; + + bool operator()(const L& l, const R& r) const + { + if (compound_type_traits<L>::width != compound_type_traits<R>::width) + return false; + + compound_type_traits<L> itl; + compound_type_traits<R> itr; + for (size_t i = 0; i < compound_type_traits<L>::width; i++) + { + equality_comparer<Tsubtype, Tsubtype> cmp; + if (!cmp(itl.at(l, i), itr.at(r, i))) + return false; + } + return true; + } +}; + +struct cmp_eq +{ + static const char* op() { return "=="; } + + template <typename L, typename R> + bool operator()(L&& left, R&& right) const + { + equality_comparer<decay<L>, decay<R>> eq; + return eq(left, right); + } +}; + +struct cmp_ne +{ + static const char* op() { return "!="; } + + template <typename L, typename R> + bool operator()(L&& left, R&& right) const + { + return !cmp_eq()(left, right); + } +}; + +struct cmp_lt +{ + static const char* op() { return "<"; } + + template <typename L, typename R> + bool operator()(L&& left, R&& right) const + { + return left < right; + } +}; + +struct cmp_gt +{ + static const char* op() { return ">"; } + + template <typename L, typename R> + bool operator()(L&& left, R&& right) const + { + return left > right; + } +}; + +struct cmp_le +{ + static const char* op() { return "<="; } + + template <typename L, typename R> + bool operator()(L&& left, R&& right) const + { + return left <= right; + } +}; + +struct cmp_ge +{ + static const char* op() { return ">="; } + + template <typename L, typename R> + bool operator()(L&& left, R&& right) const + { + return left >= right; + } +}; + +template <typename L> +struct half_comparison +{ + half_comparison(L&& left) : left(std::forward<L>(left)) {} + + template <typename R> + comparison<cmp_eq, L, R> operator==(R&& right) + { + return comparison<cmp_eq, L, R>(std::forward<L>(left), std::forward<R>(right)); + } + + template <typename R> + comparison<cmp_ne, L, R> operator!=(R&& right) + { + return comparison<cmp_ne, L, R>(std::forward<L>(left), std::forward<R>(right)); + } + + template <typename R> + comparison<cmp_lt, L, R> operator<(R&& right) + { + return comparison<cmp_lt, L, R>(std::forward<L>(left), std::forward<R>(right)); + } + + template <typename R> + comparison<cmp_gt, L, R> operator>(R&& right) + { + return comparison<cmp_gt, L, R>(std::forward<L>(left), std::forward<R>(right)); + } + + template <typename R> + comparison<cmp_le, L, R> operator<=(R&& right) + { + return comparison<cmp_le, L, R>(std::forward<L>(left), std::forward<R>(right)); + } + + template <typename R> + comparison<cmp_ge, L, R> operator>=(R&& right) + { + return comparison<cmp_ge, L, R>(std::forward<L>(left), std::forward<R>(right)); + } + + L left; +}; + +struct make_comparison +{ + template <typename L> + half_comparison<L> operator<=(L&& left) + { + return half_comparison<L>(std::forward<L>(left)); + } +}; +} + +CMT_PRAGMA_GNU(GCC diagnostic pop) diff --git a/include/kfr/testo/testo.hpp b/include/kfr/testo/testo.hpp @@ -1,10 +1,6 @@ #pragma once -#include "../cometa/tuple.hpp" - -#include "../cometa.hpp" -#include "../cometa/range.hpp" -#include "../cometa/string.hpp" +#include "comparison.hpp" #include <algorithm> #include <ctime> @@ -20,19 +16,10 @@ #include <chrono> #include <cmath> -#if !defined CLANG_DIAGNOSTIC_PRAGMA -#if defined __clang__ -#define TESTO_STRING(str) #str -#define CLANG_DIAGNOSTIC_PRAGMA(pragma) _Pragma(TESTO_STRING(clang diagnostic pragma)) -#else -#define CLANG_DIAGNOSTIC_PRAGMA(pragma) -#endif -#endif - -CLANG_DIAGNOSTIC_PRAGMA(push) -CLANG_DIAGNOSTIC_PRAGMA(ignored "-Wexit-time-destructors") -CLANG_DIAGNOSTIC_PRAGMA(ignored "-Wpadded") -CLANG_DIAGNOSTIC_PRAGMA(ignored "-Wshadow") +CMT_PRAGMA_GNU(GCC diagnostic push) +CMT_PRAGMA_GNU(GCC diagnostic ignored "-Wexit-time-destructors") +CMT_PRAGMA_GNU(GCC diagnostic ignored "-Wpadded") +CMT_PRAGMA_GNU(GCC diagnostic ignored "-Wshadow") namespace testo { @@ -90,210 +77,6 @@ inline double ulp_distance(long double reference, T test) using namespace console_colors; -template <typename Fn, typename L, typename R> -struct comparison -{ - L left; - R right; - Fn cmp; - - comparison(L&& left, R&& right) : left(std::forward<L>(left)), right(std::forward<R>(right)) {} - - bool operator()() const { return cmp(left, right); } -}; - -template <typename Left, typename Right> -struct static_assert_type_eq -{ - static_assert(std::is_same<Left, Right>::value, "std::is_same<Left, Right>::value"); -}; - -template <typename T, T left, T right> -struct static_assert_eq -{ - static_assert(left == right, "left == right"); -}; - -template <typename L, typename R, typename = void> -struct equality_comparer -{ - bool operator()(const L& l, const R& r) const { return l == r; } -}; - -CMT_PRAGMA_GNU(GCC diagnostic push) -CMT_PRAGMA_GNU(GCC diagnostic ignored "-Wfloat-equal") - -template <typename T> -inline T& epsilon() -{ - static T value = std::numeric_limits<T>::epsilon(); - return value; -} - -template <> -struct equality_comparer<float, float> -{ - bool operator()(const float& l, const float& r) const { return !(std::abs(l - r) > epsilon<float>()); } -}; -template <> -struct equality_comparer<double, double> -{ - bool operator()(const double& l, const double& r) const { return !(std::abs(l - r) > epsilon<double>()); } -}; -template <> -struct equality_comparer<long double, long double> -{ - bool operator()(const long double& l, const long double& r) const - { - return !(std::abs(l - r) > epsilon<long double>()); - } -}; - -CMT_PRAGMA_GNU(GCC diagnostic pop) - -template <typename L, typename R> -struct equality_comparer<L, R, void_t<enable_if<!compound_type_traits<L>::is_scalar>>> -{ - using Tsubtype = subtype<L>; - constexpr static static_assert_type_eq<subtype<L>, subtype<R>> assert{}; - - bool operator()(const L& l, const R& r) const - { - if (compound_type_traits<L>::width != compound_type_traits<R>::width) - return false; - - compound_type_traits<L> itl; - compound_type_traits<R> itr; - for (size_t i = 0; i < compound_type_traits<L>::width; i++) - { - equality_comparer<Tsubtype, Tsubtype> cmp; - if (!cmp(itl.at(l, i), itr.at(r, i))) - return false; - } - return true; - } -}; - -struct cmp_eq -{ - static const char* op() { return "=="; } - - template <typename L, typename R> - bool operator()(L&& left, R&& right) const - { - equality_comparer<decay<L>, decay<R>> eq; - return eq(left, right); - } -}; - -struct cmp_ne -{ - static const char* op() { return "!="; } - - template <typename L, typename R> - bool operator()(L&& left, R&& right) const - { - return !cmp_eq()(left, right); - } -}; - -struct cmp_lt -{ - static const char* op() { return "<"; } - - template <typename L, typename R> - bool operator()(L&& left, R&& right) const - { - return left < right; - } -}; - -struct cmp_gt -{ - static const char* op() { return ">"; } - - template <typename L, typename R> - bool operator()(L&& left, R&& right) const - { - return left > right; - } -}; - -struct cmp_le -{ - static const char* op() { return "<="; } - - template <typename L, typename R> - bool operator()(L&& left, R&& right) const - { - return left <= right; - } -}; - -struct cmp_ge -{ - static const char* op() { return ">="; } - - template <typename L, typename R> - bool operator()(L&& left, R&& right) const - { - return left >= right; - } -}; - -template <typename L> -struct half_comparison -{ - half_comparison(L&& left) : left(std::forward<L>(left)) {} - - template <typename R> - comparison<cmp_eq, L, R> operator==(R&& right) - { - return comparison<cmp_eq, L, R>(std::forward<L>(left), std::forward<R>(right)); - } - - template <typename R> - comparison<cmp_ne, L, R> operator!=(R&& right) - { - return comparison<cmp_ne, L, R>(std::forward<L>(left), std::forward<R>(right)); - } - - template <typename R> - comparison<cmp_lt, L, R> operator<(R&& right) - { - return comparison<cmp_lt, L, R>(std::forward<L>(left), std::forward<R>(right)); - } - - template <typename R> - comparison<cmp_gt, L, R> operator>(R&& right) - { - return comparison<cmp_gt, L, R>(std::forward<L>(left), std::forward<R>(right)); - } - - template <typename R> - comparison<cmp_le, L, R> operator<=(R&& right) - { - return comparison<cmp_le, L, R>(std::forward<L>(left), std::forward<R>(right)); - } - - template <typename R> - comparison<cmp_ge, L, R> operator>=(R&& right) - { - return comparison<cmp_ge, L, R>(std::forward<L>(left), std::forward<R>(right)); - } - - L left; -}; - -struct make_comparison -{ - template <typename L> - half_comparison<L> operator<=(L&& left) - { - return half_comparison<L>(std::forward<L>(left)); - } -}; - inline std::vector<std::string> split(const std::string& text, char delimeter) { std::string r = text; @@ -562,4 +345,4 @@ void assert_is_same_decay() #endif } -CLANG_DIAGNOSTIC_PRAGMA(pop) +CMT_PRAGMA_GNU(GCC diagnostic pop) diff --git a/sources.cmake b/sources.cmake @@ -105,4 +105,6 @@ set( ${PROJECT_SOURCE_DIR}/include/kfr/io/python_plot.hpp ${PROJECT_SOURCE_DIR}/include/kfr/io/tostring.hpp ${PROJECT_SOURCE_DIR}/include/kfr/testo/testo.hpp + ${PROJECT_SOURCE_DIR}/include/kfr/testo/assert.hpp + ${PROJECT_SOURCE_DIR}/include/kfr/testo/comparison.hpp )