-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathlive_variable.h
More file actions
299 lines (264 loc) · 12 KB
/
Copy pathlive_variable.h
File metadata and controls
299 lines (264 loc) · 12 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
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
/* NOTE: `#if NO_VA_ARGS == 0` is for e.g. C89, where __VA_ARGS__ is not available -> more work needed to make structs live
TODO:
- add known types first time (like DEBUG_LIVE_IF)
- add C basic types?
- add "Leave Empty" comment under macro lists
- allow types to be specified elsewhere?
- watch pointers & strings
- construct format strings from e.g. nested structs
- define something to return to normal behaviour
- also capture __FILE__ and __LINE__
*/
/* allow for va_args to have commas replaced */
#define _ ,
#ifndef LIVE_VARIABLE_H
#include <stdio.h>
#ifndef DEBUG_ATOMIC_EXCHANGE /* user can define it to e.g. C11 atomic_exchange or Windows InterlockedExchange */
/* sets bool to 1, evaluates to previous value of bool */
#define DEBUG_ATOMIC_EXCHANGE(ptr, desired) (*(ptr) ? 1 : (*(ptr))++)
#endif
typedef struct debug_variable debug_variable;
typedef int debug_if;
#define DEBUG_VAR_DECLARE(type, Name) static type DEBUG_LIVE_VAR_## Name
#define DEBUG_LIVE_if(Name) if(DEBUG_LIVE_VAR_## Name)
/* Declare the if statement variables */
#define DEBUG_LIVE_IF(Name, init) DEBUG_VAR_DECLARE(debug_if, Name);
#if NO_VA_ARGS
#define DEBUG_LIVE_TWEAK(type, Name, init)
#else
#define DEBUG_LIVE_TWEAK(type, Name, ...)
#endif/*NO_VA_ARGS*/
DEBUG_LIVE_VARS
#undef DEBUG_LIVE_TWEAK
#undef DEBUG_LIVE_IF
/* from now on, treat ifs like other vars */
#define DEBUG_LIVE_IF(Name, init) DEBUG_LIVE_TWEAK(debug_if, Name, init)
#define LIVE_VARIABLE_H
#endif/*LIVE_VARIABLE_H*/
/* WATCHED ******************************************************************/
/* Usage: int X = 6; => DEBUG_WATCH(int, X) = 6; */
#ifndef DEBUG_WATCHED_H
#define DEBUG_WATCH_COUNTER __COUNTER__
debug_variable DebugWatchVariables[];
static unsigned int DebugWatchCount = 0;
static unsigned int DebugWatchArrayLen;
/* allows for the proper expansion */
#define DEBUG_WATCH_STR(x) #x
#define DEBUG_WATCH_DEF_INIT(type, name, ...) DEBUG_WATCHED_DEF_INIT_(type, #name, name, __VA_ARGS__)
#define DEBUG_WATCHED_DEF_INIT(type, path, var, ...) DEBUG_WATCHED_DEF_INIT_(type, DEBUG_WATCH_STR(path ##_## var), var, __VA_ARGS__)
#define DEBUG_WATCH_DEF_EQ(type, name, ...) DEBUG_WATCH_DEF_N (type, name, 0) { type DebugWatchTemp_## var = __VA_ARGS__; var = DebugWatchTemp_## var; }
#define DEBUG_WATCHED_DEF_EQ(type, path, var, ...) DEBUG_WATCHED_DEF_N (type, path, var, 0) { type DebugWatchTemp_## var = __VA_ARGS__; var = DebugWatchTemp_## var; }
#define DEBUG_WATCH_DEF_ARR(type, name) DEBUG_WATCH_DEF_N (type, name, sizeof(name)/sizeof(*(name)))
#define DEBUG_WATCHED_DEF_ARR(type, path, var) DEBUG_WATCHED_DEF_N (type, path, var, sizeof(var)/sizeof(*(var)))
#define DEBUG_WATCH_DEF_N(type, name, n) DEBUG_WATCHED_DEF_N_ (type, #name, name, n)
#define DEBUG_WATCHED_DEF_N(type, path, var, n) DEBUG_WATCHED_DEF_N_ (type, DEBUG_WATCH_STR(path ##_## var), var, n)
/* minimal initialization - sets the value every time through */
#define DEBUG_WATCHED_DEF_N_(type, name, var, n) \
if(! DEBUG_ATOMIC_EXCHANGE(&DebugWatch_## var ##_IsInit, 1)) { \
debug_variable DebugWatch = { DebugVarType_## type, name, &var, n }; \
DebugWatchVariables[++DebugWatchCount] = DebugWatch; \
DEBUG_WATCH_COUNTER; \
}
/* sets the value once on initialization, allows later tweaking that's lost on recompile */
#define DEBUG_WATCHED_DEF_INIT_(type, name, var, ...) \
if(! DEBUG_ATOMIC_EXCHANGE(&DebugWatch_## var ##_IsInit, 1)) { \
debug_variable DebugWatch = { DebugVarType_## type, name, &var }; \
type DebugWatchTemp_## var = __VA_ARGS__; \
var = DebugWatchTemp_## var; \
DebugWatchVariables[++DebugWatchCount] = DebugWatch; \
DEBUG_WATCH_COUNTER; \
}
/* separating declaration and definition allows use without declare-anywhere */
#define DEBUG_WATCH_DECL(type, name) static type name; static int DebugWatch_## name ##_IsInit
#define DEBUG_WATCH_DECL_ARR(type, name, n) static type name n; static int DebugWatch_## name ##_IsInit
#define DEBUG_WATCH_DEF(type, name) DEBUG_WATCH_DEF_INIT(type, name, {0})
#define DEBUG_WATCHED_DEF(type, name, var) DEBUG_WATCHED_DEF_INIT(type, name, var, {0})
/* typical use: */
#define DEBUG_WATCH(type, name) DEBUG_WATCH_DECL(type, name); DEBUG_WATCH_DEF(type, name) name
#define DEBUG_WATCHED(type, path, name) DEBUG_WATCH_DECL(type, name); DEBUG_WATCHED_DEF(type, path, name) name
#define DEBUG_WATCH_INIT(type, name, ...) DEBUG_WATCH_DECL(type, name); DEBUG_WATCH_DEF_INIT(type, name, __VA_ARGS__)
#define DEBUG_WATCHED_INIT(type, path, name, ...) DEBUG_WATCH_DECL(type, name); DEBUG_WATCHED_DEF_INIT(type, path, name, __VA_ARGS__)
#define DEBUG_WATCH_EQ(type, name, ...) DEBUG_WATCH_DECL(type, name); DEBUG_WATCH_DEF_EQ(type, name, __VA_ARGS__)
#define DEBUG_WATCHED_EQ(type, path, name, ...) DEBUG_WATCH_DECL(type, name); DEBUG_WATCHED_DEF_EQ(type, path, name, __VA_ARGS__)
#define DEBUG_WATCH_ARR(type, name, n) DEBUG_WATCH_DECL_ARR(type, name, n); DEBUG_WATCH_DEF_ARR(type, name)
#define DEBUG_WATCHED_ARR(type, path, name, n) DEBUG_WATCH_DECL_ARR(type, name, n); DEBUG_WATCHED_DEF_ARR(type, path, name)
/* ^^^ suffixing with the name has the feature that it doesn't trigger a warning if unused elsewhere */
#define DEBUG_WATCH_DECLARATION \
enum { DebugWatchArrayLenEnum = DEBUG_WATCH_COUNTER + 1 }; \
debug_variable DebugWatchVariables[DebugWatchArrayLenEnum]; \
static unsigned int DebugWatchArrayLen = DebugWatchArrayLenEnum;
/* NOTE: 0 is free for invalid queries */
#define DEBUG_WATCHED_H
#endif/*DEBUG_WATCHED_H*/
/* END WATCHED **************************************************************/
/* LOOP *********************************************************************/
/* Usage: for(int i = 0; i < n; ++i) => DEBUG_for(int, i = 0, i < n, ++i) */
#ifndef DEBUG_LOOP_H
#define DEBUG_FOR_CAT1(a, b) a ## b
#define DEBUG_FOR_CAT2(a, b) DEBUG_FOR_CAT1(a, b)
#if NO_DEBUG_MACROS || NO_LOOP_MACROS
#define FRAME_for(type, init, condition, iterate) \
for(type init; condition; iterate)
#else/*NO_DEBUG_MACROS || NO_LOOP_MACROS*/
#define DEBUG_for(type, init, condition, iterate) DEBUG_TOGGLE_for(type, init, condition, iterate, 1)
#define DEBUG_TOGGLE_for(type, init, condition, iterate, isdebug) \
static type init; \
{ \
static int DebugFor_IsInit; \
int IsDebug = isdebug; \
if(! DEBUG_ATOMIC_EXCHANGE(&DebugFor_IsInit, 1)) { init; } \
if(IsDebug) { goto DEBUG_FOR_CAT1(debug_for_label_, __LINE__); } \
} \
for(init; !isdebug && (condition); iterate) \
DEBUG_FOR_CAT1(debug_for_label_, __LINE__):
#endif/*NO_DEBUG_MACROS || NO_LOOP_MACROS*/
#define DEBUG_LOOP_H
#endif/*DEBUG_LOOP_H*/
/* END LOOP *****************************************************************/
/* TWEAK **********************************************************************/
/* TODO: should I include the function definitions above? */
#if defined(DEBUG_TWEAK_IMPLEMENTATION) && !defined(DEBUG_TWEAK_IMPLEMENTATION_H)
#ifndef DEBUG_TYPES
#error You have to #define DEBUG_TYPES! Do so in this format: `DEBUG_TYPE(type, printf_format_string)`
#endif
/* DEBUG_TYPE(Unknown, "%d") \ */
#define DEBUG_TWEAK_INTERNAL_TYPES \
DEBUG_TYPE(debug_if, "%u") \
#define DEBUG_TWEAK_TYPES \
DEBUG_TWEAK_INTERNAL_TYPES \
DEBUG_TYPES \
/* //// Debug variable type, name and pointer to value */
#if NO_VA_ARGS
#define DEBUG_TYPE_STRUCT(type, format, init) DEBUG_TYPE(type, format)
#else
#define DEBUG_TYPE_STRUCT(type, format, ...) DEBUG_TYPE(type, format)
#endif/*NO_VA_ARGS */
typedef struct debug_variable
{
enum {
#define DEBUG_TYPE(type, format) \
DebugVarType_## type,
DEBUG_TWEAK_TYPES
#undef DEBUG_TYPE
} Type;
char *Name;
void *Data;
unsigned int N; /* if an array, contains the number of members in it; otherwise == 0 */
} debug_variable;
#undef DEBUG_TYPE_STRUCT
/* //// Reference debug array instances by name */
enum {
DebugVarIndexEmpty,
#if NO_VA_ARGS
#define DEBUG_LIVE_TWEAK(type, Name, init) DebugVarIndex_## Name,
#else
#define DEBUG_LIVE_TWEAK(type, Name, ...) DebugVarIndex_## Name,
#endif/*NO_VA_ARGS */
DEBUG_LIVE_VARS
#undef DEBUG_LIVE_TWEAK
DebugTweakCountPlusOne,
DebugTweakCount = DebugTweakCountPlusOne - 1,
};
/* //// Global variables of the right type */
#if NO_VA_ARGS
#define DEBUG_LIVE_TWEAK(type, Name, init) DEBUG_VAR_DECLARE(type, Name) = init;
#else
#define DEBUG_LIVE_TWEAK(type, Name, ...) DEBUG_VAR_DECLARE(type, Name) = __VA_ARGS__;
#endif/*!NO_VA_ARGS */
DEBUG_LIVE_VARS
#undef DEBUG_LIVE_TWEAK
/* //// Array of annotated typed pointers to global vars */
debug_variable DebugTweakVariables[] = {
{0},
#if NO_VA_ARGS
#define DEBUG_LIVE_TWEAK(type, Name, init) { DebugVarType_## type, #Name, (void *)&DEBUG_LIVE_VAR_## Name },
#else
#define DEBUG_LIVE_TWEAK(type, Name, ...) { DebugVarType_## type, #Name, (void *)&DEBUG_LIVE_VAR_## Name },
#endif/*NO_VA_ARGS */
DEBUG_LIVE_VARS
#undef DEBUG_LIVE_TWEAK
};
static int DebugLiveVar_IsCompiling;
/* returns the result of the system call (where 0 is success), or 0 if no action taken */
static int
DebugLiveVar_Recompile(char *BuildCall)
{
int Result = 0;
/* if(! DebugLiveVar_IsCompiling) */
/* if(! (DebugLiveVar_IsCompiling == 1 ? 1 : DebugLiveVar_IsCompiling++)) */
if(! DEBUG_ATOMIC_EXCHANGE(&DebugLiveVar_IsCompiling, 1))
{
/* DebugLiveVar_IsCompiling = 1; */
Result = system(BuildCall);
}
return Result;
}
/* returns 1 if all file prints were successful */
static int
DebugLiveVar_RewriteDefines(char *Filename)
{
int Result = 1;
if(! DebugLiveVar_IsCompiling)
{
FILE *File = fopen(Filename, "w");
Result &= fprintf(File, "#ifndef LIVE_VAR_DEFINES_H\n") > 0;
for(u32 iVar = 0; iVar < ArrayCount(DebugTweakVariables); ++iVar)
{
debug_variable Var = DebugTweakVariables[iVar];
switch(Var.Type)
{
#if NO_VA_ARGS
#define DEBUG_TYPE_STRUCT(type, format, init) case DebugVarType_## type: Result &= fprintf(File, "#define DEBUGVAR_%s "format"\n", Var.Name, init) > 0; break;
#else
#define DEBUG_TYPE_STRUCT(type, format, ...) case DebugVarType_## type: Result &= fprintf(File, "#define DEBUGVAR_%s "format"\n", Var.Name, __VA_ARGS__) > 0; break;
#endif/*NO_VA_ARGS*/
#define DEBUG_TYPE_MEMBER(struct, member) ((struct *)Var.Data)->member
#define DEBUG_TYPE(type, format) case DebugVarType_## type: Result &= fprintf(File, "#define DEBUGVAR_%s "format"\n", Var.Name, *(type *)Var.Data) > 0; break;
DEBUG_TYPES
#undef DEBUG_TYPE
#undef DEBUG_TYPE_STRUCT
#undef DEBUG_TYPE_MEMBER
}
}
Result &= fprintf(File, "#define LIVE_VAR_DEFINES_H\n#endif") > 0;
fclose(File);
}
return Result;
}
/* returns 1 if all file prints were successful */
/* TODO: make more obvious that nothing will happen if currently compiling */
static int
DebugLiveVar_RewriteConfig(char *Filename)
{
int Result = 1;
if(! DebugLiveVar_IsCompiling)
{
FILE *File = fopen(Filename, "w");
Result &= fprintf(File, "#ifndef LIVE_VAR_CONFIG_H\n\n#define DEBUG_LIVE_VARS \\\n") > 0;
for(u32 iVar = 1; iVar < ArrayCount(DebugTweakVariables); ++iVar)
{
debug_variable Var = DebugTweakVariables[iVar];
switch(Var.Type)
{
case DebugVarType_debug_if: Result &= fprintf(File, "\tDEBUG_LIVE_IF(%s, %u) \\\n", Var.Name, *(debug_if *)Var.Data) > 0; break;
#define DEBUG_TYPE_MEMBER(struct, member) ((struct *)Var.Data)->member
#if NO_VA_ARGS
#define DEBUG_TYPE_STRUCT(type, format, init) case DebugVarType_## type: Result &= fprintf(File, "\tDEBUG_LIVE_TWEAK("#type", %s, "format") \\\n", Var.Name, init) > 0; break;
#else
#define DEBUG_TYPE_STRUCT(type, format, ...) case DebugVarType_## type: Result &= fprintf(File, "\tDEBUG_LIVE_TWEAK("#type", %s, "format") \\\n", Var.Name, __VA_ARGS__) > 0; break;
#endif/*NO_VA_ARGS */
#define DEBUG_TYPE(type, format) case DebugVarType_## type: Result &= fprintf(File, "\tDEBUG_LIVE_TWEAK("#type", %s, "format") \\\n", Var.Name, *(type *)Var.Data) > 0; break;
DEBUG_TYPES
#undef DEBUG_TYPE
#undef DEBUG_TYPE_STRUCT
#undef DEBUG_TYPE_MEMBER
}
}
Result &= fputs("\n\n#include \""__FILE__"\"\n#define LIVE_VAR_CONFIG_H\n#endif", File) >= 0;
fclose(File);
}
return Result;
}
#define DEBUG_TWEAK_IMPLEMENTATION_H
#endif/*DEBUG_TWEAK_IMPLEMENTATION && !DEBUG_TWEAK_IMPLEMENTATION_H*/
#undef _