debug: don't rely on format for output
debug is relied upon by a great deal of other units so it's very difficult to include other popular headers like format.hpp without triggering cyclic dependencies.
This commit is contained in:
parent
06e29ed136
commit
4116442e40
@ -11,13 +11,14 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* Copyright 2015 Danny Robson <danny@nerdcruft.net>
|
||||
* Copyright 2015-2018 Danny Robson <danny@nerdcruft.net>
|
||||
*/
|
||||
|
||||
#ifndef __UTIL_ALLOC_ARENA_HPP
|
||||
#define __UTIL_ALLOC_ARENA_HPP
|
||||
#ifndef CRUFT_UTIL_ALLOC_ARENA_HPP
|
||||
#define CRUFT_UTIL_ALLOC_ARENA_HPP
|
||||
|
||||
#include "../memory/deleter.hpp"
|
||||
#include "../cast.hpp"
|
||||
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
|
439
debug.hpp
439
debug.hpp
@ -14,8 +14,7 @@
|
||||
* Copyright 2010-2017 Danny Robson <danny@nerdcruft.net>
|
||||
*/
|
||||
|
||||
#ifndef __DEBUG_HPP
|
||||
#define __DEBUG_HPP
|
||||
#pragma once
|
||||
|
||||
//#include "maths.hpp" // XXX: See notes at the end of file for maths.hpp inclusion
|
||||
#include <cmath>
|
||||
@ -23,7 +22,8 @@
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <iostream>
|
||||
#include <iosfwd>
|
||||
#include <sstream>
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
@ -47,6 +47,7 @@
|
||||
/// refer to variables which do not always exist, and current compiler
|
||||
/// implementations are a little picky here.
|
||||
#ifndef NDEBUG
|
||||
#include <iostream>
|
||||
#define DEBUG_ONLY(X) do { X; } while (0)
|
||||
#else
|
||||
#define DEBUG_ONLY(X) do { ; } while (0)
|
||||
@ -62,26 +63,34 @@
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#define TRACE { \
|
||||
DEBUG_ONLY ( \
|
||||
std::clog << "tid: " << std::this_thread::get_id () << "; " << __FILE__ << ":" << __func__ << ":" << __LINE__ << std::endl; \
|
||||
); \
|
||||
#define TRACE { \
|
||||
DEBUG_ONLY ( \
|
||||
std::cerr << "tid: " << std::this_thread::get_id () \
|
||||
<< "; " << __FILE__ \
|
||||
<< ":" << __func__ \
|
||||
<< ":" << __LINE__ \
|
||||
<< '\n'; \
|
||||
); \
|
||||
}
|
||||
|
||||
|
||||
#define WARN(C) do { \
|
||||
DEBUG_ONLY ( \
|
||||
if (C) { \
|
||||
std::cerr << __FILE__ << ":" << __func__ << ":" << __LINE__ << ", " << #C << std::endl; \
|
||||
} \
|
||||
); \
|
||||
#define WARN(C) do { \
|
||||
DEBUG_ONLY ( \
|
||||
if (C) { \
|
||||
std::cerr << __FILE__ \
|
||||
<< ":" << __func__ \
|
||||
<< ":" << __LINE__ \
|
||||
<< ", " << #C \
|
||||
<< '\n'; \
|
||||
} \
|
||||
); \
|
||||
} while (0)
|
||||
|
||||
|
||||
#define WARN_RETURN(CONDITION,VALUE) do { \
|
||||
if (const auto& __warn_return = (CONDITION); !!__warn_return) { \
|
||||
if constexpr (debug_enabled) { \
|
||||
std::clog << __FILE__ << ':' \
|
||||
std::cerr << __FILE__ << ':' \
|
||||
<< __LINE__ << ':' \
|
||||
<< __PRETTY_FUNCTION__ << "; " \
|
||||
<< #CONDITION << '\n'; \
|
||||
@ -96,7 +105,7 @@
|
||||
#define RETURN_UNLESS(VALUE,CONDITION) do { \
|
||||
if (const auto &__return_unless = (CONDITION); !__return_unless) { \
|
||||
if constexpr (debug_enabled) { \
|
||||
std::clog << __FILE__ << ':' \
|
||||
std::cerr << __FILE__ << ':' \
|
||||
<< __LINE__ << ':' \
|
||||
<< __PRETTY_FUNCTION__ << "; " \
|
||||
<< #CONDITION << '\n'; \
|
||||
@ -108,14 +117,6 @@
|
||||
} while (0)
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#define _CHECK_PANIC(FMT,...) do { \
|
||||
panic ("%s:%s:%i:%s\n" FMT, \
|
||||
PACKAGE, __FILE__, __LINE__, __func__, \
|
||||
__VA_ARGS__); \
|
||||
} while(0)
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#define CHECK(C) do { \
|
||||
DEBUG_ONLY ( \
|
||||
@ -142,176 +143,156 @@
|
||||
const auto &__b = (B); \
|
||||
\
|
||||
if (!::util::almost_equal (__a, __b)) { \
|
||||
_CHECK_PANIC("expected equality\n" \
|
||||
"__a: %s is %!\n" \
|
||||
"__b: %s is %!\n", \
|
||||
#A, __a, \
|
||||
#B, __b); \
|
||||
std::cerr << "expected equality\n" \
|
||||
"__a: " #A " is " << __a << "\n" \
|
||||
"__b: " #B " is " << __b << "\n"; \
|
||||
} \
|
||||
); \
|
||||
} while (0)
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#define CHECK_LT(A,B) do { \
|
||||
DEBUG_ONLY ( \
|
||||
const auto &__a = (A); \
|
||||
const auto &__b = (B); \
|
||||
\
|
||||
if (__a >= __b) { \
|
||||
_CHECK_PANIC("expected less than\n" \
|
||||
"__a: %s is %!\n" \
|
||||
"__b: %s is %!\n", \
|
||||
#A, __a, \
|
||||
#B, __b); \
|
||||
}; \
|
||||
); \
|
||||
} while (0)
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#define CHECK_LE(A,B) do { \
|
||||
DEBUG_ONLY ( \
|
||||
const auto &__a = (A); \
|
||||
const auto &__b = (B); \
|
||||
\
|
||||
if (__a > __b) { \
|
||||
_CHECK_PANIC("expected less than or equal\n" \
|
||||
"__a: %s is %!\n" \
|
||||
"__b: %s is %!\n", \
|
||||
#A, __a, \
|
||||
#B, __b); \
|
||||
} \
|
||||
); \
|
||||
} while (0)
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#define CHECK_GT(A,B) do { \
|
||||
DEBUG_ONLY ( \
|
||||
const auto &__a = (A); \
|
||||
const auto &__b = (B); \
|
||||
\
|
||||
if (__a <= __b) { \
|
||||
_CHECK_PANIC ("expected greater than\n" \
|
||||
"__a: %s is %!\n" \
|
||||
"__b: %s is %!\n", \
|
||||
#A, __a, \
|
||||
#B, __b); \
|
||||
} \
|
||||
); \
|
||||
} while (0)
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#define CHECK_GE(A,B) do { \
|
||||
DEBUG_ONLY ( \
|
||||
const auto &__a = (A); \
|
||||
const auto &__b = (B); \
|
||||
\
|
||||
if (__a < __b) { \
|
||||
_CHECK_PANIC ("expected greater or equal\n" \
|
||||
"__a: %s is %!\n" \
|
||||
"__b: %s is %!\n", \
|
||||
#A, __a, \
|
||||
#B, __b); \
|
||||
}; \
|
||||
); \
|
||||
} while (0)
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#define CHECK_LIMIT(V,L,H) do { \
|
||||
DEBUG_ONLY ( \
|
||||
const auto &__v = (V); \
|
||||
const auto &__l = (L); \
|
||||
const auto &__h = (H); \
|
||||
\
|
||||
if (__v < __l || __v > __h) { \
|
||||
_CHECK_PANIC ("expected limit\n" \
|
||||
"__l: %s is %!\n" \
|
||||
"__h: %s is %!\n" \
|
||||
"__v: %s is %!\n", \
|
||||
#L, __l, \
|
||||
#H, __h, \
|
||||
#V, __v); \
|
||||
}; \
|
||||
); \
|
||||
} while (0)
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#define CHECK_NEQ(A,B) do { \
|
||||
DEBUG_ONLY( \
|
||||
const auto &__a = (A); \
|
||||
const auto &__b = (B); \
|
||||
\
|
||||
if (::util::almost_equal (__a, __b)) { \
|
||||
_CHECK_PANIC ("expected inequality\n" \
|
||||
"__a: %s is %!\n" \
|
||||
"__b: %s is %!\n", \
|
||||
#A, __a, \
|
||||
#B, __b); \
|
||||
}; \
|
||||
); \
|
||||
} while (0)
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#define CHECK_ZERO(A) do { \
|
||||
DEBUG_ONLY ( \
|
||||
const auto &__a = (A); \
|
||||
\
|
||||
if (!::util::almost_zero (__a)) { \
|
||||
_CHECK_PANIC ("expected zero\n" \
|
||||
"__a: %s is %!\n" \
|
||||
#A, __a); \
|
||||
}; \
|
||||
); \
|
||||
} while (0)
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#define CHECK_NEZ(A) do { \
|
||||
DEBUG_ONLY ( \
|
||||
const auto &__a = (A); \
|
||||
\
|
||||
if (::util::exactly_zero (__a)) \
|
||||
_CHECK_PANIC ("expected non-zero\n" \
|
||||
"__a: %s is %!", \
|
||||
#A, __a); \
|
||||
); \
|
||||
} while (0)
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#define CHECK_MOD(V,M) do { \
|
||||
#define CHECK_LT(A,B) do { \
|
||||
DEBUG_ONLY ( \
|
||||
const auto &__check_mod_v = (V); \
|
||||
const auto &__check_mod_m = (M); \
|
||||
const auto &__a = (A); \
|
||||
const auto &__b = (B); \
|
||||
\
|
||||
if (!::util::exactly_zero (__check_mod_v % __check_mod_m)) \
|
||||
_CHECK_PANIC ("expected zero modulus\n" \
|
||||
"__v: %s is %!\n" \
|
||||
"__m: %s is %!", \
|
||||
#V, __check_mod_v, \
|
||||
#M, __check_mod_m); \
|
||||
if (__a >= __b) { \
|
||||
std::cerr << "expected less than\n" \
|
||||
"__a: " << #A << " is " << __a << "\n" \
|
||||
"__b: " << #B << " is " << __b << "\n"; \
|
||||
}; \
|
||||
); \
|
||||
} while (0)
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#define CHECK_LE(A,B) do { \
|
||||
DEBUG_ONLY ( \
|
||||
const auto &__a = (A); \
|
||||
const auto &__b = (B); \
|
||||
\
|
||||
if (__a > __b) { \
|
||||
std::cerr << "expected less than or equal\n" \
|
||||
"__a: " << #A << " is " << __a << "\n" \
|
||||
"__b: " << #B << " is " << __b << "\n"; \
|
||||
} \
|
||||
); \
|
||||
} while (0)
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#define CHECK_GT(A,B) do { \
|
||||
DEBUG_ONLY ( \
|
||||
const auto &__a = (A); \
|
||||
const auto &__b = (B); \
|
||||
\
|
||||
if (__a <= __b) { \
|
||||
std::cerr << "expected greater than\n" \
|
||||
"__a: " << #A << " is " << __a << "\n" \
|
||||
"__b: " << #B << " is " << __b << "\n"; \
|
||||
} \
|
||||
); \
|
||||
} while (0)
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#define CHECK_GE(A,B) do { \
|
||||
DEBUG_ONLY ( \
|
||||
const auto &__a = (A); \
|
||||
const auto &__b = (B); \
|
||||
\
|
||||
if (__a < __b) { \
|
||||
std::cerr << "expected greater or equal\n" \
|
||||
"__a: " << #A << " is " << __a << "\n" \
|
||||
"__b: " << #B << " is " << __b << "\n"; \
|
||||
}; \
|
||||
); \
|
||||
} while (0)
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#define CHECK_LIMIT(V,L,H) do { \
|
||||
DEBUG_ONLY ( \
|
||||
const auto &__v = (V); \
|
||||
const auto &__l = (L); \
|
||||
const auto &__h = (H); \
|
||||
\
|
||||
if (__v < __l || __v > __h) { \
|
||||
std::cerr << "expected limit\n" \
|
||||
"__l: " << #L << " is " << +__l << "\n" \
|
||||
"__h: " << #H << " is " << +__h << "\n" \
|
||||
"__v: " << #V << " is " << +__v << "\n"; \
|
||||
}; \
|
||||
); \
|
||||
} while (0)
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#define CHECK_NEQ(A,B) do { \
|
||||
DEBUG_ONLY( \
|
||||
const auto &__a = (A); \
|
||||
const auto &__b = (B); \
|
||||
\
|
||||
if (::util::almost_equal (__a, __b)) { \
|
||||
std::cerr << "expected inequality\n" \
|
||||
"__a: " << #A << " is " << __a << "\n" \
|
||||
"__b: " << #B << " is " << __b << "\n"; \
|
||||
}; \
|
||||
); \
|
||||
} while (0)
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#define CHECK_ZERO(A) do { \
|
||||
DEBUG_ONLY ( \
|
||||
const auto &__a = (A); \
|
||||
\
|
||||
if (!::util::almost_zero (__a)) { \
|
||||
std::cerr << "expected zero\n" \
|
||||
"__a: " << #A << " is " << __a << "\n"; \
|
||||
}; \
|
||||
); \
|
||||
} while (0)
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#define CHECK_NEZ(A) do { \
|
||||
DEBUG_ONLY ( \
|
||||
const auto &__a = (A); \
|
||||
\
|
||||
if (::util::exactly_zero (__a)) \
|
||||
std::cerr << "expected non-zero\n" \
|
||||
"__a: " << #A << " is " << __a << '\n'; \
|
||||
); \
|
||||
} while (0)
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#define CHECK_MOD(V,M) do { \
|
||||
DEBUG_ONLY ( \
|
||||
const auto &__check_mod_v = (V); \
|
||||
const auto &__check_mod_m = (M); \
|
||||
\
|
||||
if (!::util::exactly_zero (__check_mod_v % __check_mod_m)) \
|
||||
std::cerr << "expected zero modulus\n" \
|
||||
"__v: " << #V << " is " << __check_mod_v << "\n" \
|
||||
"__m: " << #M << " is " << __check_mod_m << "\n"; \
|
||||
); \
|
||||
} while (0)
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#if defined(ENABLE_DEBUGGING)
|
||||
#define CHECK_ENUM(C, ...) do { \
|
||||
const auto &__c = (C); \
|
||||
const auto &__e = { __VA_ARGS__ }; \
|
||||
\
|
||||
if (std::find (std::cbegin (__e), \
|
||||
std::cend (__e), \
|
||||
__c) == std::end (__e)) { \
|
||||
_CHECK_PANIC("expect enum\n" \
|
||||
"__c: %s is %!", \
|
||||
#C, __c); \
|
||||
} \
|
||||
#define CHECK_ENUM(C, ...) do { \
|
||||
const auto &__c = (C); \
|
||||
const auto &__e = { __VA_ARGS__ }; \
|
||||
\
|
||||
if (std::find (std::cbegin (__e), \
|
||||
std::cend (__e), \
|
||||
__c) == std::end (__e)) { \
|
||||
std::cerr << "expect enum\n" \
|
||||
"__c: " << #C << " is " << __c << '\n'; \
|
||||
} \
|
||||
} while (0)
|
||||
#else
|
||||
#define CHECK_ENUM(C,...)
|
||||
@ -319,13 +300,12 @@
|
||||
|
||||
|
||||
#if !defined(NDEBUG)
|
||||
#define CHECK_FINITE(V) do { \
|
||||
const auto &__v = (V); \
|
||||
if (!std::isfinite (__v)) { \
|
||||
_CHECK_PANIC ("expected finite value\n" \
|
||||
"__v: %! is %!", \
|
||||
#V, __v); \
|
||||
} \
|
||||
#define CHECK_FINITE(V) do { \
|
||||
const auto &__v = (V); \
|
||||
if (!std::isfinite (__v)) { \
|
||||
std::cerr << "expected finite value\n" \
|
||||
"__v: " << #V << " is " << __v << '\n'; \
|
||||
} \
|
||||
} while (0)
|
||||
#else
|
||||
#define CHECK_FINITE(V,...)
|
||||
@ -335,34 +315,32 @@
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#define CHECK_THROWS(E,C) do { \
|
||||
DEBUG_ONLY ( \
|
||||
bool caught = false; \
|
||||
\
|
||||
try \
|
||||
{ C; } \
|
||||
catch (E const&) \
|
||||
{ caught = true; } \
|
||||
\
|
||||
if (!caught) \
|
||||
_CHECK_PANIC ("expected exception: %s", #E); \
|
||||
); \
|
||||
#define CHECK_THROWS(E,C) do { \
|
||||
DEBUG_ONLY ( \
|
||||
bool caught = false; \
|
||||
\
|
||||
try \
|
||||
{ C; } \
|
||||
catch (E const&) \
|
||||
{ caught = true; } \
|
||||
\
|
||||
if (!caught) \
|
||||
std::cerr << "expected exception: " << #E << '\n' \
|
||||
); \
|
||||
} while (0)
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#define CHECK_NOTHROW(C) do { \
|
||||
DEBUG_ONLY ( \
|
||||
try { \
|
||||
C; \
|
||||
} catch (const std::exception &e) { \
|
||||
_CHECK_PANIC ("unexpected exception: %s", \
|
||||
e.what ()); \
|
||||
} catch (...) { \
|
||||
_CHECK_PANIC ("unexpected exception: %s", \
|
||||
"unknown"); \
|
||||
} \
|
||||
); \
|
||||
#define CHECK_NOTHROW(C) do { \
|
||||
DEBUG_ONLY ( \
|
||||
try { \
|
||||
C; \
|
||||
} catch (const std::exception &e) { \
|
||||
std::cerr << "unexpected exception: " << e.what () << '\n'; \
|
||||
} catch (...) { \
|
||||
std::cerr << "unexpected exception: unknown\n"; \
|
||||
} \
|
||||
); \
|
||||
} while (0)
|
||||
|
||||
|
||||
@ -434,23 +412,14 @@ void breakpoint (void);
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#include "log.hpp"
|
||||
#include "backtrace.hpp"
|
||||
|
||||
|
||||
namespace util::debug::detail {
|
||||
void panic [[noreturn]] (const char *msg);
|
||||
void
|
||||
panic [[noreturn]] (const char *msg);
|
||||
|
||||
template <typename ...Args, size_t N>
|
||||
void panic [[noreturn]] (const char (&fmt)[N], const Args& ...args)
|
||||
{
|
||||
LOG_EMERGENCY (fmt, args...);
|
||||
LOG_EMERGENCY ("%!", ::debug::backtrace ());
|
||||
breakpoint ();
|
||||
abort ();
|
||||
}
|
||||
|
||||
void not_implemented [[noreturn]] (const char *msg);
|
||||
|
||||
|
||||
void unreachable [[noreturn]] (const char *msg);
|
||||
}
|
||||
|
||||
@ -465,11 +434,10 @@ panic [[noreturn]] (const char *msg)
|
||||
}
|
||||
|
||||
|
||||
template <typename ...Args, size_t N>
|
||||
constexpr void
|
||||
panic [[noreturn]] (const char (&fmt)[N], const Args&... args)
|
||||
inline void
|
||||
panic [[noreturn]] (const std::string &msg)
|
||||
{
|
||||
util::debug::detail::panic (fmt, args...);
|
||||
panic (msg.c_str ());
|
||||
}
|
||||
|
||||
|
||||
@ -530,11 +498,23 @@ unreachable [[noreturn]] (void)
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
/// report a fatal error induced by an unhandled value, especially in switch
|
||||
/// statements. will almost invariably abort the application.
|
||||
namespace util::debug::detail {
|
||||
template <typename T>
|
||||
void
|
||||
unhandled [[noreturn]] (T &&t) noexcept
|
||||
{
|
||||
std::ostringstream os;
|
||||
os << "unhandled value: " << t << '\n';
|
||||
::panic (os.str ());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template <typename T>
|
||||
constexpr void
|
||||
unhandled [[noreturn]] (T &&t) noexcept
|
||||
{
|
||||
panic ("unhandled value %!", std::forward<T> (t));
|
||||
util::debug::detail::unhandled (std::forward<T> (t));
|
||||
}
|
||||
|
||||
|
||||
@ -648,6 +628,3 @@ namespace util::debug {
|
||||
// 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.
|
||||
#include "maths.hpp"
|
||||
|
||||
|
||||
#endif // __DEBUG_HPP
|
||||
|
@ -19,6 +19,7 @@
|
||||
|
||||
|
||||
#include "version.hpp"
|
||||
#include "maths.hpp"
|
||||
|
||||
#include <cstring>
|
||||
#include <stdexcept>
|
||||
|
Loading…
Reference in New Issue
Block a user