-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathdebugger.h
More file actions
200 lines (160 loc) · 6.69 KB
/
debugger.h
File metadata and controls
200 lines (160 loc) · 6.69 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
/*
/$$$$$$$ /$$ /$$ /$$$$$$$ /$$$$$$ /$$ /$$ /$$$$$$ /$$$$$$$$
| $$__ $$| $$ | $$| $$__ $$ /$$__ $$| $$ | $$|_ $$_/|__ $$__/
| $$ \ $$| $$ | $$| $$ \ $$| $$ \__/| $$ | $$ | $$ | $$
| $$$$$$$/| $$ | $$| $$$$$$$/| $$$$$$ | $$ | $$ | $$ | $$
| $$____/ | $$ | $$| $$__ $$ \____ $$| $$ | $$ | $$ | $$
| $$ | $$ | $$| $$ \ $$ /$$ \ $$| $$ | $$ | $$ | $$
| $$ | $$$$$$/| $$ | $$| $$$$$$/| $$$$$$/ /$$$$$$ | $$
|__/ \______/ |__/ |__/ \______/ \______/ |______/ |__/
*/
#undef __format
#undef __print_arg
#undef __nargs_0
#undef __nargs_1
#undef __eval_0
#undef __eval_1
#undef __eval_2
#undef __print_0
#undef __print_1
#undef __print_2
#undef __print_3
#undef __arg_1
#undef __arg_2
#undef __loop
#undef __loop_helper
#undef __empty_helper
#undef __print_info
#undef __custom_debug
#undef __custom_idebug
#undef __debug_P_1
#undef __debug_P_2
#undef __idebug_P_1
#undef __idebug_P_2
#undef __debug_raw_P_1
#undef __debug_raw_P_2
#undef __idebug_0
#undef __idebug_1
#undef __idebug_arg_1
#undef __idebug_arg_2
#undef debug
#undef idebug
#undef debug_raw
#undef idebug_raw
// If NDEBUG is defined, the debugging functions shouldn't print anything.
#ifdef NDEBUG
#define debug(...) ((void)0)
#define idebug(...) ((void)0)
#define debug_raw(...) ((void)0)
#define idebug_raw(...) ((void)0)
#else
/*
If stdio wasn't included yet (best effort), instead of including it, we just
declare printf. This allows the inclusion of this header in the middle of a
function, for quick debugging.
*/
#if !defined(_STDIO_H_) && !defined(_STDIO_H)
int printf(const char *restrict format, ...);
#endif
/*
There's a few tricks in here:
- Since we want to support literal strings (that have type char[n]), we match
with char[sizeof(arg)]. Both _Generic and sizeof are resolved at
compilation time, and in the right order.
- We use a really hacky trick to print a complex double, that relies on the
fact that the memory layout of a complex double on most compilers (not
portable though!) is just the real-part double next to the imaginary-part
double. So we just use "%g + %gi", which might produce several compiler
warnings, but will (probably) work.
Structs, unions, pointers/arrays (except for null terminated strings and
void* pointers), complex floats and complex long doubles are NOT supported.
With a little bit of work (or a lot) both complex types and arrays with a
known size (i.e. sizeof(array) works) could be supported.
*/
#define __format(arg) _Generic((arg), \
char: "%c", \
signed char: "%hhd", \
unsigned char: "%hhu", \
signed short: "%hd", \
unsigned short: "%hu", \
signed int: "%d", \
unsigned int: "%u", \
long int: "%ld", \
unsigned long int: "%lu", \
long long int: "%lld", \
unsigned long long int: "%llu", \
_Bool: "%d", \
float: "%g", \
double: "%g", \
long double: "%Lg", \
_Complex double: "%g + %gi", \
char *: "%s", \
void *: "%p", \
char[sizeof(arg)]: "%s", \
default: "<unknown>" \
)
// Print an argument regardless of its type (see __format).
#define __print_arg(arg) printf(__format(arg), arg)
/*
__nargs_0 calls __nargs_1 with all the arguments, plus 15 twos and 1 one at
the end (the zero is there just to avoid a warning when __nargs_1 has an
empty __VA_ARGS__). __nargs_1 selects the 17th argument, and discards the
rest. In combination, they resolve to 1 if there's just one argument, or 2
if there's more than that.
*/
#define __nargs_0(...) __nargs_1(__VA_ARGS__, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 0)
#define __nargs_1(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, ...) q
// Force 4 * 4 = 16 preprocessor passes on the arguments.
#define __eval_0(...) __eval_1(__eval_1(__eval_1(__eval_1(__VA_ARGS__))))
#define __eval_1(...) __eval_2(__eval_2(__eval_2(__eval_2(__VA_ARGS__))))
#define __eval_2(...) __VA_ARGS__
// Eval what follows as many times as necessary.
#define __print_0(...) __eval_0(__print_1(__VA_ARGS__))
// Get the cardinality of the arguments.
#define __print_1(P, ...) __print_2(__nargs_0(__VA_ARGS__), P, __VA_ARGS__)
// Force a preprocessor pass, to eval the __nargs_0 macro.
#define __print_2(num, ...) __print_3(num, __VA_ARGS__)
// Switch based on the number of arguments.
#define __print_3(num, ...) __arg_ ## num (__VA_ARGS__)
// If there's only one argument:
// Print the argument.
#define __arg_1(P, arg) P ## 1(arg)
// If there's two or more arguments:
// Print the first argument.
#define __arg_2(P, arg, ...) P ## 2(arg), __loop(P, __VA_ARGS__)
// Call __print_1 with the rest of the arguments.
#define __loop(...) __loop_helper __empty_helper() () (__VA_ARGS__)
// Loop helpers, they force re-evaluation after the first pass.
#define __loop_helper() __print_1
#define __empty_helper()
/*
These wrappers of __print_0 receive custom argument printing functions, and
take care of the formatting and printing of the arguments, and the optional
file and line information.
*/
#define __print_info(sep) printf("%s:%d:%s", __FILE__, __LINE__, sep)
#define __custom_debug(P, ...) (__print_0(P, __VA_ARGS__), printf("\n"))
#define __custom_idebug(P, sep, ...) (__print_info(sep), __custom_debug(P, __VA_ARGS__))
// HERE IS debug FUNCTION
#define __debug_P_1(arg) printf("%s = ", #arg), __print_arg(arg)
#define __debug_P_2(arg) __debug_P_1(arg), printf("\n")
#define debug(...) __custom_debug(__debug_P_, __VA_ARGS__)
// HERE IS idebug FUNCTION
#define __idebug_P_1(arg) printf("\t%s = ", #arg), __print_arg(arg)
#define __idebug_P_2(arg) __idebug_P_1(arg), printf("\n")
/*
If there's only one argument, print everything in the same line. If there's
more, print the file information in the first line, and then one argument per
line.
*/
#define idebug(...) __idebug_0(__nargs_0(__VA_ARGS__), __VA_ARGS__)
#define __idebug_0(num, ...) __idebug_1(num, __VA_ARGS__)
#define __idebug_1(num, ...) __idebug_arg_ ## num (__VA_ARGS__)
#define __idebug_arg_1(...) __custom_idebug(__debug_P_, " ", __VA_ARGS__)
#define __idebug_arg_2(...) __custom_idebug(__idebug_P_, "\n", __VA_ARGS__)
// HERE IS debug_raw AND idebug_raw FUNCTIONS
#define __debug_raw_P_1(arg) __print_arg(arg)
#define __debug_raw_P_2(arg) __debug_raw_P_1(arg), printf(" ")
#define debug_raw(...) __custom_debug(__debug_raw_P_, __VA_ARGS__)
#define idebug_raw(...) __custom_idebug(__debug_raw_P_, " ", __VA_ARGS__)
#endif /* NDEBUG */