1 | #pragma once |
2 | |
3 | #include "demangle.h" |
4 | #include "getThreadNumber.h" |
5 | #include <type_traits> |
6 | #include <tuple> |
7 | #include <iomanip> |
8 | #include <iostream> |
9 | |
10 | /** Usage: |
11 | * |
12 | * DUMP(variable...) |
13 | */ |
14 | |
15 | |
16 | template <typename Out, typename T> |
17 | Out & dumpValue(Out &, T &&); |
18 | |
19 | |
20 | /// Catch-all case. |
21 | template <int priority, typename Out, typename T> |
22 | std::enable_if_t<priority == -1, Out> & dumpImpl(Out & out, T &&) |
23 | { |
24 | return out << "{...}" ; |
25 | } |
26 | |
27 | /// An object, that could be output with operator <<. |
28 | template <int priority, typename Out, typename T> |
29 | std::enable_if_t<priority == 0, Out> & dumpImpl(Out & out, T && x, std::decay_t<decltype(std::declval<Out &>() << std::declval<T>())> * = nullptr) |
30 | { |
31 | return out << x; |
32 | } |
33 | |
34 | /// A pointer-like object. |
35 | template <int priority, typename Out, typename T> |
36 | std::enable_if_t<priority == 1 |
37 | /// Protect from the case when operator * do effectively nothing (function pointer). |
38 | && !std::is_same_v<std::decay_t<T>, std::decay_t<decltype(*std::declval<T>())>> |
39 | , Out> & dumpImpl(Out & out, T && x, std::decay_t<decltype(*std::declval<T>())> * = nullptr) |
40 | { |
41 | if (!x) |
42 | return out << "nullptr" ; |
43 | return dumpValue(out, *x); |
44 | } |
45 | |
46 | /// Container. |
47 | template <int priority, typename Out, typename T> |
48 | std::enable_if_t<priority == 2, Out> & dumpImpl(Out & out, T && x, std::decay_t<decltype(std::begin(std::declval<T>()))> * = nullptr) |
49 | { |
50 | bool first = true; |
51 | out << "{" ; |
52 | for (const auto & elem : x) |
53 | { |
54 | if (first) |
55 | first = false; |
56 | else |
57 | out << ", " ; |
58 | dumpValue(out, elem); |
59 | } |
60 | return out << "}" ; |
61 | } |
62 | |
63 | |
64 | /// string and const char * - output not as container or pointer. |
65 | |
66 | template <int priority, typename Out, typename T> |
67 | std::enable_if_t<priority == 3 && (std::is_same_v<std::decay_t<T>, std::string> || std::is_same_v<std::decay_t<T>, const char *>), Out> & |
68 | dumpImpl(Out & out, T && x) |
69 | { |
70 | return out << std::quoted(x); |
71 | } |
72 | |
73 | /// UInt8 - output as number, not char. |
74 | |
75 | template <int priority, typename Out, typename T> |
76 | std::enable_if_t<priority == 3 && std::is_same_v<std::decay_t<T>, unsigned char>, Out> & |
77 | dumpImpl(Out & out, T && x) |
78 | { |
79 | return out << int(x); |
80 | } |
81 | |
82 | |
83 | |
84 | /// Tuple, pair |
85 | template <size_t N, typename Out, typename T> |
86 | Out & dumpTupleImpl(Out & out, T && x) |
87 | { |
88 | if constexpr (N == 0) |
89 | out << "{" ; |
90 | else |
91 | out << ", " ; |
92 | |
93 | dumpValue(out, std::get<N>(x)); |
94 | |
95 | if constexpr (N + 1 == std::tuple_size_v<std::decay_t<T>>) |
96 | out << "}" ; |
97 | else |
98 | dumpTupleImpl<N + 1>(out, x); |
99 | |
100 | return out; |
101 | } |
102 | |
103 | template <int priority, typename Out, typename T> |
104 | std::enable_if_t<priority == 4, Out> & dumpImpl(Out & out, T && x, std::decay_t<decltype(std::get<0>(std::declval<T>()))> * = nullptr) |
105 | { |
106 | return dumpTupleImpl<0>(out, x); |
107 | } |
108 | |
109 | |
110 | template <int priority, typename Out, typename T> |
111 | Out & dumpDispatchPriorities(Out & out, T && x, std::decay_t<decltype(dumpImpl<priority>(std::declval<Out &>(), std::declval<T>()))> *) |
112 | { |
113 | return dumpImpl<priority>(out, x); |
114 | } |
115 | |
116 | struct LowPriority { LowPriority(void *) {} }; |
117 | |
118 | template <int priority, typename Out, typename T> |
119 | Out & dumpDispatchPriorities(Out & out, T && x, LowPriority) |
120 | { |
121 | return dumpDispatchPriorities<priority - 1>(out, x, nullptr); |
122 | } |
123 | |
124 | |
125 | template <typename Out, typename T> |
126 | Out & dumpValue(Out & out, T && x) |
127 | { |
128 | return dumpDispatchPriorities<5>(out, x, nullptr); |
129 | } |
130 | |
131 | |
132 | template <typename Out, typename T> |
133 | Out & dump(Out & out, const char * name, T && x) |
134 | { |
135 | out << demangle(typeid(x).name()) << " " << name << " = " ; |
136 | return dumpValue(out, x); |
137 | } |
138 | |
139 | #ifdef __clang__ |
140 | #pragma clang diagnostic ignored "-Wgnu-zero-variadic-macro-arguments" |
141 | #endif |
142 | |
143 | #define DUMPVAR(VAR) ::dump(std::cerr, #VAR, (VAR)); std::cerr << "; "; |
144 | #define DUMPHEAD std::cerr << __FILE__ << ':' << __LINE__ << " [ " << getThreadNumber() << " ] "; |
145 | #define DUMPTAIL std::cerr << '\n'; |
146 | |
147 | #define DUMP1(V1) do { DUMPHEAD DUMPVAR(V1) DUMPTAIL } while(0) |
148 | #define DUMP2(V1, V2) do { DUMPHEAD DUMPVAR(V1) DUMPVAR(V2) DUMPTAIL } while(0) |
149 | #define DUMP3(V1, V2, V3) do { DUMPHEAD DUMPVAR(V1) DUMPVAR(V2) DUMPVAR(V3) DUMPTAIL } while(0) |
150 | #define DUMP4(V1, V2, V3, V4) do { DUMPHEAD DUMPVAR(V1) DUMPVAR(V2) DUMPVAR(V3) DUMPVAR(V4) DUMPTAIL } while(0) |
151 | #define DUMP5(V1, V2, V3, V4, V5) do { DUMPHEAD DUMPVAR(V1) DUMPVAR(V2) DUMPVAR(V3) DUMPVAR(V4) DUMPVAR(V5) DUMPTAIL } while(0) |
152 | #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) |
153 | #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) |
154 | #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) |
155 | #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) |
156 | |
157 | /// https://groups.google.com/forum/#!searchin/kona-dev/variadic$20macro%7Csort:date/kona-dev/XMA-lDOqtlI/GCzdfZsD41sJ |
158 | |
159 | #define VA_NUM_ARGS_IMPL(x1, x2, x3, x4, x5, x6, x7, x8, x9, N, ...) N |
160 | #define VA_NUM_ARGS(...) VA_NUM_ARGS_IMPL(__VA_ARGS__, 9, 8, 7, 6, 5, 4, 3, 2, 1) |
161 | |
162 | #define MAKE_VAR_MACRO_IMPL_CONCAT(PREFIX, NUM_ARGS) PREFIX ## NUM_ARGS |
163 | #define MAKE_VAR_MACRO_IMPL(PREFIX, NUM_ARGS) MAKE_VAR_MACRO_IMPL_CONCAT(PREFIX, NUM_ARGS) |
164 | #define MAKE_VAR_MACRO(PREFIX, ...) MAKE_VAR_MACRO_IMPL(PREFIX, VA_NUM_ARGS(__VA_ARGS__)) |
165 | |
166 | #define DUMP(...) MAKE_VAR_MACRO(DUMP, __VA_ARGS__)(__VA_ARGS__) |
167 | |