debug: simplify CHECK macros for constexpr safety
This commit is contained in:
parent
9248c2f379
commit
2224131955
264
debug.hpp
264
debug.hpp
@ -23,6 +23,7 @@
|
|||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
#ifdef ENABLE_DEBUGGING
|
#ifdef ENABLE_DEBUGGING
|
||||||
#define DEBUG_ONLY(X) do { \
|
#define DEBUG_ONLY(X) do { \
|
||||||
@ -57,43 +58,34 @@
|
|||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
#define _CHECK_META(C, SUCCESS, FAILURE) do { \
|
#define _CHECK_PANIC(FMT,...) do { \
|
||||||
const auto __DEBUG_value = (C); \
|
panic ("%s:%s:%i:%s\n" FMT, \
|
||||||
if (!__DEBUG_value) { \
|
PACKAGE, __FILE__, __LINE__, __FUNCTION__, \
|
||||||
std::cerr << PACKAGE << ": " \
|
__VA_ARGS__); \
|
||||||
<< __FILE__ << ":" \
|
} while(0)
|
||||||
<< __LINE__ << ": " \
|
|
||||||
<< __FUNCTION__ \
|
|
||||||
<< ". Assertion '" << #C \
|
|
||||||
<< "' failed: " << __DEBUG_value << std::endl; \
|
|
||||||
\
|
|
||||||
{ FAILURE } \
|
|
||||||
} else { \
|
|
||||||
{ SUCCESS } \
|
|
||||||
} \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
#define CHECK(C) do { DEBUG_ONLY(_CHECK_META((C), { ; }, { panic (); });); } while (0)
|
#define CHECK(C) do { \
|
||||||
|
DEBUG_ONLY( \
|
||||||
|
if (!(C)) \
|
||||||
|
panic (); \
|
||||||
|
); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
#define CHECK_EQ(A,B) do { \
|
#define CHECK_EQ(A,B) do { \
|
||||||
DEBUG_ONLY( \
|
DEBUG_ONLY( \
|
||||||
const auto __a = (A); \
|
const auto __a = (A); \
|
||||||
const auto __b = (B); \
|
const auto __b = (B); \
|
||||||
_CHECK_META (util::almost_equal (__a, __b), \
|
\
|
||||||
{ ; }, \
|
if (!util::almost_equal (__a, __b)) { \
|
||||||
{ \
|
_CHECK_PANIC("expected equality\n" \
|
||||||
std::ostringstream __debug_os; \
|
"__a: %s is %!\n" \
|
||||||
__debug_os.precision (15); \
|
"__b: %s is %!\n", \
|
||||||
__debug_os \
|
#A, __a, \
|
||||||
<< "expected equality.\n" \
|
#B, __b); \
|
||||||
<< "__a: " << #A << " is " << __a << ")" \
|
} \
|
||||||
<< "\n != \n" \
|
|
||||||
<< "__b: " << #B << " is " << __b << ")"; \
|
|
||||||
panic (__debug_os.str ()); \
|
|
||||||
}); \
|
|
||||||
); \
|
); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
@ -103,17 +95,14 @@
|
|||||||
DEBUG_ONLY( \
|
DEBUG_ONLY( \
|
||||||
const auto __a = (A); \
|
const auto __a = (A); \
|
||||||
const auto __b = (B); \
|
const auto __b = (B); \
|
||||||
_CHECK_META (__a < __b, \
|
\
|
||||||
{ ; }, \
|
if (__a >= __b) { \
|
||||||
{ \
|
_CHECK_PANIC("expected less than\n" \
|
||||||
std::ostringstream __debug_check_lt_os; \
|
"__a: %s is %!\n" \
|
||||||
__debug_check_lt_os \
|
"__b: %s is %!\n", \
|
||||||
<< "expected less than.\n" \
|
#A, __a, \
|
||||||
<< "__a: " << #A << " is " << __a << ")" \
|
#B, __b); \
|
||||||
<< "\n >= \n" \
|
}; \
|
||||||
<< "__b: " << #B << " is " << __b << ")"; \
|
|
||||||
panic (__debug_check_lt_os.str ()); \
|
|
||||||
}); \
|
|
||||||
); \
|
); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
@ -123,17 +112,14 @@
|
|||||||
DEBUG_ONLY( \
|
DEBUG_ONLY( \
|
||||||
const auto __a = (A); \
|
const auto __a = (A); \
|
||||||
const auto __b = (B); \
|
const auto __b = (B); \
|
||||||
_CHECK_META (__a <= __b, \
|
\
|
||||||
{ ; }, \
|
if (__a > __b) { \
|
||||||
{ \
|
_CHECK_PANIC("expected less than or equal\n" \
|
||||||
std::ostringstream __debug_check_lt_os; \
|
"__a: %s is %!\n" \
|
||||||
__debug_check_lt_os \
|
"__b: %s is %!\n", \
|
||||||
<< "expected less or equal to\n" \
|
#A, __a, \
|
||||||
<< "__a: " << #A << " is " << __a << ")" \
|
#B, __b); \
|
||||||
<< "\n > \n" \
|
} \
|
||||||
<< "__b: " << #B << " is " << __b << ")"; \
|
|
||||||
panic (__debug_check_lt_os.str ()); \
|
|
||||||
}); \
|
|
||||||
); \
|
); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
@ -143,17 +129,14 @@
|
|||||||
DEBUG_ONLY( \
|
DEBUG_ONLY( \
|
||||||
const auto __a = (A); \
|
const auto __a = (A); \
|
||||||
const auto __b = (B); \
|
const auto __b = (B); \
|
||||||
_CHECK_META (__a > __b, \
|
\
|
||||||
{ ; }, \
|
if (__a <= __b) { \
|
||||||
{ \
|
_CHECK_PANIC ("expected greater than\n" \
|
||||||
std::ostringstream __debug_check_gt_os; \
|
"__a: %s is %!\n" \
|
||||||
__debug_check_gt_os \
|
"__b: %s is %!\n", \
|
||||||
<< "expected greater than.\n" \
|
#A, __a, \
|
||||||
<< "__a: " << #A << " is " << __a << ")" \
|
#B, __b); \
|
||||||
<< "\n <= \n" \
|
} \
|
||||||
<< "__b: " << #B << " is " << __b << ")"; \
|
|
||||||
panic (__debug_check_gt_os.str ()); \
|
|
||||||
}); \
|
|
||||||
); \
|
); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
@ -163,39 +146,35 @@
|
|||||||
DEBUG_ONLY( \
|
DEBUG_ONLY( \
|
||||||
const auto __a = (A); \
|
const auto __a = (A); \
|
||||||
const auto __b = (B); \
|
const auto __b = (B); \
|
||||||
_CHECK_META (__a >= __b, \
|
\
|
||||||
{ ; }, \
|
if (__a < __b) { \
|
||||||
{ \
|
_CHECK_PANIC ("expected greater or equal\n" \
|
||||||
std::ostringstream __debug_check_gt_os; \
|
"__a: %s is %!\n" \
|
||||||
__debug_check_gt_os \
|
"__b: %s is %!\n", \
|
||||||
<< "expected greater or equal to.\n" \
|
#A, __a, \
|
||||||
<< "__a: " << #A << " is " << __a << ")" \
|
#B, __b); \
|
||||||
<< "\n < \n" \
|
}; \
|
||||||
<< "__b: " << #B << " is " << __b << ")"; \
|
|
||||||
panic (__debug_check_gt_os.str ()); \
|
|
||||||
}); \
|
|
||||||
); \
|
); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
#define CHECK_LIMIT(VAL,LO,HI) do { \
|
#define CHECK_LIMIT(V,L,H) do { \
|
||||||
DEBUG_ONLY( \
|
DEBUG_ONLY( \
|
||||||
const auto __val = (VAL); \
|
const auto __v = (V); \
|
||||||
const auto __hi = (HI); \
|
const auto __l = (L); \
|
||||||
const auto __lo = (LO); \
|
const auto __h = (H); \
|
||||||
\
|
\
|
||||||
_CHECK_META (__val >= __lo && __val <= __hi, \
|
if (__v < __l || __v > __h) { \
|
||||||
{ ; }, \
|
_CHECK_PANIC ("expected limit\n" \
|
||||||
{ \
|
"__l: %s is %!\n" \
|
||||||
std::ostringstream __os; \
|
"__h: %s is %!\n" \
|
||||||
__os << "expected satisifies limit\n" \
|
"__v: %s is %!\n", \
|
||||||
<< "__val: " << #VAL << " = " << __val << '\n' \
|
#H, __h, \
|
||||||
<< "__lo: " << #LO << " = " << __lo << '\n' \
|
#L, __l, \
|
||||||
<< "__hi: " << #HI << " = " << __hi << '\n'; \
|
#V, __v); \
|
||||||
panic (__os.str ()); \
|
}; \
|
||||||
}); \
|
); \
|
||||||
); \
|
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
@ -203,16 +182,14 @@
|
|||||||
DEBUG_ONLY( \
|
DEBUG_ONLY( \
|
||||||
const auto __a = (A); \
|
const auto __a = (A); \
|
||||||
const auto __b = (B); \
|
const auto __b = (B); \
|
||||||
_CHECK_META (!util::almost_equal (__a, __b), \
|
\
|
||||||
{ ; }, \
|
if (util::almost_equal (__a, __b)) { \
|
||||||
{ \
|
_CHECK_PANIC ("expected inequality\n" \
|
||||||
std::ostringstream __debug_neq_os; \
|
"__a: %s is %s\n" \
|
||||||
__debug_neq_os << "unexpected equality.\n" \
|
"__b: %s is %s\n", \
|
||||||
<< "__a: " << #A << " is " << __a << ")" \
|
#A, __a, \
|
||||||
<< "\n == \n" \
|
#B, __b); \
|
||||||
<< "__b: " << #B << " is " << __b << ")"; \
|
}; \
|
||||||
panic (__debug_neq_os.str ()); \
|
|
||||||
}); \
|
|
||||||
); \
|
); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
@ -221,14 +198,12 @@
|
|||||||
#define CHECK_ZERO(A) do { \
|
#define CHECK_ZERO(A) do { \
|
||||||
DEBUG_ONLY( \
|
DEBUG_ONLY( \
|
||||||
const auto __a = (A); \
|
const auto __a = (A); \
|
||||||
_CHECK_META (util::almost_zero (__a), \
|
\
|
||||||
{ ; }, \
|
if (!util::almost_zero (__a)) { \
|
||||||
{ \
|
_CHECK_PANIC ("expected zero\n" \
|
||||||
std::ostringstream __debug_nez_os; \
|
"__a: %s is %s\n" \
|
||||||
__debug_nez_os << "expected zero.\n" \
|
#A, __a); \
|
||||||
<< "__a: " << #A << " is " << __a << ")"; \
|
}; \
|
||||||
panic (__debug_nez_os.str ()); \
|
|
||||||
}); \
|
|
||||||
); \
|
); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
@ -237,63 +212,53 @@
|
|||||||
#define CHECK_NEZ(A) do { \
|
#define CHECK_NEZ(A) do { \
|
||||||
DEBUG_ONLY( \
|
DEBUG_ONLY( \
|
||||||
const auto __a = (A); \
|
const auto __a = (A); \
|
||||||
_CHECK_META (!util::almost_zero (__a), \
|
if (util::exactly_zero (__a)) \
|
||||||
{ ; }, \
|
_CHECK_PANIC ("expected zero\n" \
|
||||||
{ \
|
"__a: %s is %!", \
|
||||||
std::ostringstream __debug_nez_os; \
|
#A, __a); \
|
||||||
__debug_nez_os << "unexpected zero.\n" \
|
|
||||||
<< "__a: " << #A << " is " << __a << ")"; \
|
|
||||||
panic (__debug_nez_os.str ()); \
|
|
||||||
}); \
|
|
||||||
); \
|
); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
#define CHECK_THROWS(E,C) do { \
|
#define CHECK_THROWS(E,C) do { \
|
||||||
DEBUG_ONLY( \
|
DEBUG_ONLY( \
|
||||||
bool caught = false; \
|
bool caught = false; \
|
||||||
\
|
\
|
||||||
try \
|
try \
|
||||||
{ C; } \
|
{ C; } \
|
||||||
catch (E) \
|
catch (E) \
|
||||||
{ caught = true; } \
|
{ caught = true; } \
|
||||||
\
|
\
|
||||||
if (!caught) \
|
if (!caught) \
|
||||||
panic ("expected exception: " #E); \
|
_CHECK_PANIC ("expected exception: %s", #E); \
|
||||||
); \
|
); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
#define CHECK_NOTHROW(C) do { \
|
#define CHECK_NOTHROW(C) do { \
|
||||||
DEBUG_ONLY( \
|
DEBUG_ONLY( \
|
||||||
try { \
|
try { \
|
||||||
C; \
|
C; \
|
||||||
} catch (...) { \
|
} catch (const std::exception &e) { \
|
||||||
panic ("unexpected exception"); \
|
_CHECK_PANIC ("unexpected exception: %s", \
|
||||||
} \
|
e.what ()); \
|
||||||
); \
|
} catch (...) { \
|
||||||
|
_CHECK_PANIC ("unexpected exception: %s", \
|
||||||
|
"unknown"); \
|
||||||
|
} \
|
||||||
|
); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
class panic_error {
|
|
||||||
protected:
|
|
||||||
std::string m_what;
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit panic_error (const std::string &_what):
|
|
||||||
m_what (_what)
|
|
||||||
{ ; }
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
|
||||||
void panic [[noreturn]] (const std::string&);
|
|
||||||
constexpr void panic [[noreturn]] (const char*);
|
constexpr void panic [[noreturn]] (const char*);
|
||||||
constexpr void panic [[noreturn]] (void);
|
constexpr void panic [[noreturn]] (void);
|
||||||
|
|
||||||
|
template <typename ...Args>
|
||||||
|
constexpr void panic [[noreturn]] (const char *fmt, const Args&...);
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
constexpr void not_implemented [[noreturn]] (void);
|
constexpr void not_implemented [[noreturn]] (void);
|
||||||
@ -368,12 +333,13 @@ namespace util { namespace debug {
|
|||||||
} }
|
} }
|
||||||
|
|
||||||
|
|
||||||
|
#include "./debug.ipp"
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
// XXX: maths needs to be included so that CHECK_EQ/NEQ can call almost_equal,
|
// XXX: maths needs to be included so that CHECK_EQ/NEQ can call almost_equal,
|
||||||
// but maths.hpp might be using CHECK_ macros so we must include maths.hpp
|
// but maths.hpp might be using CHECK_ macros so we must include maths.hpp
|
||||||
// after we define the CHECK_ macros so the preprocessor can resolve them.
|
// after we define the CHECK_ macros so the preprocessor can resolve them.
|
||||||
#include "./maths.hpp"
|
#include "./maths.hpp"
|
||||||
|
|
||||||
#include "./debug.ipp"
|
|
||||||
|
|
||||||
#endif // __DEBUG_HPP
|
#endif // __DEBUG_HPP
|
||||||
|
26
debug.ipp
26
debug.ipp
@ -20,11 +20,18 @@
|
|||||||
|
|
||||||
#define __UTIL_DEBUG_IPP
|
#define __UTIL_DEBUG_IPP
|
||||||
|
|
||||||
|
#include "./format.hpp"
|
||||||
|
|
||||||
#include <limits>
|
#include <limits>
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
namespace util { namespace debug { namespace detail {
|
namespace util { namespace debug { namespace detail {
|
||||||
void panic [[noreturn]] (const char *msg);
|
void panic [[noreturn]] (const char *msg);
|
||||||
|
|
||||||
|
template <typename ...Args>
|
||||||
|
void panic [[noreturn]] (const char *msg, const Args& ...args)
|
||||||
|
{ panic (util::format::render (msg, args...).c_str ()); }
|
||||||
|
|
||||||
void not_implemented [[noreturn]] (const char *msg);
|
void not_implemented [[noreturn]] (const char *msg);
|
||||||
void unreachable [[noreturn]] (const char *msg);
|
void unreachable [[noreturn]] (const char *msg);
|
||||||
} } }
|
} } }
|
||||||
@ -76,13 +83,6 @@ constexpr void unreachable [[noreturn]] (const char *msg)
|
|||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
inline void panic [[noreturn]] (const std::string &msg)
|
|
||||||
{
|
|
||||||
util::debug::detail::panic (msg.c_str ());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
constexpr void panic [[noreturn]] (void)
|
constexpr void panic [[noreturn]] (void)
|
||||||
{
|
{
|
||||||
panic ("nfi");
|
panic ("nfi");
|
||||||
@ -96,3 +96,15 @@ constexpr void panic [[noreturn]] (const char *msg)
|
|||||||
? panic (msg)
|
? panic (msg)
|
||||||
: util::debug::detail::panic (msg);
|
: util::debug::detail::panic (msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
template <typename ...Args>
|
||||||
|
constexpr
|
||||||
|
void
|
||||||
|
panic [[noreturn]] (const char *fmt, const Args& ...args)
|
||||||
|
{
|
||||||
|
! fmt
|
||||||
|
? panic ()
|
||||||
|
: util::debug::detail::panic (fmt, args...);
|
||||||
|
}
|
||||||
|
224
maths.hpp
224
maths.hpp
@ -38,6 +38,135 @@
|
|||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
namespace util {
|
namespace util {
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
// Comparisons
|
||||||
|
inline bool
|
||||||
|
almost_equal (const float &a, const float &b)
|
||||||
|
{
|
||||||
|
return ieee_single::almost_equal (a, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
inline bool
|
||||||
|
almost_equal (const double &a, const double &b)
|
||||||
|
{
|
||||||
|
return ieee_double::almost_equal (a, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
template <typename A, typename B>
|
||||||
|
typename std::enable_if_t<
|
||||||
|
std::is_floating_point<A>::value &&
|
||||||
|
std::is_floating_point<B>::value,
|
||||||
|
bool
|
||||||
|
>
|
||||||
|
almost_equal (const A &a, const B &b)
|
||||||
|
{
|
||||||
|
using common_t = std::common_type_t<A,B>;
|
||||||
|
return almost_equal<common_t> (static_cast<common_t> (a),
|
||||||
|
static_cast<common_t> (b));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
template <typename A, typename B>
|
||||||
|
typename std::enable_if_t<
|
||||||
|
std::is_integral<A>::value &&
|
||||||
|
std::is_integral<B>::value &&
|
||||||
|
std::is_signed<A>::value == std::is_signed<B>::value,
|
||||||
|
bool
|
||||||
|
>
|
||||||
|
almost_equal (const A &a, const B &b) {
|
||||||
|
using common_t = std::common_type_t<A,B>;
|
||||||
|
return static_cast<common_t> (a) == static_cast<common_t> (b);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
template <typename Ta, typename Tb>
|
||||||
|
typename std::enable_if<
|
||||||
|
!std::is_arithmetic<Ta>::value ||
|
||||||
|
!std::is_arithmetic<Tb>::value,
|
||||||
|
bool
|
||||||
|
>::type
|
||||||
|
almost_equal (const Ta &a, const Tb &b)
|
||||||
|
{ return a == b; }
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Useful for explictly ignore equality warnings
|
||||||
|
#pragma GCC diagnostic push
|
||||||
|
#pragma GCC diagnostic ignored "-Wfloat-equal"
|
||||||
|
template <typename Ta, typename Tb>
|
||||||
|
constexpr
|
||||||
|
typename std::enable_if_t<
|
||||||
|
std::is_arithmetic<Ta>::value &&
|
||||||
|
std::is_arithmetic<Tb>::value,
|
||||||
|
bool
|
||||||
|
>
|
||||||
|
exactly_equal (const Ta a, const Tb b)
|
||||||
|
{
|
||||||
|
return a == b;
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------
|
||||||
|
template <typename Ta, typename Tb>
|
||||||
|
typename std::enable_if_t<
|
||||||
|
!std::is_arithmetic<Ta>::value ||
|
||||||
|
!std::is_arithmetic<Tb>::value,
|
||||||
|
bool
|
||||||
|
>
|
||||||
|
exactly_equal (const Ta &a, const Tb &b)
|
||||||
|
{
|
||||||
|
return a == b;
|
||||||
|
}
|
||||||
|
#pragma GCC diagnostic pop
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
template <typename T>
|
||||||
|
constexpr
|
||||||
|
std::enable_if_t<
|
||||||
|
std::is_integral<T>::value, bool
|
||||||
|
>
|
||||||
|
almost_zero (T t)
|
||||||
|
{
|
||||||
|
return t == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
std::enable_if_t<
|
||||||
|
!std::is_integral<T>::value, bool
|
||||||
|
>
|
||||||
|
almost_zero (T a)
|
||||||
|
{ return almost_equal (a, T{0}); }
|
||||||
|
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------
|
||||||
|
template <typename T>
|
||||||
|
constexpr
|
||||||
|
typename std::enable_if_t<
|
||||||
|
std::is_integral<T>::value, bool
|
||||||
|
>
|
||||||
|
exactly_zero (T t)
|
||||||
|
{
|
||||||
|
return exactly_equal (t, T{0});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
typename std::enable_if_t<
|
||||||
|
!std::is_integral<T>::value, bool
|
||||||
|
>
|
||||||
|
exactly_zero (T t)
|
||||||
|
{
|
||||||
|
return exactly_equal (t, T{0});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
template <typename T>
|
template <typename T>
|
||||||
T
|
T
|
||||||
abs [[gnu::const]] (T t)
|
abs [[gnu::const]] (T t)
|
||||||
@ -170,97 +299,20 @@ namespace util {
|
|||||||
constexpr T
|
constexpr T
|
||||||
gcd (T a, T b)
|
gcd (T a, T b)
|
||||||
{
|
{
|
||||||
if (a == b) return a;
|
CHECK_NEZ (a);
|
||||||
|
CHECK_NEZ (b);
|
||||||
|
|
||||||
if (a > b) return gcd (a - b, b);
|
while (a != b) {
|
||||||
if (b > a) return gcd (a, b - a);
|
if (a > b)
|
||||||
|
a -= b;
|
||||||
|
else if (b > a)
|
||||||
|
b -= a;
|
||||||
|
}
|
||||||
|
|
||||||
unreachable ();
|
return a;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
|
||||||
// Comparisons
|
|
||||||
inline bool
|
|
||||||
almost_equal (const float &a, const float &b)
|
|
||||||
{
|
|
||||||
return ieee_single::almost_equal (a, b);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
inline bool
|
|
||||||
almost_equal (const double &a, const double &b)
|
|
||||||
{
|
|
||||||
return ieee_double::almost_equal (a, b);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
template <typename A, typename B>
|
|
||||||
typename std::enable_if_t<
|
|
||||||
std::is_floating_point<A>::value &&
|
|
||||||
std::is_floating_point<B>::value,
|
|
||||||
bool
|
|
||||||
>
|
|
||||||
almost_equal (const A &a, const B &b)
|
|
||||||
{
|
|
||||||
using common_t = std::common_type_t<A,B>;
|
|
||||||
return almost_equal<common_t> (static_cast<common_t> (a),
|
|
||||||
static_cast<common_t> (b));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
template <typename A, typename B>
|
|
||||||
typename std::enable_if_t<
|
|
||||||
std::is_integral<A>::value &&
|
|
||||||
std::is_integral<B>::value &&
|
|
||||||
std::is_signed<A>::value == std::is_signed<B>::value,
|
|
||||||
bool
|
|
||||||
>
|
|
||||||
almost_equal (const A &a, const B &b) {
|
|
||||||
using common_t = std::common_type_t<A,B>;
|
|
||||||
return static_cast<common_t> (a) == static_cast<common_t> (b);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
template <typename Ta, typename Tb>
|
|
||||||
typename std::enable_if<
|
|
||||||
!std::is_arithmetic<Ta>::value ||
|
|
||||||
!std::is_arithmetic<Tb>::value,
|
|
||||||
bool
|
|
||||||
>::type
|
|
||||||
almost_equal (const Ta &a, const Tb &b)
|
|
||||||
{ return a == b; }
|
|
||||||
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
// Useful for explictly ignore equality warnings
|
|
||||||
#pragma GCC diagnostic push
|
|
||||||
#pragma GCC diagnostic ignored "-Wfloat-equal"
|
|
||||||
template <typename T, typename U>
|
|
||||||
bool
|
|
||||||
exactly_equal (const T &a, const U &b)
|
|
||||||
{ return a == b; }
|
|
||||||
#pragma GCC diagnostic pop
|
|
||||||
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
template <typename T>
|
|
||||||
bool
|
|
||||||
almost_zero (T a)
|
|
||||||
{ return almost_equal (a, T{0}); }
|
|
||||||
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
template <typename T>
|
|
||||||
bool
|
|
||||||
exactly_zero (T a)
|
|
||||||
{ return exactly_equal (a, T{0}); }
|
|
||||||
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
template <typename T>
|
template <typename T>
|
||||||
const T&
|
const T&
|
||||||
|
Loading…
Reference in New Issue
Block a user