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
16template <typename Out, typename T>
17Out & dumpValue(Out &, T &&);
18
19
20/// Catch-all case.
21template <int priority, typename Out, typename T>
22std::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 <<.
28template <int priority, typename Out, typename T>
29std::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.
35template <int priority, typename Out, typename T>
36std::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.
47template <int priority, typename Out, typename T>
48std::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
66template <int priority, typename Out, typename T>
67std::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> &
68dumpImpl(Out & out, T && x)
69{
70 return out << std::quoted(x);
71}
72
73/// UInt8 - output as number, not char.
74
75template <int priority, typename Out, typename T>
76std::enable_if_t<priority == 3 && std::is_same_v<std::decay_t<T>, unsigned char>, Out> &
77dumpImpl(Out & out, T && x)
78{
79 return out << int(x);
80}
81
82
83
84/// Tuple, pair
85template <size_t N, typename Out, typename T>
86Out & 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
103template <int priority, typename Out, typename T>
104std::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
110template <int priority, typename Out, typename T>
111Out & 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
116struct LowPriority { LowPriority(void *) {} };
117
118template <int priority, typename Out, typename T>
119Out & dumpDispatchPriorities(Out & out, T && x, LowPriority)
120{
121 return dumpDispatchPriorities<priority - 1>(out, x, nullptr);
122}
123
124
125template <typename Out, typename T>
126Out & dumpValue(Out & out, T && x)
127{
128 return dumpDispatchPriorities<5>(out, x, nullptr);
129}
130
131
132template <typename Out, typename T>
133Out & 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