commit 2d457a951599ad878866b800a6a5ea099c793eef
parent 96671cc5421bda39f5e56646dff1aa2abb350dee
Author: d.levin256@gmail.com <d.levin256@gmail.com>
Date: Tue, 8 Nov 2016 13:31:16 +0300
Tests refactoring
Diffstat:
15 files changed, 835 insertions(+), 851 deletions(-)
diff --git a/include/kfr/base/select.hpp b/include/kfr/base/select.hpp
@@ -129,7 +129,8 @@ KFR_SINTRIN vec<T, N> select(const mask<T, N>& a, const vec<T, N>& b, const vec<
template <typename T, size_t N, KFR_ENABLE_IF(N >= platform<T>::vector_width), typename = void>
KFR_SINTRIN vec<T, N> select(const mask<T, N>& a, const vec<T, N>& b, const vec<T, N>& c)
{
- return concat(select(low(a.asvec()).asmask(), low(b), low(c)), select(high(a.asvec()).asmask(), high(b), high(c)));
+ return concat(select(low(a.asvec()).asmask(), low(b), low(c)),
+ select(high(a.asvec()).asmask(), high(b), high(c)));
}
#elif defined CMT_ARCH_NEON && defined KFR_NATIVE_INTRINSICS
@@ -139,8 +140,14 @@ KFR_SINTRIN f32neon select(const maskfor<f32neon>& m, const f32neon& x, const f3
return vbslq_f32(*m, *x, *y);
}
-KFR_SINTRIN i8neon select(const maskfor<i8neon>& m, const i8neon& x, const i8neon& y) { return vbslq_s8(*m, *x, *y); }
-KFR_SINTRIN u8neon select(const maskfor<u8neon>& m, const u8neon& x, const u8neon& y) { return vbslq_u8(*m, *x, *y); }
+KFR_SINTRIN i8neon select(const maskfor<i8neon>& m, const i8neon& x, const i8neon& y)
+{
+ return vbslq_s8(*m, *x, *y);
+}
+KFR_SINTRIN u8neon select(const maskfor<u8neon>& m, const u8neon& x, const u8neon& y)
+{
+ return vbslq_u8(*m, *x, *y);
+}
KFR_SINTRIN i16neon select(const maskfor<i16neon>& m, const i16neon& x, const i16neon& y)
{
return vbslq_s16(*m, *x, *y);
@@ -218,7 +225,8 @@ template <typename T1, size_t N, typename T2, typename T3, KFR_ENABLE_IF(is_nume
KFR_INTRIN vec<Tout, N> select(const mask<T1, N>& m, const T2& x, const T3& y)
{
static_assert(sizeof(T1) == sizeof(Tout), "select: incompatible types");
- return intrinsics::select(bitcast<Tout>(m.asvec()).asmask(), static_cast<vec<Tout, N>>(x), static_cast<vec<Tout, N>>(y));
+ return intrinsics::select(bitcast<Tout>(m.asvec()).asmask(), static_cast<vec<Tout, N>>(x),
+ static_cast<vec<Tout, N>>(y));
}
/**
diff --git a/include/kfr/base/types.hpp b/include/kfr/base/types.hpp
@@ -33,10 +33,17 @@
CMT_PRAGMA_GNU(GCC diagnostic push)
CMT_PRAGMA_GNU(GCC diagnostic ignored "-Wshadow")
+#ifdef KFR_TESTING
+#include "../testo/testo.hpp"
+#endif
+
#include "../cometa.hpp"
#define KFR_ENABLE_IF CMT_ENABLE_IF
+/**
+ * @brief Internal macro for functions
+ */
#define KFR_FN(FN) \
namespace fn \
{ \
@@ -50,6 +57,9 @@ CMT_PRAGMA_GNU(GCC diagnostic ignored "-Wshadow")
}; \
}
+/**
+ * @brief Internal macro for functions
+ */
#define KFR_I_FN(FN) \
namespace fn \
{ \
@@ -66,8 +76,10 @@ CMT_PRAGMA_GNU(GCC diagnostic ignored "-Wshadow")
namespace kfr
{
+// Include all from CoMeta library
using namespace cometa;
+/// @brief Short names for common types
using f32 = float;
using f64 = double;
using i8 = int8_t;
@@ -84,8 +96,10 @@ using fmax = double;
using f80 = long double;
#if defined(KFR_BASETYPE_F32) || defined(KFR_NO_NATIVE_F64)
+/// @brief Floating point type used by default
using fbase = f32;
#else
+/// @brief Floating point type used by default
using fbase = f64;
#endif
@@ -120,6 +134,7 @@ struct f16
u16 raw;
};
+/// @brief An enumeration representing data type
template <typename T1>
struct range
{
@@ -199,12 +214,22 @@ struct typebits
namespace fn
{
+///@copybrief cometa::pass_through
using pass_through = cometa::fn_pass_through;
-using noop = cometa::fn_noop;
-using get_first = cometa::fn_get_first;
-using get_second = cometa::fn_get_second;
-using get_third = cometa::fn_get_third;
+///@copybrief cometa::noop
+using noop = cometa::fn_noop;
+
+///@copybrief cometa::get_first
+using get_first = cometa::fn_get_first;
+
+///@copybrief cometa::get_second
+using get_second = cometa::fn_get_second;
+
+///@copybrief cometa::get_third
+using get_third = cometa::fn_get_third;
+
+///@copybrief cometa::returns
template <typename T>
using returns = cometa::fn_returns<T>;
}
@@ -226,25 +251,6 @@ using isubtype = itype<subtype<T>>;
template <typename T>
using usubtype = utype<subtype<T>>;
-template <typename T, typename R = T>
-using enable_if_vec = enable_if<(typebits<T>::width > 0), R>;
-template <typename T, typename R = T>
-using enable_if_not_vec = enable_if<(typebits<T>::width == 0), R>;
-
-template <typename T, typename R = T>
-using enable_if_i = enable_if<typeclass<T> == datatype::i, R>;
-template <typename T, typename R = T>
-using enable_if_u = enable_if<typeclass<T> == datatype::u, R>;
-template <typename T, typename R = T>
-using enable_if_f = enable_if<typeclass<T> == datatype::f, R>;
-
-template <typename T, typename R = T>
-using enable_if_not_i = enable_if<typeclass<T> != datatype::i, R>;
-template <typename T, typename R = T>
-using enable_if_not_u = enable_if<typeclass<T> != datatype::u, R>;
-template <typename T, typename R = T>
-using enable_if_not_f = enable_if<typeclass<T> != datatype::f, R>;
-
namespace internal
{
template <typename T>
@@ -298,11 +304,6 @@ CMT_INLINE void builtin_memcpy(void* dest, const void* src, size_t size) { ::mem
CMT_INLINE void builtin_memset(void* dest, int val, size_t size) { ::memset(dest, val, size); }
#endif
-template <typename T1>
-CMT_INLINE void zeroize(T1& value)
-{
- builtin_memset(static_cast<void*>(builtin_addressof(value)), 0, sizeof(T1));
-}
CMT_PRAGMA_GNU(GCC diagnostic push)
CMT_PRAGMA_GNU(GCC diagnostic ignored "-Wattributes")
@@ -328,6 +329,14 @@ __attribute__((__packed__, __may_alias__)) //
CMT_PRAGMA_GNU(GCC diagnostic pop)
}
+/// @brief Fills a value with zeros
+template <typename T1>
+CMT_INLINE void zeroize(T1& value)
+{
+ internal::builtin_memset(static_cast<void*>(builtin_addressof(value)), 0, sizeof(T1));
+}
+
+/// @brief Used to determine the initial value for reduce functions
template <typename T>
struct initialvalue
{
diff --git a/include/kfr/ext/console_colors.hpp b/include/kfr/ext/console_colors.hpp
@@ -0,0 +1,161 @@
+#pragma once
+#include <cstdint>
+#include <cstdio>
+
+//#define CONSOLE_COLORS_FORCE_ASCII
+
+#if defined _WIN32 && !defined PRINT_COLORED_FORCE_ASCII
+#define USE_WIN32_API
+#endif
+
+#if defined(USE_WIN32_API)
+
+namespace win32_lite
+{
+typedef void* HANDLE;
+typedef uint32_t DWORD;
+
+#define WIN32_LITE_STD_INPUT_HANDLE ((win32_lite::DWORD)-10)
+#define WIN32_LITE_STD_OUTPUT_HANDLE ((win32_lite::DWORD)-11)
+#define WIN32_LITE_STD_ERROR_HANDLE ((win32_lite::DWORD)-12)
+
+#define WIN32_LITE_DECLSPEC_IMPORT __declspec(dllimport)
+
+#define WIN32_LITE_WINAPI __stdcall
+
+typedef short SHORT;
+typedef unsigned short WORD;
+typedef int WINBOOL;
+
+extern "C" {
+WIN32_LITE_DECLSPEC_IMPORT HANDLE WIN32_LITE_WINAPI GetStdHandle(DWORD nStdHandle);
+WIN32_LITE_DECLSPEC_IMPORT WINBOOL WIN32_LITE_WINAPI SetConsoleTextAttribute(HANDLE hConsoleOutput,
+ WORD wAttributes);
+}
+}
+
+#endif
+
+namespace console_colors
+{
+
+enum text_color : uint32_t
+{
+ Black = 0x00,
+ DarkBlue = 0x01,
+ DarkGreen = 0x02,
+ DarkCyan = 0x03,
+ DarkRed = 0x04,
+ DarkMagenta = 0x05,
+ DarkYellow = 0x06,
+ LightGrey = 0x07,
+ Gray = 0x08,
+ Blue = 0x09,
+ Green = 0x0A,
+ Cyan = 0x0B,
+ Red = 0x0C,
+ Magenta = 0x0D,
+ Yellow = 0x0E,
+ White = 0x0F,
+ BgBlack = 0x00,
+ BgDarkBlue = 0x10,
+ BgDarkGreen = 0x20,
+ BgDarkCyan = 0x30,
+ BgDarkRed = 0x40,
+ BgDarkMagenta = 0x50,
+ BgDarkYellow = 0x60,
+ BgLightGrey = 0x70,
+ BgGray = 0x80,
+ BgBlue = 0x90,
+ BgGreen = 0xA0,
+ BgCyan = 0xB0,
+ BgRed = 0xC0,
+ BgMagenta = 0xD0,
+ BgYellow = 0xE0,
+ BgWhite = 0xF0,
+
+ Normal = BgBlack | LightGrey
+};
+
+enum console_buffer
+{
+ ConsoleStdOutput,
+ ConsoleStdError
+};
+
+struct console_color
+{
+public:
+ console_color(text_color c, console_buffer console = ConsoleStdOutput)
+ : m_old(get(console)), m_console(console)
+ {
+ set(c, m_console);
+ }
+
+ ~console_color() { set(m_old, m_console); }
+
+private:
+ text_color get(console_buffer console = ConsoleStdOutput) { return saved_color(); }
+
+ void set(text_color new_color, console_buffer console = ConsoleStdOutput)
+ {
+#ifdef USE_WIN32_API
+ win32_lite::SetConsoleTextAttribute(win32_lite::GetStdHandle(console == ConsoleStdOutput
+ ? WIN32_LITE_STD_OUTPUT_HANDLE
+ : WIN32_LITE_STD_ERROR_HANDLE),
+ static_cast<win32_lite::WORD>(new_color));
+#else
+ if (new_color != Normal)
+ {
+ uint8_t t = new_color & 0xF;
+ uint8_t b = (new_color & 0xF0) >> 4;
+ uint8_t tnum = 30 + ((t & 1) << 2 | (t & 2) | (t & 4) >> 2);
+ uint8_t bnum = 40 + ((b & 1) << 2 | (b & 2) | (b & 4) >> 2);
+ if (t & 8)
+ tnum += 60;
+ if (b & 8)
+ bnum += 60;
+ std::fprintf(console == ConsoleStdOutput ? stdout : stderr, "\x1B[%d;%dm", tnum, bnum);
+ }
+ else
+ {
+ std::fprintf(console == ConsoleStdOutput ? stdout : stderr, "\x1B[0m");
+ }
+#endif
+ saved_color() = new_color;
+ }
+
+ text_color m_old;
+ console_buffer m_console;
+ static text_color& saved_color()
+ {
+ static text_color color = Normal;
+ return color;
+ }
+};
+
+template <text_color color, console_buffer console = ConsoleStdOutput>
+struct console_color_tpl : public console_color
+{
+public:
+ console_color_tpl() : console_color(color, console) {}
+
+private:
+};
+
+typedef console_color_tpl<DarkBlue> darkblue_text;
+typedef console_color_tpl<DarkGreen> darkgreen_text;
+typedef console_color_tpl<DarkCyan> darkcyan_text;
+typedef console_color_tpl<DarkRed> darkred_text;
+typedef console_color_tpl<DarkMagenta> darkmagenta_text;
+typedef console_color_tpl<DarkYellow> darkyellow_text;
+typedef console_color_tpl<LightGrey> lightgrey_text;
+typedef console_color_tpl<Gray> gray_text;
+typedef console_color_tpl<Blue> blue_text;
+typedef console_color_tpl<Green> green_text;
+typedef console_color_tpl<Cyan> cyan_text;
+typedef console_color_tpl<Red> red_text;
+typedef console_color_tpl<Magenta> magenta_text;
+typedef console_color_tpl<Yellow> yellow_text;
+typedef console_color_tpl<White> white_text;
+}
diff --git a/include/kfr/testo/testo.hpp b/include/kfr/testo/testo.hpp
@@ -0,0 +1,565 @@
+#pragma once
+
+#include "../cometa/tuple.hpp"
+
+#include "../cometa.hpp"
+#include "../cometa/range.hpp"
+#include "../cometa/string.hpp"
+
+#include <algorithm>
+#include <ctime>
+#include <functional>
+#include <sstream>
+#include <utility>
+#include <vector>
+#ifdef TESTO_MPFR
+#include <mpfr/mpfr.hpp>
+#include <mpfr/mpfr_tostring.hpp>
+#endif
+#include "../ext/console_colors.hpp"
+#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")
+
+namespace testo
+{
+
+using namespace cometa;
+
+#ifdef TESTO_MPFR
+using reference_number = mpfr::number;
+#else
+using reference_number = long double;
+#endif
+
+#ifdef TESTO_MPFR
+template <typename T>
+inline double ulp_distance(const mpfr::number& reference, T test)
+{
+ if (std::isnan(test) && reference.isnan())
+ return 0.0;
+ if (std::isinf(test) && (reference.isinfinity() || mpfr::abs(reference) > std::numeric_limits<T>::max()))
+ {
+ if ((reference < 0 && test < 0) || (reference > 0 && test > 0))
+ return 0.0;
+ else
+ return std::numeric_limits<double>::infinity();
+ }
+ mpfr::number testreal = test;
+ T next = std::nexttoward(test, std::numeric_limits<long double>::infinity());
+ mpfr::number ulp = testreal - mpfr::number(next);
+ return std::abs(static_cast<double>((reference - testreal) / ulp));
+}
+inline std::string number_to_string(const mpfr::number& reference, int precision)
+{
+ return mpfr::to_string(reference, precision, 'g');
+}
+#else
+template <typename T>
+inline double ulp_distance(long double reference, T test)
+{
+ if (__builtin_isnan(test) && __builtin_isnan(reference))
+ return 0.0;
+ if (__builtin_isinf(test) &&
+ (__builtin_isinf(reference) || std::fabs(reference) > std::numeric_limits<T>::max()))
+ {
+ if ((reference < 0 && test < 0) || (reference > 0 && test > 0))
+ return 0.0;
+ else
+ return std::numeric_limits<double>::infinity();
+ }
+ long double test80 = test;
+ T next = std::nexttoward(test, std::numeric_limits<long double>::infinity());
+ long double ulp = test80 - static_cast<long double>(next);
+ return std::abs(static_cast<double>((reference - test80) / ulp));
+}
+#endif
+
+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;
+ size_t prev_pos = 0;
+ size_t start_pos = 0;
+ std::vector<std::string> list;
+ while ((start_pos = r.find(delimeter, prev_pos)) != std::string::npos)
+ {
+ list.push_back(text.substr(prev_pos, start_pos - prev_pos));
+ prev_pos = start_pos + 1;
+ }
+ list.push_back(text.substr(prev_pos));
+ return list;
+}
+
+struct test_case;
+
+inline test_case*& active_test()
+{
+ static test_case* instance = nullptr;
+ return instance;
+}
+
+struct test_case
+{
+ using test_func = void (*)();
+
+ static std::vector<test_case*>& tests()
+ {
+ static std::vector<test_case*> list;
+ return list;
+ }
+
+ test_case(test_func func, const char* name)
+ : func(func), name(name), success(0), failed(0), time(0), show_progress(false)
+ {
+ tests().push_back(this);
+ }
+
+ bool run(bool show_successful)
+ {
+ using namespace std::chrono;
+ using time_point = high_resolution_clock::time_point;
+ {
+ console_color cc(Cyan);
+ printfmt("[{}]", padcenter(11, std::string("RUN"), '-'));
+ }
+ printfmt(" {}...\n", name);
+ time_point start = high_resolution_clock::now();
+ active_test() = this;
+ func();
+ active_test() = nullptr;
+ time_point stop = high_resolution_clock::now();
+ time = duration_cast<duration<double>>(stop - start).count();
+
+ {
+ console_color cc(failed ? Red : Green);
+ printfmt("[{}] {} subtests of {}\n", padcenter(11, failed ? "ERROR" : "SUCCESS", '-'),
+ failed ? failed : success, success + failed);
+ }
+ if (failed)
+ {
+ for (const subtest& s : subtests)
+ {
+ if ((s.success && show_successful) || !s.success)
+ {
+ if (!s.comment.empty())
+ printfmt(" {}:\n", s.comment);
+ {
+ console_color cc(s.success ? Green : Red);
+ printfmt(" {} ", s.success ? "[success]" : "[fail] ");
+ }
+ printfmt("{}\n", s.text);
+ }
+ }
+ console_color cc(White);
+ }
+ return !failed;
+ }
+
+ void check(bool result, const std::string& value, const char* expr)
+ {
+ subtests.push_back(subtest{ result, as_string(padleft(22, expr), " | ", value), comment });
+ result ? success++ : failed++;
+ if (show_progress)
+ {
+ if (result)
+ {
+ console_color cc(Green);
+ print(".");
+ }
+ else
+ {
+ console_color cc(Red);
+ print("E");
+ }
+ }
+ }
+
+ template <typename Op, typename L, typename R>
+ void check(const comparison<Op, L, R>& comparison, const char* expr)
+ {
+ bool result = comparison();
+ check(result, as_string(comparison.left, " ", Op::op(), " ", comparison.right), expr);
+ }
+
+ template <typename L>
+ void check(const half_comparison<L>& comparison, const char* expr)
+ {
+ bool result = comparison.left ? true : false;
+ check(result, as_string(comparison.left), expr);
+ }
+
+ void set_comment(const std::string& text)
+ {
+ comment = text;
+ if (show_progress)
+ {
+ println();
+ println(comment, ":");
+ }
+ }
+
+ struct subtest
+ {
+ bool success;
+ std::string text;
+ std::string comment;
+ };
+
+ test_func func;
+ const char* name;
+ std::vector<subtest> subtests;
+ std::string comment;
+ int success;
+ int failed;
+ double time;
+ bool show_progress;
+};
+
+template <typename Number>
+struct statistics
+{
+ Number minimum;
+ Number maximum;
+ double sum;
+ unsigned long long count;
+ std::vector<Number> values;
+ void reset() { *this = statistics<Number>(); }
+ std::string str()
+ {
+ return format("{} ... {} (avg={}, median={})\n", minimum, maximum, cometa::fmt<'f', 2>(average()),
+ median());
+ }
+ double average() const { return sum / count; }
+ Number median()
+ {
+ std::sort(values.begin(), values.end());
+ return values.empty() ? Number() : values[values.size() / 2];
+ }
+ statistics()
+ : sum(), count(), minimum(std::numeric_limits<Number>::max()),
+ maximum(std::numeric_limits<Number>::min())
+ {
+ }
+ void operator()(Number x)
+ {
+ minimum = std::min(minimum, x);
+ maximum = std::max(maximum, x);
+ sum += x;
+ count++;
+ values.push_back(x);
+ }
+};
+
+template <typename Arg0, typename Fn>
+void matrix(named_arg<Arg0>&& arg0, Fn&& fn)
+{
+ cforeach(std::forward<Arg0>(arg0.value), [&](auto v0) {
+ active_test()->set_comment(as_string(arg0.name, " = ", v0));
+ fn(v0);
+ });
+ if (active_test()->show_progress)
+ println();
+}
+
+template <typename Arg0, typename Arg1, typename Fn>
+void matrix(named_arg<Arg0>&& arg0, named_arg<Arg1>&& arg1, Fn&& fn)
+{
+ cforeach(std::forward<Arg0>(arg0.value), std::forward<Arg1>(arg1.value), [&](auto v0, auto v1) {
+ active_test()->set_comment(as_string(arg0.name, " = ", v0, ", ", arg1.name, " = ", v1));
+ fn(v0, v1);
+ });
+ if (active_test()->show_progress)
+ println();
+}
+
+template <typename Arg0, typename Arg1, typename Arg2, typename Fn>
+void matrix(named_arg<Arg0>&& arg0, named_arg<Arg1>&& arg1, named_arg<Arg2>&& arg2, Fn&& fn)
+{
+ cforeach(std::forward<Arg0>(arg0.value), std::forward<Arg1>(arg1.value), std::forward<Arg2>(arg2.value),
+ [&](auto v0, auto v1, auto v2) {
+ active_test()->set_comment(
+ as_string(arg0.name, " = ", v0, ", ", arg1.name, " = ", v1, ", ", arg2.name, " = ", v2));
+ fn(v0, v1, v2);
+ });
+ if (active_test()->show_progress)
+ println();
+}
+
+static int run_all(const std::string& name = std::string(), bool show_successful = false)
+{
+ std::vector<test_case*> success;
+ std::vector<test_case*> failed;
+ for (test_case* t : test_case::tests())
+ {
+ if (name.empty() || t->name == name)
+ t->run(show_successful) ? success.push_back(t) : failed.push_back(t);
+ }
+ printfmt("{}\n", std::string(79, '='));
+ if (!success.empty())
+ {
+ console_color cc(Green);
+ printfmt("[{}]", padcenter(11, "SUCCESS", '-'));
+ printfmt(" {} tests\n", success.size());
+ }
+ if (!failed.empty())
+ {
+ console_color cc(Red);
+ printfmt("[{}]", padcenter(11, "ERROR", '-'));
+ printfmt(" {} tests\n", failed.size());
+ }
+ return static_cast<int>(failed.size());
+}
+
+template <typename T1, typename T2>
+void assert_is_same()
+{
+ static_assert(std::is_same<T1, T2>::value, "");
+}
+template <typename T1, typename T2>
+void assert_is_same_decay()
+{
+ static_assert(std::is_same<cometa::decay<T1>, cometa::decay<T2>>::value, "");
+}
+
+#define TESTO_CHECK(...) \
+ do \
+ { \
+ ::testo::active_test()->check(::testo::make_comparison() <= __VA_ARGS__, #__VA_ARGS__); \
+ } while (0)
+
+#define TESTO_TEST(name) \
+ static void test_function_##name(); \
+ ::testo::test_case test_case_##name(&test_function_##name, #name); \
+ static void CMT_NOINLINE test_function_##name()
+
+#define TESTO_DTEST(name) \
+ template <typename> \
+ static void disabled_test_function_##name()
+
+#ifndef TESTO_NO_SHORT_MACROS
+#define CHECK TESTO_CHECK
+#define TEST TESTO_TEST
+#define DTEST TESTO_DTEST
+#endif
+}
+
+CLANG_DIAGNOSTIC_PRAGMA(pop)
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
@@ -18,9 +18,10 @@
cmake_minimum_required(VERSION 2.8)
set(TEST_SRC
- testo/testo.hpp
)
+add_definitions(-DKFR_TESTING=1)
+
include_directories(../include)
if (NOT ARM)
diff --git a/tests/base_test.cpp b/tests/base_test.cpp
@@ -4,7 +4,8 @@
* See LICENSE.txt for details
*/
-#include "testo/testo.hpp"
+#include <kfr/testo/testo.hpp>
+
#include <kfr/base.hpp>
#include <kfr/io.hpp>
@@ -131,13 +132,13 @@ TEST(test_basic)
CHECK(transpose<4>(sixteen) == vec<float, 16>(0, 4, 8, 12, 1, 5, 9, 13, 2, 6, 10, 14, 3, 7, 11, 15));
}
-TEST(vec_concat)
+TEST(concat)
{
CHECK(concat(vec<f32, 1>{ 1 }, vec<f32, 2>{ 2, 3 }, vec<f32, 1>{ 4 }, vec<f32, 3>{ 5, 6, 7 }) //
== vec<f32, 7>{ 1, 2, 3, 4, 5, 6, 7 });
}
-TEST(vec_split)
+TEST(split)
{
vec<f32, 1> a1;
vec<f32, 2> a23;
@@ -150,21 +151,21 @@ TEST(vec_split)
CHECK(a567 == vec<f32, 3>{ 5, 6, 7 });
}
-TEST(vec_broadcast)
+TEST(broadcast)
{
CHECK(broadcast<5>(3.f) == vec<f32, 5>{ 3, 3, 3, 3, 3 });
CHECK(broadcast<6>(1.f, 2.f) == vec<f32, 6>{ 1, 2, 1, 2, 1, 2 });
CHECK(broadcast<6>(1.f, 2.f, 3.f) == vec<f32, 6>{ 1, 2, 3, 1, 2, 3 });
}
-TEST(vec_resize)
+TEST(resize)
{
CHECK(resize<5>(make_vector(3.f)) == vec<f32, 5>{ 3, 3, 3, 3, 3 });
CHECK(resize<6>(make_vector(1.f, 2.f)) == vec<f32, 6>{ 1, 2, 1, 2, 1, 2 });
CHECK(resize<6>(make_vector(1.f, 2.f, 3.f)) == vec<f32, 6>{ 1, 2, 3, 1, 2, 3 });
}
-TEST(vec_make_vector)
+TEST(make_vector)
{
const signed char ch = -1;
CHECK(make_vector(1, 2, ch) == vec<i32, 3>{ 1, 2, -1 });
@@ -178,20 +179,20 @@ TEST(vec_make_vector)
CHECK(make_vector(1.f, f32x2{ 10, 20 }) == vec<vec<f32, 2>, 2>{ f32x2{ 1, 1 }, f32x2{ 10, 20 } });
}
-TEST(vec_apply)
+TEST(apply)
{
CHECK(apply([](int x) { return x + 1; }, make_vector(1, 2, 3, 4, 5)) == make_vector(2, 3, 4, 5, 6));
CHECK(apply(fn::sqr(), make_vector(1, 2, 3, 4, 5)) == make_vector(1, 4, 9, 16, 25));
}
-TEST(vec_zerovector)
+TEST(zerovector)
{
CHECK(zerovector<f32, 3>() == f32x3{ 0, 0, 0 });
// CHECK(zerovector<i16, 3>() == i16x3{ 0, 0, 0 }); // clang 3.9 (trunk) crashes here
CHECK(zerovector(f64x8{}) == f64x8{ 0, 0, 0, 0, 0, 0, 0, 0 });
}
-TEST(vec_allonesvector)
+TEST(allonesvector)
{
CHECK(bitcast<u32>(constants<f32>::allones()) == 0xFFFFFFFFu);
CHECK(bitcast<u64>(constants<f64>::allones()) == 0xFFFFFFFFFFFFFFFFull);
@@ -201,7 +202,7 @@ TEST(vec_allonesvector)
CHECK(allonesvector<u8, 3>() == u8x3{ 255, 255, 255 });
}
-TEST(vec_low_high)
+TEST(low_high)
{
CHECK(low(vec<u8, 8>(1, 2, 3, 4, 5, 6, 7, 8)) == vec<u8, 4>(1, 2, 3, 4));
CHECK(high(vec<u8, 8>(1, 2, 3, 4, 5, 6, 7, 8)) == vec<u8, 4>(5, 6, 7, 8));
@@ -226,7 +227,7 @@ TEST(vec_low_high)
}
#ifdef CMT_COMPILER_CLANG
-TEST(vec_matrix)
+TEST(matrix)
{
using i32x2x2 = vec<vec<int, 2>, 2>;
const i32x2x2 m22{ i32x2{ 1, 2 }, i32x2{ 3, 4 } };
@@ -245,7 +246,7 @@ TEST(vec_matrix)
}
#endif
-TEST(vec_is_convertible)
+TEST(is_convertible)
{
static_assert(std::is_convertible<float, f32x4>::value, "");
static_assert(std::is_convertible<float, f64x8>::value, "");
@@ -329,6 +330,13 @@ TEST(transcendental)
CHECK(kfr::log(2.45) == 0.89608802455663561677548191074382);
}
+TEST(horner)
+{
+ CHECK(horner(pack(0, 1, 2, 3), 1, 2, 3) == pack(1, 6, 17, 34));
+ CHECK(horner_odd(pack(0, 1, 2, 3), 1, 2, 3) == pack(0, 6, 114, 786));
+ CHECK(horner_even(pack(0, 1, 2, 3), 1, 2, 3) == pack(1, 6, 57, 262));
+}
+
TEST(test_stat)
{
{
diff --git a/tests/complex_test.cpp b/tests/complex_test.cpp
@@ -4,7 +4,8 @@
* See LICENSE.txt for details
*/
-#include "testo/testo.hpp"
+#include <kfr/testo/testo.hpp>
+
#include <kfr/base.hpp>
#include <kfr/io.hpp>
diff --git a/tests/dft_test.cpp b/tests/dft_test.cpp
@@ -4,7 +4,8 @@
* See LICENSE.txt for details
*/
-#include "testo/testo.hpp"
+#include <kfr/testo/testo.hpp>
+
#include <kfr/base.hpp>
#include <kfr/dft.hpp>
#include <kfr/dsp.hpp>
diff --git a/tests/dsp_test.cpp b/tests/dsp_test.cpp
@@ -4,7 +4,8 @@
* See LICENSE.txt for details
*/
-#include "testo/testo.hpp"
+#include <kfr/testo/testo.hpp>
+
#include <kfr/base.hpp>
#include <kfr/dsp.hpp>
#include <kfr/io.hpp>
@@ -14,19 +15,9 @@ using namespace kfr;
TEST(delay)
{
const univector<float, 33> v1 = counter() + 100;
- const univector<float, 33> v2 = delay(v1);
- CHECK(v2[0] == 0);
- CHECK(v2[1] == 100);
- CHECK(v2[2] == 101);
- CHECK(v2[19] == 118);
+ CHECK_EXPRESSION(delay(v1), 33, [](size_t i) { return i < 1 ? 0.f : (i - 1) + 100.f; });
- const univector<float, 33> v3 = delay(v1, csize_t<3>());
- CHECK(v3[0] == 0);
- CHECK(v3[1] == 0);
- CHECK(v3[2] == 0);
- CHECK(v3[3] == 100);
- CHECK(v3[4] == 101);
- CHECK(v3[19] == 116);
+ CHECK_EXPRESSION(delay<3>(v1), 33, [](size_t i) { return i < 3 ? 0.f : (i - 3) + 100.f; });
}
TEST(fracdelay)
@@ -47,12 +38,8 @@ TEST(fracdelay)
TEST(mixdown)
{
- univector<double, 20> ch1 = counter();
- univector<double, 20> ch2 = counter() * 2 + 100;
- univector<double, 20> mix = mixdown(ch1, ch2);
- CHECK(mix[0] == 100);
- CHECK(mix[1] == 103);
- CHECK(mix[19] == 157);
+ CHECK_EXPRESSION(mixdown(counter(), counter() * 2 + 100), infinite_size,
+ [](size_t i) { return i + i * 2 + 100; });
}
#ifdef CMT_COMPILER_CLANG
@@ -64,12 +51,8 @@ TEST(mixdown_stereo)
univector<double, 21> side;
unpack(mid, side) = mixdown_stereo(left, right, matrix_sum_diff());
- CHECK(mid[0] == 100);
- CHECK(side[0] == -100);
- CHECK(mid[1] == 103);
- CHECK(side[1] == -101);
- CHECK(mid[20] == 160);
- CHECK(side[20] == -120);
+ CHECK_EXPRESSION(mid, 21, [](size_t i) { return i + i * 2.0 + 100.0; });
+ CHECK_EXPRESSION(side, 21, [](size_t i) { return i - (i * 2.0 + 100.0); });
}
#endif
@@ -77,7 +60,7 @@ TEST(phasor)
{
constexpr fbase sr = 44100.0;
univector<fbase, 100> v1 = sinenorm(phasor(15000, sr));
- univector<fbase, 100> v2 = sin(c_pi<fbase, 2> * counter(0, 15000 / sr));
+ univector<fbase, 100> v2 = sin(constants<fbase>::pi_s(2) * counter(0, 15000 / sr));
CHECK(rms(v1 - v2) < 1.e-5);
}
diff --git a/tests/expression_test.cpp b/tests/expression_test.cpp
@@ -4,7 +4,7 @@
* See LICENSE.txt for details
*/
-#include "testo/testo.hpp"
+#include <kfr/testo/testo.hpp>
#include <kfr/base.hpp>
#include <kfr/cometa/function.hpp>
@@ -17,30 +17,18 @@ TEST(pack)
{
const univector<float, 21> v1 = 1 + counter();
const univector<float, 21> v2 = v1 * 11;
- const univector<f32x2, 21> v3 = pack(v1, v2);
- CHECK(v3[0] == f32x2{ 1, 11 });
- CHECK(v3[1] == f32x2{ 2, 22 });
- CHECK(v3[18] == f32x2{ 19, 209 });
- CHECK(v3[19] == f32x2{ 20, 220 });
- CHECK(v3[20] == f32x2{ 21, 231 });
-
- const univector<f32x2, 21> v4 = bind_expression(fn::reverse(), v3);
- CHECK(v4[0] == f32x2{ 11, 1 });
- CHECK(v4[1] == f32x2{ 22, 2 });
- CHECK(v4[18] == f32x2{ 209, 19 });
- CHECK(v4[19] == f32x2{ 220, 20 });
- CHECK(v4[20] == f32x2{ 231, 21 });
+
+ CHECK_EXPRESSION(pack(v1, v2), 21, [](size_t i) { return f32x2{ 1 + i, (1 + i) * 11 }; });
+
+ CHECK_EXPRESSION(bind_expression(fn::reverse(), pack(v1, v2)), 21, [](size_t i) {
+ return f32x2{ (1 + i) * 11, 1 + i };
+ });
}
TEST(adjacent)
{
- univector<int, 20> v1 = adjacent(fn::mul(), counter());
- CHECK(v1[0] == 0);
- CHECK(v1[1] == 0);
- CHECK(v1[2] == 2);
- CHECK(v1[3] == 6);
- CHECK(v1[4] == 12);
- CHECK(v1[19] == 342);
+ CHECK_EXPRESSION(adjacent(fn::mul(), counter()), infinite_size,
+ [](size_t i) { return i > 0 ? i * (i - 1) : 0; });
}
TEST(padded)
@@ -48,27 +36,16 @@ TEST(padded)
static_assert(is_infinite<decltype(padded(counter()))>::value, "");
static_assert(is_infinite<decltype(padded(truncate(counter(), 100)))>::value, "");
- univector<int, 21> v1 = padded(truncate(counter(), 6), -1);
- CHECK(v1[0] == 0);
- CHECK(v1[1] == 1);
- CHECK(v1[2] == 2);
- CHECK(v1[3] == 3);
- CHECK(v1[4] == 4);
- CHECK(v1[5] == 5);
- CHECK(v1[6] == -1);
- CHECK(v1[20] == -1);
+ CHECK_EXPRESSION(padded(truncate(counter(), 6), -1), infinite_size,
+ [](size_t i) { return i >= 6 ? -1 : i; });
}
TEST(rebind)
{
auto c_minus_two = counter() - 2;
auto four_minus_c = rebind(c_minus_two, 4, counter());
- univector<int, 5> v1 = c_minus_two;
- univector<int, 5> v2 = four_minus_c;
- CHECK(v1[0] == -2);
- CHECK(v1[1] == -1);
- CHECK(v2[0] == 4);
- CHECK(v2[1] == 3);
+ CHECK_EXPRESSION(c_minus_two, infinite_size, [](size_t i) { return i - 2; });
+ CHECK_EXPRESSION(four_minus_c, infinite_size, [](size_t i) { return 4 - i; });
}
TEST(test_arg_access)
@@ -78,11 +55,8 @@ TEST(test_arg_access)
auto e1 = std::move(v1) + 10;
std::get<0>(e1.args)[0] = 100;
std::get<1>(e1.args).val = 1;
- univector<float, 10> v2 = e1;
- CHECK(v2[0] == 101);
- CHECK(v2[1] == 2);
- CHECK(v2[2] == 3);
- CHECK(v2[9] == 10);
+
+ CHECK_EXPRESSION(e1, 10, [](size_t i) { return (i == 0 ? 100 : i) + 1; });
}
TEST(test_arg_replace)
@@ -91,11 +65,8 @@ TEST(test_arg_replace)
univector<float, 10> v2 = -counter();
auto e1 = to_pointer(v1) * 10;
std::get<0>(e1.args) = to_pointer(v2);
- univector<float, 10> v3 = e1;
- CHECK(v3[0] == 0);
- CHECK(v3[1] == -10);
- CHECK(v3[2] == -20);
- CHECK(v3[9] == -90);
+
+ CHECK_EXPRESSION(e1, 10, [](size_t i) { return i * -10.0; });
}
TEST(size_calc)
@@ -112,21 +83,14 @@ TEST(size_calc)
TEST(reverse)
{
- univector<int, 21> a = reverse(truncate(counter(), 21));
- CHECK(a[0] == 20);
- CHECK(a[1] == 19);
- CHECK(a[20] == 0);
+ CHECK_EXPRESSION(reverse(truncate(counter(), 21)), 21, [](size_t i) { return 20 - i; });
}
TEST(mix)
{
- univector<float, 21> a = mix(sequence(0, 0.5f, 1, 0.5f), counter(), counter() * 10);
- CHECK(a[0] == 0);
- CHECK(a[1] == 5.5);
- CHECK(a[2] == 20);
- CHECK(a[3] == 16.5);
- CHECK(a[4] == 4);
- CHECK(a[20] == 20);
+ CHECK_EXPRESSION(mix(sequence(0, 0.5f, 1, 0.5f), counter(), counter() * 10), infinite_size, [](size_t i) {
+ return mix(std::array<float, 4>{ 0, 0.5f, 1, 0.5f }[i % 4], i, i * 10);
+ });
}
constexpr inline size_t fast_range_sum(size_t stop) { return stop * (stop + 1) / 2; }
diff --git a/tests/intrinsic_test.cpp b/tests/intrinsic_test.cpp
@@ -4,7 +4,7 @@
* See LICENSE.txt for details
*/
-#include "testo/testo.hpp"
+#include <kfr/testo/testo.hpp>
#include <kfr/base.hpp>
#include <kfr/dsp.hpp>
diff --git a/tests/multiarch.cpp b/tests/multiarch.cpp
@@ -4,7 +4,7 @@
* See LICENSE.txt for details
*/
-#include "testo/testo.hpp"
+#include <kfr/testo/testo.hpp>
#include <kfr/base.hpp>
#include <kfr/dsp.hpp>
diff --git a/tests/testo/print_colored.hpp b/tests/testo/print_colored.hpp
@@ -1,153 +0,0 @@
-#pragma once
-#include <cstdint>
-
-#if defined(_WIN32)
-#ifndef NOMINMAX
-#define NOMINMAX
-#endif
-#include <windows.h>
-#endif
-
-namespace print_colored
-{
-
-enum text_color : uint32_t
-{
- Black = 0x00,
- DarkBlue = 0x01,
- DarkGreen = 0x02,
- DarkCyan = 0x03,
- DarkRed = 0x04,
- DarkMagenta = 0x05,
- DarkYellow = 0x06,
- LightGrey = 0x07,
- Gray = 0x08,
- Blue = 0x09,
- Green = 0x0A,
- Cyan = 0x0B,
- Red = 0x0C,
- Magenta = 0x0D,
- Yellow = 0x0E,
- White = 0x0F,
- BgBlack = 0x00,
- BgDarkBlue = 0x10,
- BgDarkGreen = 0x20,
- BgDarkCyan = 0x30,
- BgDarkRed = 0x40,
- BgDarkMagenta = 0x50,
- BgDarkYellow = 0x60,
- BgLightGrey = 0x70,
- BgGray = 0x80,
- BgBlue = 0x90,
- BgGreen = 0xA0,
- BgCyan = 0xB0,
- BgRed = 0xC0,
- BgMagenta = 0xD0,
- BgYellow = 0xE0,
- BgWhite = 0xF0,
-
- Normal = BgBlack | LightGrey
-};
-
-enum console_buffer
-{
- ConsoleStdOutput,
- ConsoleStdError
-};
-
-#if defined(_WIN32)
-typedef HANDLE console_handle_t;
-
-inline console_handle_t console_handle(console_buffer console = ConsoleStdOutput)
-{
- static HANDLE con_out = ::GetStdHandle(STD_OUTPUT_HANDLE);
- static HANDLE con_err = ::GetStdHandle(STD_ERROR_HANDLE);
- return console == ConsoleStdOutput ? con_out : con_err;
-}
-
-#endif
-
-struct console_color
-{
-public:
- console_color(text_color c, console_buffer console = ConsoleStdOutput)
- : m_old(get(console)), m_console(console)
- {
- set(c, m_console);
- }
-
- ~console_color() { set(m_old, m_console); }
-
-private:
- text_color get(console_buffer console = ConsoleStdOutput)
- {
-#ifdef _WIN32
- CONSOLE_SCREEN_BUFFER_INFO info;
- ::GetConsoleScreenBufferInfo(console_handle(console), &info);
- return static_cast<text_color>(info.wAttributes & 0xFF);
-#else
- return static_color();
-#endif
- }
-
- void set(text_color new_color, console_buffer console = ConsoleStdOutput)
- {
-#ifdef _WIN32
- ::SetConsoleTextAttribute(console_handle(console), static_cast<WORD>(new_color));
-#else
- if (new_color != Normal)
- {
- uint8_t t = new_color & 0xF;
- uint8_t b = (new_color & 0xF0) >> 4;
- uint8_t tnum = 30 + ((t & 1) << 2 | (t & 2) | (t & 4) >> 2);
- uint8_t bnum = 40 + ((b & 1) << 2 | (b & 2) | (b & 4) >> 2);
- if (t & 8)
- tnum += 60;
- if (b & 8)
- bnum += 60;
- printf("\x1B[%d;%dm", tnum, bnum);
- }
- else
- {
- printf("\x1B[0m");
- }
- static_color() = new_color;
-#endif
- }
-
- text_color m_old;
- console_buffer m_console;
-#ifndef _WIN32
- static text_color& static_color()
- {
- static text_color color = Normal;
- return color;
- }
-#endif
-};
-
-template <text_color color, console_buffer console = ConsoleStdOutput>
-struct colored_text_tpl : public console_color
-{
-public:
- colored_text_tpl() : console_color(color, console) {}
-
-private:
-};
-
-typedef colored_text_tpl<DarkBlue> darkblue_text;
-typedef colored_text_tpl<DarkGreen> darkgreen_text;
-typedef colored_text_tpl<DarkCyan> darkcyan_text;
-typedef colored_text_tpl<DarkRed> darkred_text;
-typedef colored_text_tpl<DarkMagenta> darkmagenta_text;
-typedef colored_text_tpl<DarkYellow> darkyellow_text;
-typedef colored_text_tpl<LightGrey> lightgrey_text;
-typedef colored_text_tpl<Gray> gray_text;
-typedef colored_text_tpl<Blue> blue_text;
-typedef colored_text_tpl<Green> green_text;
-typedef colored_text_tpl<Cyan> cyan_text;
-typedef colored_text_tpl<Red> red_text;
-typedef colored_text_tpl<Magenta> magenta_text;
-typedef colored_text_tpl<Yellow> yellow_text;
-typedef colored_text_tpl<White> white_text;
-}
diff --git a/tests/testo/testo.hpp b/tests/testo/testo.hpp
@@ -1,565 +0,0 @@
-#pragma once
-
-#include <kfr/cometa/tuple.hpp>
-
-#include <kfr/cometa.hpp>
-#include <kfr/cometa/range.hpp>
-#include <kfr/cometa/string.hpp>
-
-#include <algorithm>
-#include <ctime>
-#include <functional>
-#include <sstream>
-#include <utility>
-#include <vector>
-#ifdef TESTO_MPFR
-#include <mpfr/mpfr.hpp>
-#include <mpfr/mpfr_tostring.hpp>
-#endif
-#include "print_colored.hpp"
-#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")
-
-namespace testo
-{
-
-using namespace cometa;
-
-#ifdef TESTO_MPFR
-using reference_number = mpfr::number;
-#else
-using reference_number = long double;
-#endif
-
-#ifdef TESTO_MPFR
-template <typename T>
-inline double ulp_distance(const mpfr::number& reference, T test)
-{
- if (std::isnan(test) && reference.isnan())
- return 0.0;
- if (std::isinf(test) && (reference.isinfinity() || mpfr::abs(reference) > std::numeric_limits<T>::max()))
- {
- if ((reference < 0 && test < 0) || (reference > 0 && test > 0))
- return 0.0;
- else
- return std::numeric_limits<double>::infinity();
- }
- mpfr::number testreal = test;
- T next = std::nexttoward(test, std::numeric_limits<long double>::infinity());
- mpfr::number ulp = testreal - mpfr::number(next);
- return std::abs(static_cast<double>((reference - testreal) / ulp));
-}
-inline std::string number_to_string(const mpfr::number& reference, int precision)
-{
- return mpfr::to_string(reference, precision, 'g');
-}
-#else
-template <typename T>
-inline double ulp_distance(long double reference, T test)
-{
- if (__builtin_isnan(test) && __builtin_isnan(reference))
- return 0.0;
- if (__builtin_isinf(test) &&
- (__builtin_isinf(reference) || std::fabs(reference) > std::numeric_limits<T>::max()))
- {
- if ((reference < 0 && test < 0) || (reference > 0 && test > 0))
- return 0.0;
- else
- return std::numeric_limits<double>::infinity();
- }
- long double test80 = test;
- T next = std::nexttoward(test, std::numeric_limits<long double>::infinity());
- long double ulp = test80 - static_cast<long double>(next);
- return std::abs(static_cast<double>((reference - test80) / ulp));
-}
-#endif
-
-using namespace print_colored;
-
-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;
- size_t prev_pos = 0;
- size_t start_pos = 0;
- std::vector<std::string> list;
- while ((start_pos = r.find(delimeter, prev_pos)) != std::string::npos)
- {
- list.push_back(text.substr(prev_pos, start_pos - prev_pos));
- prev_pos = start_pos + 1;
- }
- list.push_back(text.substr(prev_pos));
- return list;
-}
-
-struct test_case;
-
-inline test_case*& active_test()
-{
- static test_case* instance = nullptr;
- return instance;
-}
-
-struct test_case
-{
- using test_func = void (*)();
-
- static std::vector<test_case*>& tests()
- {
- static std::vector<test_case*> list;
- return list;
- }
-
- test_case(test_func func, const char* name)
- : func(func), name(name), success(0), failed(0), time(0), show_progress(false)
- {
- tests().push_back(this);
- }
-
- bool run(bool show_successful)
- {
- using namespace std::chrono;
- using time_point = high_resolution_clock::time_point;
- {
- console_color cc(Cyan);
- printfmt("[{}]", padcenter(11, std::string("RUN"), '-'));
- }
- printfmt(" {}...\n", name);
- time_point start = high_resolution_clock::now();
- active_test() = this;
- func();
- active_test() = nullptr;
- time_point stop = high_resolution_clock::now();
- time = duration_cast<duration<double>>(stop - start).count();
-
- {
- console_color cc(failed ? Red : Green);
- printfmt("[{}] {} subtests of {}\n", padcenter(11, failed ? "ERROR" : "SUCCESS", '-'),
- failed ? failed : success, success + failed);
- }
- if (failed)
- {
- for (const subtest& s : subtests)
- {
- if ((s.success && show_successful) || !s.success)
- {
- if (!s.comment.empty())
- printfmt(" {}:\n", s.comment);
- {
- console_color cc(s.success ? Green : Red);
- printfmt(" {} ", s.success ? "[success]" : "[fail] ");
- }
- printfmt("{}\n", s.text);
- }
- }
- console_color cc(White);
- }
- return !failed;
- }
-
- void check(bool result, const std::string& value, const char* expr)
- {
- subtests.push_back(subtest{ result, as_string(padleft(22, expr), " | ", value), comment });
- result ? success++ : failed++;
- if (show_progress)
- {
- if (result)
- {
- console_color cc(Green);
- print(".");
- }
- else
- {
- console_color cc(Red);
- print("E");
- }
- }
- }
-
- template <typename Op, typename L, typename R>
- void check(const comparison<Op, L, R>& comparison, const char* expr)
- {
- bool result = comparison();
- check(result, as_string(comparison.left, " ", Op::op(), " ", comparison.right), expr);
- }
-
- template <typename L>
- void check(const half_comparison<L>& comparison, const char* expr)
- {
- bool result = comparison.left ? true : false;
- check(result, as_string(comparison.left), expr);
- }
-
- void set_comment(const std::string& text)
- {
- comment = text;
- if (show_progress)
- {
- println();
- println(comment, ":");
- }
- }
-
- struct subtest
- {
- bool success;
- std::string text;
- std::string comment;
- };
-
- test_func func;
- const char* name;
- std::vector<subtest> subtests;
- std::string comment;
- int success;
- int failed;
- double time;
- bool show_progress;
-};
-
-template <typename Number>
-struct statistics
-{
- Number minimum;
- Number maximum;
- double sum;
- unsigned long long count;
- std::vector<Number> values;
- void reset() { *this = statistics<Number>(); }
- std::string str()
- {
- return format("{} ... {} (avg={}, median={})\n", minimum, maximum, cometa::fmt<'f', 2>(average()),
- median());
- }
- double average() const { return sum / count; }
- Number median()
- {
- std::sort(values.begin(), values.end());
- return values.empty() ? Number() : values[values.size() / 2];
- }
- statistics()
- : sum(), count(), minimum(std::numeric_limits<Number>::max()),
- maximum(std::numeric_limits<Number>::min())
- {
- }
- void operator()(Number x)
- {
- minimum = std::min(minimum, x);
- maximum = std::max(maximum, x);
- sum += x;
- count++;
- values.push_back(x);
- }
-};
-
-template <typename Arg0, typename Fn>
-void matrix(named_arg<Arg0>&& arg0, Fn&& fn)
-{
- cforeach(std::forward<Arg0>(arg0.value), [&](auto v0) {
- active_test()->set_comment(as_string(arg0.name, " = ", v0));
- fn(v0);
- });
- if (active_test()->show_progress)
- println();
-}
-
-template <typename Arg0, typename Arg1, typename Fn>
-void matrix(named_arg<Arg0>&& arg0, named_arg<Arg1>&& arg1, Fn&& fn)
-{
- cforeach(std::forward<Arg0>(arg0.value), std::forward<Arg1>(arg1.value), [&](auto v0, auto v1) {
- active_test()->set_comment(as_string(arg0.name, " = ", v0, ", ", arg1.name, " = ", v1));
- fn(v0, v1);
- });
- if (active_test()->show_progress)
- println();
-}
-
-template <typename Arg0, typename Arg1, typename Arg2, typename Fn>
-void matrix(named_arg<Arg0>&& arg0, named_arg<Arg1>&& arg1, named_arg<Arg2>&& arg2, Fn&& fn)
-{
- cforeach(std::forward<Arg0>(arg0.value), std::forward<Arg1>(arg1.value), std::forward<Arg2>(arg2.value),
- [&](auto v0, auto v1, auto v2) {
- active_test()->set_comment(
- as_string(arg0.name, " = ", v0, ", ", arg1.name, " = ", v1, ", ", arg2.name, " = ", v2));
- fn(v0, v1, v2);
- });
- if (active_test()->show_progress)
- println();
-}
-
-static int run_all(const std::string& name = std::string(), bool show_successful = false)
-{
- std::vector<test_case*> success;
- std::vector<test_case*> failed;
- for (test_case* t : test_case::tests())
- {
- if (name.empty() || t->name == name)
- t->run(show_successful) ? success.push_back(t) : failed.push_back(t);
- }
- printfmt("{}\n", std::string(79, '='));
- if (!success.empty())
- {
- console_color cc(Green);
- printfmt("[{}]", padcenter(11, "SUCCESS", '-'));
- printfmt(" {} tests\n", success.size());
- }
- if (!failed.empty())
- {
- console_color cc(Red);
- printfmt("[{}]", padcenter(11, "ERROR", '-'));
- printfmt(" {} tests\n", failed.size());
- }
- return static_cast<int>(failed.size());
-}
-
-template <typename T1, typename T2>
-void assert_is_same()
-{
- static_assert(std::is_same<T1, T2>::value, "");
-}
-template <typename T1, typename T2>
-void assert_is_same_decay()
-{
- static_assert(std::is_same<cometa::decay<T1>, cometa::decay<T2>>::value, "");
-}
-
-#define TESTO_CHECK(...) \
- do \
- { \
- ::testo::active_test()->check(::testo::make_comparison() <= __VA_ARGS__, #__VA_ARGS__); \
- } while (0)
-
-#define TESTO_TEST(name) \
- void test_function_##name(); \
- ::testo::test_case test_case_##name(&test_function_##name, #name); \
- void CMT_NOINLINE test_function_##name()
-
-#define TESTO_DTEST(name) \
- template <typename> \
- void disabled_test_function_##name()
-
-#ifndef TESTO_NO_SHORT_MACROS
-#define CHECK TESTO_CHECK
-#define TEST TESTO_TEST
-#define DTEST TESTO_DTEST
-#endif
-}
-
-CLANG_DIAGNOSTIC_PRAGMA(pop)
diff --git a/tests/transcendental_test.cpp b/tests/transcendental_test.cpp
@@ -4,7 +4,8 @@
* See LICENSE.txt for details
*/
-#include "testo/testo.hpp"
+#include <kfr/testo/testo.hpp>
+
#include <kfr/base.hpp>
#include <kfr/io.hpp>