#pragma once #include "demangle.h" #include "getThreadId.h" #include #include #include #include /** Usage: * * DUMP(variable...) */ template Out & dumpValue(Out &, T &&); /// Catch-all case. template std::enable_if_t & dumpImpl(Out & out, T &&) { return out << "{...}"; } /// An object, that could be output with operator <<. template std::enable_if_t & dumpImpl(Out & out, T && x, std::decay_t() << std::declval())> * = nullptr) { return out << x; } /// A pointer-like object. template std::enable_if_t, std::decay_t())>> , Out> & dumpImpl(Out & out, T && x, std::decay_t())> * = nullptr) { if (!x) return out << "nullptr"; return dumpValue(out, *x); } /// Container. template std::enable_if_t & dumpImpl(Out & out, T && x, std::decay_t()))> * = nullptr) { bool first = true; out << "{"; for (const auto & elem : x) { if (first) first = false; else out << ", "; dumpValue(out, elem); } return out << "}"; } /// string and const char * - output not as container or pointer. template std::enable_if_t, std::string> || std::is_same_v, const char *>), Out> & dumpImpl(Out & out, T && x) { return out << std::quoted(x); } /// UInt8 - output as number, not char. template std::enable_if_t, unsigned char>, Out> & dumpImpl(Out & out, T && x) { return out << int(x); } /// Tuple, pair template Out & dumpTupleImpl(Out & out, T && x) { if constexpr (N == 0) out << "{"; else out << ", "; dumpValue(out, std::get(x)); if constexpr (N + 1 == std::tuple_size_v>) out << "}"; else dumpTupleImpl(out, x); return out; } template std::enable_if_t & dumpImpl(Out & out, T && x, std::decay_t(std::declval()))> * = nullptr) { return dumpTupleImpl<0>(out, x); } template Out & dumpDispatchPriorities(Out & out, T && x, std::decay_t(std::declval(), std::declval()))> *) { return dumpImpl(out, x); } struct LowPriority { LowPriority(void *) {} }; template Out & dumpDispatchPriorities(Out & out, T && x, LowPriority) { return dumpDispatchPriorities(out, x, nullptr); } template Out & dumpValue(Out & out, T && x) { return dumpDispatchPriorities<5>(out, x, nullptr); } template Out & dump(Out & out, const char * name, T && x) { out << demangle(typeid(x).name()) << " " << name << " = "; return dumpValue(out, x); } #ifdef __clang__ #pragma clang diagnostic ignored "-Wgnu-zero-variadic-macro-arguments" #endif #define DUMPVAR(VAR) ::dump(std::cerr, #VAR, (VAR)); std::cerr << "; "; #define DUMPHEAD std::cerr << __FILE__ << ':' << __LINE__ << " [ " << getThreadId() << " ] "; #define DUMPTAIL std::cerr << '\n'; #define DUMP1(V1) do { DUMPHEAD DUMPVAR(V1) DUMPTAIL } while(0) #define DUMP2(V1, V2) do { DUMPHEAD DUMPVAR(V1) DUMPVAR(V2) DUMPTAIL } while(0) #define DUMP3(V1, V2, V3) do { DUMPHEAD DUMPVAR(V1) DUMPVAR(V2) DUMPVAR(V3) DUMPTAIL } while(0) #define DUMP4(V1, V2, V3, V4) do { DUMPHEAD DUMPVAR(V1) DUMPVAR(V2) DUMPVAR(V3) DUMPVAR(V4) DUMPTAIL } while(0) #define DUMP5(V1, V2, V3, V4, V5) do { DUMPHEAD DUMPVAR(V1) DUMPVAR(V2) DUMPVAR(V3) DUMPVAR(V4) DUMPVAR(V5) DUMPTAIL } while(0) #define DUMP6(V1, V2, V3, V4, V5, V6) do { DUMPHEAD DUMPVAR(V1) DUMPVAR(V2) DUMPVAR(V3) DUMPVAR(V4) DUMPVAR(V5) DUMPVAR(V6) DUMPTAIL } while(0) #define DUMP7(V1, V2, V3, V4, V5, V6, V7) do { DUMPHEAD DUMPVAR(V1) DUMPVAR(V2) DUMPVAR(V3) DUMPVAR(V4) DUMPVAR(V5) DUMPVAR(V6) DUMPVAR(V7) DUMPTAIL } while(0) #define DUMP8(V1, V2, V3, V4, V5, V6, V7, V8) do { DUMPHEAD DUMPVAR(V1) DUMPVAR(V2) DUMPVAR(V3) DUMPVAR(V4) DUMPVAR(V5) DUMPVAR(V6) DUMPVAR(V7) DUMPVAR(V8) DUMPTAIL } while(0) #define DUMP9(V1, V2, V3, V4, V5, V6, V7, V8, V9) do { DUMPHEAD DUMPVAR(V1) DUMPVAR(V2) DUMPVAR(V3) DUMPVAR(V4) DUMPVAR(V5) DUMPVAR(V6) DUMPVAR(V7) DUMPVAR(V8) DUMPVAR(V9) DUMPTAIL } while(0) /// https://groups.google.com/forum/#!searchin/kona-dev/variadic$20macro%7Csort:date/kona-dev/XMA-lDOqtlI/GCzdfZsD41sJ #define VA_NUM_ARGS_IMPL(x1, x2, x3, x4, x5, x6, x7, x8, x9, N, ...) N #define VA_NUM_ARGS(...) VA_NUM_ARGS_IMPL(__VA_ARGS__, 9, 8, 7, 6, 5, 4, 3, 2, 1) #define MAKE_VAR_MACRO_IMPL_CONCAT(PREFIX, NUM_ARGS) PREFIX ## NUM_ARGS #define MAKE_VAR_MACRO_IMPL(PREFIX, NUM_ARGS) MAKE_VAR_MACRO_IMPL_CONCAT(PREFIX, NUM_ARGS) #define MAKE_VAR_MACRO(PREFIX, ...) MAKE_VAR_MACRO_IMPL(PREFIX, VA_NUM_ARGS(__VA_ARGS__)) #define DUMP(...) MAKE_VAR_MACRO(DUMP, __VA_ARGS__)(__VA_ARGS__)