3#include <uni20/config.hpp>
23#include <fmt/chrono.h>
27#include <source_location>
36#if UNI20_HAS_STACKTRACE
37#define TRACE_HAS_STACKTRACE 1
40#define TRACE_HAS_STACKTRACE 0
44#define TRACE_DISABLE 0
48#define TRACE_STRINGIZE_IMPL(x) #x
49#define TRACE_STRINGIZE(x) TRACE_STRINGIZE_IMPL(x)
51namespace trace::detail
54[[nodiscard]]
constexpr bool is_constant_evaluation()
noexcept {
return std::is_constant_evaluated(); }
61#define COMPILER_NOTE(msg) __pragma(message(msg))
64#define COMPILER_NOTE(msg) _Pragma(TRACE_STRINGIZE(message msg))
70#if defined(__clang__) || defined(__GNUC__)
71#define COMPILER_WARNING_NOTE(msg) \
74 ([]() __attribute__((deprecated(msg))){})(); \
78#define COMPILER_WARNING_NOTE(msg) \
92 if (::trace::detail::is_constant_evaluation()) \
96 if constexpr (TRACE_DISABLE) \
100 ::trace::TraceCall(#__VA_ARGS__, __FILE__, __LINE__ __VA_OPT__(, __VA_ARGS__)); \
106#define TRACE_IF(cond, ...) \
109 if (::trace::detail::is_constant_evaluation()) \
113 if constexpr (TRACE_DISABLE) \
117 if (::trace::detail::is_constant_evaluation()) \
121 ::trace::TraceCall(#__VA_ARGS__, __FILE__, __LINE__ __VA_OPT__(, __VA_ARGS__)); \
128#define TRACE_ONCE(...) \
131 if (::trace::detail::is_constant_evaluation()) \
135 if constexpr (TRACE_DISABLE) \
139 static std::atomic_flag _trace_once_flag = ATOMIC_FLAG_INIT; \
140 if (!_trace_once_flag.test_and_set(std::memory_order_relaxed)) \
142 ::trace::TraceOnceCall(#__VA_ARGS__, __FILE__, __LINE__ __VA_OPT__(, __VA_ARGS__)); \
149#define TRACE_MODULE(m, ...) \
152 if (::trace::detail::is_constant_evaluation()) \
156 if constexpr (ENABLE_TRACE_##m) \
158 if constexpr (TRACE_DISABLE) \
162 ::trace::TraceModuleCall(#m, #__VA_ARGS__, __FILE__, __LINE__ __VA_OPT__(, __VA_ARGS__)); \
169#define TRACE_MODULE_IF(m, cond, ...) \
172 if (::trace::detail::is_constant_evaluation()) \
176 if constexpr (ENABLE_TRACE_##m) \
180 if constexpr (TRACE_DISABLE) \
184 ::trace::TraceModuleCall(#m, #__VA_ARGS__, __FILE__, __LINE__ __VA_OPT__(, __VA_ARGS__)); \
192#define TRACE_STACK(...) \
195 if (::trace::detail::is_constant_evaluation()) \
199 if constexpr (TRACE_DISABLE) \
203 ::trace::TraceStackCall(#__VA_ARGS__, __FILE__, __LINE__ __VA_OPT__(, __VA_ARGS__)); \
209#define TRACE_IF_STACK(cond, ...) \
212 if (::trace::detail::is_constant_evaluation()) \
216 if constexpr (TRACE_DISABLE) \
220 if (::trace::detail::is_constant_evaluation()) \
224 ::trace::TraceStackCall(#__VA_ARGS__, __FILE__, __LINE__ __VA_OPT__(, __VA_ARGS__)); \
231#define TRACE_ONCE_STACK(...) \
234 if (::trace::detail::is_constant_evaluation()) \
238 if constexpr (TRACE_DISABLE) \
242 static std::atomic_flag _trace_once_stack_flag = ATOMIC_FLAG_INIT; \
243 if (!_trace_once_stack_flag.test_and_set(std::memory_order_relaxed)) \
245 ::trace::TraceStackOnceCall(#__VA_ARGS__, __FILE__, __LINE__ __VA_OPT__(, __VA_ARGS__)); \
252#define TRACE_MODULE_STACK(m, ...) \
255 if (::trace::detail::is_constant_evaluation()) \
259 if constexpr (ENABLE_TRACE_##m) \
261 if constexpr (TRACE_DISABLE) \
265 ::trace::TraceModuleStackCall(#m, #__VA_ARGS__, __FILE__, __LINE__ __VA_OPT__(, __VA_ARGS__)); \
272#define TRACE_MODULE_IF_STACK(m, cond, ...) \
275 if (::trace::detail::is_constant_evaluation()) \
279 if constexpr (ENABLE_TRACE_##m) \
283 if constexpr (TRACE_DISABLE) \
287 ::trace::TraceModuleStackCall(#m, #__VA_ARGS__, __FILE__, __LINE__ __VA_OPT__(, __VA_ARGS__)); \
299#define CHECK(cond, ...) \
304 ::trace::CheckCall(#cond, #__VA_ARGS__, __FILE__, __LINE__ __VA_OPT__(, __VA_ARGS__)); \
309#define CHECK_EQUAL(a, b, ...) \
314 ::trace::CheckEqualCall(#a, #b, (#a "," #b __VA_OPT__("," #__VA_ARGS__)), __FILE__, __LINE__, a, \
315 b __VA_OPT__(, __VA_ARGS__)); \
322#define CHECK_FLOATING_EQ(a, b, ...) \
327 using T = std::decay_t<decltype(va)>; \
328 static_assert(::uni20::check::UlpComparable<T>, "CHECK_FLOATING_EQ requires a ULP-comparable scalar"); \
329 [&](auto const&... extra) \
331 auto const ulps = ::trace::detail::get_ulps(va, vb, extra...); \
332 if (!::uni20::check::FloatingULP<T>::eq(va, vb, ulps)) \
334 ::trace::CheckFloatingEqCall(#a, #b, ulps, (#a "," #b __VA_OPT__("," #__VA_ARGS__)), \
335 __FILE__, __LINE__, va, vb, extra...); \
341#define PRECONDITION(cond, ...) \
346 ::trace::PreconditionCall(#cond, #__VA_ARGS__, __FILE__, __LINE__ __VA_OPT__(, __VA_ARGS__)); \
351#define PRECONDITION_EQUAL(a, b, ...) \
356 ::trace::PreconditionEqualCall(#a, #b, (#a "," #b __VA_OPT__("," #__VA_ARGS__)), __FILE__, __LINE__, a, \
357 b __VA_OPT__(, __VA_ARGS__)); \
362#define PRECONDITION_FLOATING_EQ(a, b, ...) \
367 using T = std::decay_t<decltype(va)>; \
368 static_assert(::uni20::check::UlpComparable<T>, "PRECONDITION_FLOATING_EQ requires a ULP-comparable scalar"); \
369 [&](auto const&... extra) \
371 auto const ulps = ::trace::detail::get_ulps(va, vb, extra...); \
372 if (!::uni20::check::FloatingULP<T>::eq(va, vb, ulps)) \
374 ::trace::PreconditionFloatingEqCall(#a, #b, ulps, (#a "," #b __VA_OPT__("," #__VA_ARGS__)), \
375 __FILE__, __LINE__, va, vb, extra...); \
382#define PANIC(...) trace::PanicCall(#__VA_ARGS__, __FILE__, __LINE__ __VA_OPT__(, __VA_ARGS__));
387#define ERROR(...) trace::ErrorCall(#__VA_ARGS__, __FILE__, __LINE__ __VA_OPT__(, __VA_ARGS__));
389#define ERROR_IF(cond, ...) \
394 ::trace::ErrorIfCall(#cond, #__VA_ARGS__, __FILE__, __LINE__ __VA_OPT__(, __VA_ARGS__)); \
402#define DEBUG_TRACE(...) \
406#define DEBUG_TRACE_IF(...) \
410#define DEBUG_TRACE_ONCE(...) \
414#define DEBUG_TRACE_MODULE(...) \
418#define DEBUG_TRACE_MODULE_IF(...) \
422#define DEBUG_TRACE_STACK(...) \
426#define DEBUG_TRACE_IF_STACK(...) \
430#define DEBUG_TRACE_ONCE_STACK(...) \
434#define DEBUG_TRACE_MODULE_STACK(...) \
438#define DEBUG_TRACE_MODULE_IF_STACK(...) \
442#define DEBUG_CHECK(...) \
446#define DEBUG_CHECK_EQUAL(...) \
450#define DEBUG_CHECK_FLOATING_EQ(...) \
454#define DEBUG_PRECONDITION(...) \
458#define DEBUG_PRECONDITION_EQUAL(...) \
462#define DEBUG_PRECONDITION_FLOATING_EQ(...) \
468#define DEBUG_TRACE(...) \
471 if constexpr (TRACE_DISABLE) \
474 ::trace::DebugTraceCall(#__VA_ARGS__, __FILE__, __LINE__ __VA_OPT__(, __VA_ARGS__)); \
478#define DEBUG_TRACE_IF(cond, ...) \
481 if constexpr (TRACE_DISABLE) \
485 ::trace::DebugTraceCall(#__VA_ARGS__, __FILE__, __LINE__ __VA_OPT__(, __VA_ARGS__)); \
490#define DEBUG_TRACE_ONCE(...) \
493 if (::trace::detail::is_constant_evaluation()) \
497 if constexpr (TRACE_DISABLE) \
501 static std::atomic_flag _trace_once_flag = ATOMIC_FLAG_INIT; \
502 if (!_trace_once_flag.test_and_set(std::memory_order_relaxed)) \
504 ::trace::DebugTraceOnceCall(#__VA_ARGS__, __FILE__, __LINE__ __VA_OPT__(, __VA_ARGS__)); \
511#define DEBUG_TRACE_MODULE(m, ...) \
514 if constexpr (TRACE_DISABLE) \
516 else if constexpr (ENABLE_TRACE_##m) \
518 ::trace::DebugTraceModuleCall(#m, #__VA_ARGS__, __FILE__, __LINE__ __VA_OPT__(, __VA_ARGS__)); \
523#define DEBUG_TRACE_MODULE_IF(m, cond, ...) \
526 if constexpr (TRACE_DISABLE) \
528 else if constexpr (ENABLE_TRACE_##m) \
532 ::trace::DebugTraceModuleCall(#m, #__VA_ARGS__, __FILE__, __LINE__ __VA_OPT__(, __VA_ARGS__)); \
538#define DEBUG_TRACE_STACK(...) \
541 if constexpr (TRACE_DISABLE) \
544 ::trace::DebugTraceStackCall(#__VA_ARGS__, __FILE__, __LINE__ __VA_OPT__(, __VA_ARGS__)); \
548#define DEBUG_TRACE_IF_STACK(cond, ...) \
551 if constexpr (TRACE_DISABLE) \
555 ::trace::DebugTraceStackCall(#__VA_ARGS__, __FILE__, __LINE__ __VA_OPT__(, __VA_ARGS__)); \
560#define DEBUG_TRACE_ONCE_STACK(...) \
563 if (::trace::detail::is_constant_evaluation()) \
567 if constexpr (TRACE_DISABLE) \
571 static std::atomic_flag _debug_trace_once_stack_flag = ATOMIC_FLAG_INIT; \
572 if (!_debug_trace_once_stack_flag.test_and_set(std::memory_order_relaxed)) \
574 ::trace::DebugTraceStackOnceCall(#__VA_ARGS__, __FILE__, __LINE__ __VA_OPT__(, __VA_ARGS__)); \
581#define DEBUG_TRACE_MODULE_STACK(m, ...) \
584 if constexpr (TRACE_DISABLE) \
586 else if constexpr (ENABLE_TRACE_##m) \
588 ::trace::DebugTraceModuleStackCall(#m, #__VA_ARGS__, __FILE__, __LINE__ __VA_OPT__(, __VA_ARGS__)); \
593#define DEBUG_TRACE_MODULE_IF_STACK(m, cond, ...) \
596 if constexpr (TRACE_DISABLE) \
598 else if constexpr (ENABLE_TRACE_##m) \
602 ::trace::DebugTraceModuleStackCall(#m, #__VA_ARGS__, __FILE__, __LINE__ __VA_OPT__(, __VA_ARGS__)); \
608#define DEBUG_CHECK(cond, ...) \
613 ::trace::DebugCheckCall(#cond, #__VA_ARGS__, __FILE__, __LINE__ __VA_OPT__(, __VA_ARGS__)); \
618#define DEBUG_CHECK_EQUAL(a, b, ...) \
623 ::trace::DebugCheckEqualCall(#a, #b, (#a "," #b __VA_OPT__("," #__VA_ARGS__)), __FILE__, __LINE__, a, \
624 b __VA_OPT__(, __VA_ARGS__)); \
629#define DEBUG_CHECK_FLOATING_EQ(a, b, ...) \
634 using T = std::decay_t<decltype(va)>; \
635 static_assert(::uni20::check::UlpComparable<T>, "DEBUG_CHECK_FLOATING_EQ requires a ULP-comparable scalar"); \
636 [&](auto const&... extra) \
638 auto const ulps = ::trace::detail::get_ulps(va, vb, extra...); \
639 if (!::uni20::check::FloatingULP<T>::eq(va, vb, ulps)) \
641 ::trace::DebugCheckFloatingEqCall(#a, #b, ulps, (#a "," #b __VA_OPT__("," #__VA_ARGS__)), \
642 __FILE__, __LINE__, va, vb, extra...); \
648#define DEBUG_PRECONDITION(cond, ...) \
653 ::trace::DebugPreconditionCall(#cond, #__VA_ARGS__, __FILE__, __LINE__ __VA_OPT__(, __VA_ARGS__)); \
658#define DEBUG_PRECONDITION_EQUAL(a, b, ...) \
663 ::trace::DebugPreconditionEqualCall(#a, #b, (#a "," #b __VA_OPT__("," #__VA_ARGS__)), __FILE__, __LINE__, a, \
664 b __VA_OPT__(, __VA_ARGS__)); \
669#define DEBUG_PRECONDITION_FLOATING_EQ(a, b, ...) \
674 using T = std::decay_t<decltype(va)>; \
675 static_assert(::uni20::check::UlpComparable<T>, "DEBUG_PRECONDITION_FLOATING_EQ requires a ULP-comparable scalar"); \
676 [&](auto const&... extra) \
678 auto const ulps = ::trace::detail::get_ulps(va, vb, extra...); \
679 if (!::uni20::check::FloatingULP<T>::eq(va, vb, ulps)) \
681 ::trace::DebugPreconditionFloatingEqCall(#a, #b, ulps, (#a "," #b __VA_OPT__("," #__VA_ARGS__)), \
682 __FILE__, __LINE__, va, vb, extra...); \
710 for (
size_t i = 0; i < N; ++i)
714 constexpr operator std::string_view()
const {
return {
value, N - 1}; }
727 Derived
const*
This() const noexcept {
return static_cast<Derived const*
>(
this); }
728 Derived*
This() noexcept {
return static_cast<Derived*
>(
this); }
735 return detail::TraceNameValue(
"other", fmt::format(
"{:p}", fmt::ptr(x)));
739 return detail::TraceNameValue(
"this", fmt::format(
"{:p}", fmt::ptr(
this)));
792#define TRACE_BASE_CLASS(Name) trace::TracingBaseClass<trace::BaseName(TRACE_STRINGIZE(Name)), Name>
Structured exception base carrying diagnostic source context.
std::string demangle(const char *name)
Turn a compiler‐mangled name into a human‐readable one.
Definition demangle.hpp:22
Presentation-layer formatting for standard stacktraces.
Compile-time string wrapper for use as a non-type template parameter.
Definition trace.hpp:704
constexpr BaseName(const char(&str)[N])
Construct from a string literal.
Definition trace.hpp:708
char value[N]
The wrapped string literal.
Definition trace.hpp:705
CRTP tracing base class that emits messages with demangled type name.
Definition trace.hpp:725
TracingBaseClass(const TracingBaseClass &other)
Copy constructor. Emits a trace message.
Definition trace.hpp:751
~TracingBaseClass()
Destructor. Emits a trace message.
Definition trace.hpp:789
TracingBaseClass(Args &&... args)
Definition trace.hpp:745
Derived const * This() const noexcept
Get this pointer as Derived* (for CRTP usage).
Definition trace.hpp:727
std::string DerivedName() const
Get demangled class name of the CRTP derived class.
Definition trace.hpp:731
Derived * This() noexcept
Definition trace.hpp:728
TracingBaseClass(Derived &&other) noexcept
Move constructor. Emits a trace message.
Definition trace.hpp:763
TracingBaseClass & operator=(const TracingBaseClass &other)
Copy assignment. Emits a trace message.
Definition trace.hpp:769
detail::TraceNameValue OtherPointer(T *x) const
Definition trace.hpp:733
detail::TraceNameValue ThisPointer() const
Definition trace.hpp:737
TracingBaseClass()
Default constructor. Emits a trace message.
Definition trace.hpp:743
TracingBaseClass(TracingBaseClass &&other) noexcept
Move constructor. Emits a trace message.
Definition trace.hpp:757
TracingBaseClass & operator=(TracingBaseClass &&other) noexcept
Move assignment. Emits a trace message.
Definition trace.hpp:779
#define TRACE(...)
Definition trace.hpp:89