libGimbal 0.0.0 (PRERELEASE)
Ultimate C17/C++20 Core Utility Library and Cross-Language Runtime Framework
gimbal_api_frame.h
Go to the documentation of this file.
1
5#ifndef GIMBAL_API_FRAME_H
6#define GIMBAL_API_FRAME_H
7
9#include "../algorithms/gimbal_numeric.h"
10#include "gimbal_ext.h"
11#include "gimbal_call_stack.h"
12#include "gimbal_thread.h"
13#include <stdarg.h>
14#include <string.h>
15#include <errno.h>
16
17#ifdef __cplusplus
18extern "C" {
19#endif
20
21// ===== GBL API FRAME CONVENIENCE ACCESSORS =====
22
23#define GBL_API_FRAME_DECLARE GblStackFrame* GBL_API_FRAME_NAME
24#define GBL_API_FRAME() (GBL_API_FRAME_NAME)
25#define GBL_API_CONTEXT() GBL_API_FRAME()->pContext
26#define GBL_API_OBJECT() GBL_API_FRAME()->pObject
27#define GBL_API_RECORD() GBL_API_FRAME()->record
28#define GBL_API_RESULT() GBL_API_RECORD().result
29#define GBL_API_SOURCE() GBL_API_FRAME()->sourceCurrent
30#define GBL_API_LAST_RECORD() GblThread_callRecord(NULL)
31#define GBL_API_LAST_RESULT() GblThread_callRecord(NULL)->result
32
33// ====== SOURCE LOCATION PROPAGATION UTILITIES =====
34
35#define GBL_SRC_FILE GBL_SOURCE_FILE
36#define GBL_SRC_FN GBL_SOURCE_FUNCTION
37#define GBL_SRC_LN GBL_SOURCE_LINE
38#define GBL_SRC_COL GBL_SOURCE_COLUMN
39#define GBL_SRC_LOC GBL_SOURCE_LOCATION
40#define GblSrcLoc GblSourceLocation
41
42#define GBL_SOURCE_LOCATION(FILE, FUNCTION, LINE, COL) ((GblSourceLocation){FILE, FUNCTION, LINE, COL})
43
44#define GBL_API_STACK_FRAME_SOURCE_PUSH(pStackFrame, current) \
45 if(++pStackFrame->sourceCurrentCaptureDepth == 1) pStackFrame->sourceCurrent = current;
46
47#define GBL_API_STACK_FRAME_SOURCE_POP(pStackFrame) \
48 GBL_STMT_START { \
49 GBL_ASSERT(pStackFrame->sourceCurrentCaptureDepth); \
50 if(--pStackFrame->sourceCurrentCaptureDepth == 0) \
51 pStackFrame->sourceCurrent = pStackFrame->sourceEntry; \
52 } GBL_STMT_END
53
54
55#define GBL_API_SOURCE_LOC_PUSH(srcLoc) \
56 GBL_API_STACK_FRAME_SOURCE_PUSH(GBL_API_FRAME(), srcLoc)
57
58#define GBL_API_SOURCE_PUSH(FILE, FUNCTION, LINE, COLUMN) \
59 GBL_API_SOURCE_LOC_PUSH(GBL_SOURCE_LOCATION(FILE, FUNCTION, LINE, COLUMN))
60
61#define GBL_API_SOURCE_POP() \
62 GBL_API_STACK_FRAME_SOURCE_POP(GBL_API_FRAME())
63
64#define GBL_API_SOURCE_SCOPED(CALL, loc, ...) \
65 GBL_STMT_START { \
66 GBL_API_SOURCE_LOC_PUSH((loc)); \
67 GBL_IDENTITY(CALL)(__VA_ARGS__); \
68 GBL_API_SOURCE_POP(); \
69 } GBL_STMT_END
70
71// ====== BOTTOM-LEVEL ERROR HANDLING + CONTROL FLOW =====
72
73#define GBL_API_RECORD_SET_JMP_CND_(expr, result, label, srcLoc, ...) \
74 GBL_STMT_START { \
75 GBL_API_SOURCE_LOC_PUSH(srcLoc); \
76 if(!(expr)) GBL_UNLIKELY { \
77 GBL_API_RECORD_SET(result, __VA_ARGS__); \
78 GBL_API_SOURCE_POP(); \
79 label; \
80 } else GBL_LIKELY { \
81 GBL_API_SOURCE_POP(); \
82 } \
83 } GBL_STMT_END
84
85#define GBL_API_RECORD_SET_JMP_CND(expr, result, label, ...) \
86 GBL_API_RECORD_SET_JMP_CND_(expr, result, goto label, GBL_SRC_LOC(GBL_SRC_FILE, GBL_SRC_FN, GBL_SRC_LN, GBL_SRC_COL), __VA_ARGS__);
87
88//====== VERIFY =========
89
90#define GBL_API_VERIFY_(expr, result, srcLoc, ...) \
91 GBL_API_RECORD_SET_JMP_CND_((expr), \
92 result, \
93 goto GBL_API_END_LABEL, \
94 srcLoc, __VA_ARGS__)
95
96
97
98#define GBL_API_VERIFY_N(srcLoc, expr, result, ...) \
99 GBL_API_VERIFY_(expr, result, srcLoc, __VA_ARGS__)
100
101#define GBL_API_VERIFY_3(srcLoc, expr, result) \
102 GBL_API_VERIFY_N(srcLoc, expr, result, gblResultString(result))
103
104#define GBL_API_VERIFY(...) \
105 GBL_STMT_START { \
106 const GblSrcLoc src_ = GBL_SRC_LOC(GBL_SRC_FILE, GBL_SRC_FN, GBL_SRC_LN, GBL_SRC_COL); \
107 GBL_VA_OVERLOAD_SELECT(GBL_API_VERIFY, GBL_VA_OVERLOAD_SUFFIXER_3_N, src_, __VA_ARGS__)(src_, __VA_ARGS__); \
108 } GBL_STMT_END
109
110//====== VERIFY_EXPRESSION =========
111
112#define GBL_API_VERIFY_EXPRESSION_N(srcLoc, expr, ...) \
113 GBL_API_VERIFY_(expr, GBL_RESULT_ERROR_INVALID_EXPRESSION, srcLoc, __VA_ARGS__)
114
115#define GBL_API_VERIFY_EXPRESSION_2(src, expr) \
116 GBL_API_VERIFY_EXPRESSION_N(src, expr, "Invalid Expression: "#expr)
117
118#define GBL_API_VERIFY_EXPRESSION(...) \
119 GBL_STMT_START { \
120 const GblSrcLoc src_ = GBL_SRC_LOC(GBL_SRC_FILE, GBL_SRC_FN, GBL_SRC_LN, GBL_SRC_COL); \
121 GBL_VA_OVERLOAD_SELECT(GBL_API_VERIFY_EXPRESSION, GBL_VA_OVERLOAD_SUFFIXER_2_N, src_, __VA_ARGS__)(src_, __VA_ARGS__); \
122 } GBL_STMT_END
123
124//====== VERIFY_POINTER =========
125#define GBL_API_VERIFY_POINTER_N(srcLoc, expr, ...) \
126 GBL_API_VERIFY_(expr, GBL_RESULT_ERROR_INVALID_POINTER, srcLoc, __VA_ARGS__)
127
128#define GBL_API_VERIFY_POINTER_2(src, expr) \
129 GBL_API_VERIFY_POINTER_N(src, expr, "Invalid Pointer")
130
131#define GBL_API_VERIFY_POINTER(...) \
132 GBL_STMT_START { \
133 const GblSrcLoc src_ = GBL_SRC_LOC(GBL_SRC_FILE, GBL_SRC_FN, GBL_SRC_LN, GBL_SRC_COL); \
134 GBL_VA_OVERLOAD_SELECT(GBL_API_VERIFY_POINTER, GBL_VA_OVERLOAD_SUFFIXER_2_N, src_, __VA_ARGS__)(src_, __VA_ARGS__); \
135 } GBL_STMT_END
136
137//====== VERIFY_ARG =========
138#define GBL_API_VERIFY_ARG_N(srcLoc, expr, ...) \
139 GBL_API_VERIFY_(expr, GBL_RESULT_ERROR_INVALID_ARG, srcLoc, __VA_ARGS__)
140
141#define GBL_API_VERIFY_ARG_2(src, expr) \
142 GBL_API_VERIFY_ARG_N(src, expr, "Invalid Arg: "#expr);
143
144#define GBL_API_VERIFY_ARG(...) \
145 GBL_STMT_START { \
146 const GblSrcLoc src_ = GBL_SRC_LOC(GBL_SRC_FILE, GBL_SRC_FN, GBL_SRC_LN, GBL_SRC_COL); \
147 GBL_VA_OVERLOAD_SELECT(GBL_API_VERIFY_ARG, GBL_VA_OVERLOAD_SUFFIXER_2_N, src_, __VA_ARGS__)(src_, __VA_ARGS__); \
148 } GBL_STMT_END
149
150//===== VERIFY_TYPE =======
151#define GBL_API_VERIFY_TYPE_N(srcLoc, actualType, expectedType, ...) \
152 GBL_API_VERIFY_(GblType_check(actualType, expectedType), GBL_RESULT_ERROR_TYPE_MISMATCH, srcLoc, __VA_ARGS__)
153
154#define GBL_API_VERIFY_TYPE_3(srcLoc, actualType, expectedType) \
155 GBL_API_VERIFY_TYPE_N(srcLoc, actualType, expectedType, "Type mismatch [Actual: %s, Expected: %s]", GblType_name(actualType), GblType_name(expectedType))
156
157#define GBL_API_VERIFY_TYPE_2(srcLoc, actualType) \
158 GBL_API_VERIFY_(actualType != GBL_INVALID_TYPE, GBL_RESULT_ERROR_INVALID_TYPE, srcLoc, "Invalid Type");
159
160#define GBL_API_VERIFY_TYPE(...) \
161 GBL_STMT_START { \
162 const GblSrcLoc src_ = GBL_SRC_LOC(GBL_SRC_FILE, GBL_SRC_FN, GBL_SRC_LN, GBL_SRC_COL); \
163 GBL_VA_OVERLOAD_SELECT(GBL_API_VERIFY_TYPE, GBL_VA_OVERLOAD_SUFFIXER_3_N, src_, __VA_ARGS__)(src_, __VA_ARGS__); \
164 } GBL_STMT_END
165
166//==== LAST RECORD =====
167#define GBL_API_VERIFY_LAST_RECORD() \
168 GBL_STMT_START { \
169 const GblCallRecord* pRecord = \
170 GblThread_callRecord(NULL); \
171 if(pRecord && GBL_RESULT_ERROR(pRecord->result)) { \
172 GBL_API_RESULT() = pRecord->result; \
173 GBL_API_DONE(); \
174 } \
175 } GBL_STMT_END
176
177#define GBL_API_CLEAR_LAST_RECORD() \
178 GblThread_setCallRecord(NULL, NULL)
179
180//===== C STD ERRNO =====
181
182#ifdef GBL_CONFIG_ERRNO_CHECKS
183#define GBL_API_ERRNO_CLEAR() errno = 0
184#else
185#define GBL_API_ERRNO_CLEAR()
186#endif
187
188#ifdef GBL_CONFIG_ERRNO_CHECKS
189# define GBL_API_PERROR(...) \
190 GBL_STMT_START { \
191 if(errno) GBL_UNLIKELY { \
192 const GBL_RESULT code = \
193 GBL_ERRNO_RESULT(errno); \
194 GBL_API_VERIFY( \
195 GBL_RESULT_SUCCESS(code), \
196 code, \
197 "ERRNO: %x", errno); \
198 } \
199 } GBL_STMT_END
200#else
201# define GBL_API_PERROR(...)
202#endif
203
204GBL_MAYBE_UNUSED GBL_INLINE GBL_RESULT GBL_ERRNO_RESULT(int ernum) {
205 switch(ernum) {
206 case 0: return GBL_RESULT_SUCCESS;
207 default: return GBL_RESULT_ERROR;
208 }
209}
210
211// ======= API ======
212#define GBL_API_INLINE_RETVAL() GBL_API_INLINE_RETURN_VALUE_NAME
213
214#define GBL_API_INLINE(MethodPrefix, ReturnType, ...) \
215 GBL_INLINE ReturnType GBL_API_INLINE_##MethodPrefix##_(GBL_API_FRAME_DECLARE, GblSrcLoc srcLoc, ##__VA_ARGS__) { \
216 ReturnType GBL_API_INLINE_RETURN_VALUE_NAME;
217
218#define GBL_API_INLINE_BEGIN(InitialRetValue) \
219 GBL_API_INLINE_RETVAL() = InitialRetValue; \
220 GBL_API_SOURCE_LOC_PUSH(srcLoc);
221
222
223#define GBL_API_INLINE_END() \
224 goto GBL_API_END_LABEL; \
225 GBL_API_END_LABEL: GBL_STMT_START {;} GBL_STMT_END; \
226 }
227
228#define GBL_API_INLINE_RETURN() \
229 GBL_API_SOURCE_POP(); \
230 return GBL_API_INLINE_RETVAL()
231
232
233#define GBL_API_INLINE_CALL_(MethodPrefix, srcLoc, ...) \
234 GBL_API_INLINE_##MethodPrefix##_(GBL_API_FRAME(), srcLoc GBL_VA_ARGS(__VA_ARGS__))
235
236#define GBL_API_INLINE_CALL(MethodPrefix, ...) \
237 GBL_API_INLINE_CALL_(MethodPrefix, GBL_SRC_LOC(GBL_SRC_FILE, GBL_SRC_FN, GBL_SRC_LN, GBL_SRC_COL) GBL_VA_ARG)
238
239// ============== GBL EXT USERMETHODS ==========
240
241#define GBL_API_EXT(prefix, ...) \
242 GBL_STMT_START { \
243 GBL_API_SOURCE_PUSH(GBL_SRC_FILE, GBL_SRC_FN, GBL_SRC_LN, GBL_SRC_COL); \
244 GBL_MAYBE_UNUSED const GBL_RESULT localResult = GBL_EXT_##prefix(GBL_API_FRAME(), ##__VA_ARGS__); \
245 GBL_ASSERT(!(GBL_CONFIG_ASSERT_ERROR_ENABLED && GBL_RESULT_ERROR(localResult)), "Ext["#prefix"]: ERROR"); \
246 GBL_ASSERT(!(GBL_CONFIG_ASSERT_PARTIAL_ENABLED && GBL_RESULT_PARTIAL(localResult)), "Ext["#prefix"]: ERROR"); \
247 GBL_UNUSED(localResult); \
248 GBL_API_SOURCE_POP(); \
249 } GBL_STMT_END
250
251
252GBL_MAYBE_UNUSED GBL_API_INLINE(MALLOC, void*, GblSize size, GblSize align, const char* pDebugStr) {
253 GBL_API_INLINE_BEGIN(GBL_NULL);
254 if(align == 0) {
255 align = GBL_ALIGNOF(GBL_MAX_ALIGN_T);
256 size = gblAlignedAllocSizeDefault(size);
257 }
258 GBL_ASSERT(size % align == 0);
259 GBL_API_EXT(MALLOC, size, align, pDebugStr, &GBL_API_INLINE_RETVAL());
260 GBL_API_INLINE_END();
261 // modify/set return value based on result
262 GBL_API_INLINE_RETURN();
263}
264
265#define GBL_API_MALLOC_4(src, size, align, dbgStr) \
266 GBL_API_INLINE_CALL_(MALLOC, src, size, align, dbgStr)
267
268#define GBL_API_MALLOC_3(src, size, align) \
269 GBL_API_MALLOC_4(src, size, align, GBL_NULL)
270
271#define GBL_API_MALLOC_2(src, size) \
272 GBL_API_MALLOC_3(src, gblAlignedAllocSizeDefault(size), GBL_ALIGNOF(GBL_MAX_ALIGN_T))
273
274#define GBL_API_MALLOC(...) \
275 GBL_VA_OVERLOAD_SELECT(GBL_API_MALLOC, GBL_VA_OVERLOAD_SUFFIXER_ARGC, 1, __VA_ARGS__)(GBL_SRC_LOC(GBL_SRC_FILE, GBL_SRC_FN, GBL_SRC_LN, GBL_SRC_COL), __VA_ARGS__)
276
277#define GBL_API_NEW_4(src, type, count, dbgStr) \
278 (type*)GBL_API_INLINE_CALL_(MALLOC, src, gblAlignedAllocSizeDefault(sizeof(type)*count), 0, dbgStr)
279
280#define GBL_API_NEW_3(src, type, count) \
281 GBL_API_NEW_4(src, type, count, GBL_NULL)
282
283#define GBL_API_NEW_2(src, type) \
284 GBL_API_NEW_3(src, type, 1)
285
286#define GBL_API_NEW(...) \
287 GBL_VA_OVERLOAD_SELECT(GBL_API_NEW, GBL_VA_OVERLOAD_SUFFIXER_ARGC, 1, __VA_ARGS__)(GBL_SRC_LOC(GBL_SRC_FILE, GBL_SRC_FN, GBL_SRC_LN, GBL_SRC_COL), __VA_ARGS__)
288
289GBL_MAYBE_UNUSED GBL_API_INLINE(REALLOC, void*, void* pData, GblSize newSize, GblSize newAlign) {
290 GBL_API_INLINE_BEGIN(NULL);
291
292 GBL_API_EXT(REALLOC, pData, newSize, newAlign, &GBL_API_INLINE_RETVAL());
293 GBL_API_INLINE_END();
294 // modify/set return value based on result
295 GBL_API_INLINE_RETURN();
296}
297
298#define GBL_API_REALLOC_4(src, pData, newSize, newAlign) \
299 GBL_API_INLINE_CALL_(REALLOC, src, pData, newSize, newAlign)
300
301#define GBL_API_REALLOC_3(src, pData, newSize) \
302 GBL_API_REALLOC_4(src, pData, newSize, 1)
303
304#define GBL_API_REALLOC(...) \
305 GBL_VA_OVERLOAD_SELECT(GBL_API_REALLOC, GBL_VA_OVERLOAD_SUFFIXER_ARGC, 1, __VA_ARGS__)(GBL_SRC_LOC(GBL_SRC_FILE, GBL_SRC_FN, GBL_SRC_LN, GBL_SRC_COL), __VA_ARGS__)
306
307#define GBL_API_RENEW_5(src, ptr, type, count, dbgStr) \
308 GBL_API_INLINE_CALL(REALLOC, src, ptr, sizeof(type)*count, dbgStr)
309
310#define GBL_API_RENEW_4(src, ptr, type, count) \
311 GBL_API_RENEW_5(src, ptr, type, count, GBL_NULL)
312
313#define GBL_API_RENEW_3(src, ptr, type) \
314 GBL_API_RENEW_4(src, ptr, type, 1)
315
316#define GBL_API_RENEW(...) \
317 GBL_VA_OVERLOAD_SELECT(GBL_API_REALLOC, GBL_VA_OVERLOAD_SUFFIXER_ARGC, 1, __VA_ARGS__)(GBL_SRC_LOC(GBL_SRC_FILE, GBL_SRC_FN, GBL_SRC_LN, GBL_SRC_COL), __VA_ARGS__)
318
319#define GBL_API_FREE(pData) \
320 GBL_API_SOURCE_SCOPED(GBL_API_EXT, (GBL_SRC_LOC(GBL_SRC_FILE, GBL_SRC_FN, GBL_SRC_LN, GBL_SRC_COL)), FREE, pData)
321
322#define GBL_API_PUSH_(srcLoc, ...) \
323 GBL_STMT_START { \
324 GBL_API_SOURCE_LOC_PUSH(srcLoc); \
325 GBL_RESULT_SUCCESS(GblThread_logPush(NULL)); \
326 GBL_API_EXT(LOG_PUSH); \
327 GBL_API_SOURCE_POP(); \
328 ++GBL_API_FRAME()->stackDepth; \
329 } GBL_STMT_END
330
331#define GBL_API_PUSH() \
332 GBL_STMT_START { \
333 const GblSrcLoc src_ = GBL_SRC_LOC(GBL_SRC_FILE, GBL_SRC_FN, GBL_SRC_LN, GBL_SRC_COL); \
334 GBL_API_PUSH_(src_); \
335 } GBL_STMT_END
336
337#define GBL_API_PUSH_VERBOSE_N(srcLoc, pFmt, ...) \
338 GBL_STMT_START { \
339 GBL_API_SOURCE_SCOPED(GBL_API_VERBOSE, srcLoc, pFmt, ##__VA_ARGS__); \
340 GBL_API_PUSH_(srcLoc); \
341 } GBL_STMT_END
342
343#define GBL_API_PUSH_VERBOSE(...) \
344 GBL_STMT_START { \
345 const GblSrcLoc src_ = GBL_SRC_LOC(GBL_SRC_FILE, GBL_SRC_FN, GBL_SRC_LN, GBL_SRC_COL); \
346 GBL_VA_OVERLOAD_SELECT(GBL_API_PUSH_VERBOSE, GBL_VA_OVERLOAD_SUFFIXER_1_N, src_, ##__VA_ARGS__)(src_, ##__VA_ARGS__); \
347 } GBL_STMT_END
348
349#define GBL_API_POP_2(srcLoc, count) \
350 GblThread_logPop(NULL, count); \
351 GBL_API_SOURCE_SCOPED(GBL_API_EXT, srcLoc, LOG_POP, count); \
352 GBL_API_FRAME()->stackDepth -= count;
353
354#define GBL_API_POP_1(srcLoc) \
355 GBL_API_POP_2(srcLoc, 1)
356
357#define GBL_API_POP(...) \
358 GBL_STMT_START { \
359 const GblSrcLoc loc = GBL_SRC_LOC(GBL_SRC_FILE, GBL_SRC_FN, GBL_SRC_LN, GBL_SRC_COL); \
360 GBL_VA_OVERLOAD_CALL(GBL_API_POP, GBL_VA_OVERLOAD_SUFFIXER_ARGC, loc, __VA_ARGS__); \
361 } GBL_STMT_END
362
363GBL_MAYBE_UNUSED GBL_API_INLINE(LOG, GBL_RESULT, GBL_LOG_LEVEL level, const char* pFmt, ...) {
364 GBL_API_INLINE_BEGIN(GBL_RESULT_SUCCESS);
365 va_list varArgs;
366 va_start(varArgs, pFmt);
367
368 GBL_API_EXT(LOG_WRITE, level, pFmt, varArgs);
369 va_end(varArgs);
370 GBL_API_INLINE_END();
371 GBL_API_INLINE_RETURN();
372}
373
374#define GBL_API_LOG_(src, level, pFmt, ...) \
375 GBL_API_INLINE_CALL_(LOG, src, level, pFmt, ##__VA_ARGS__);
376#define GBL_API_LOG(level, pFmt, ...) \
377 GBL_API_LOG_(GBL_SRC_LOC(GBL_SRC_FILE, GBL_SRC_FN, GBL_SRC_LN, GBL_SRC_COL), level, pFmt, ##__VA_ARGS__)
378
379#define GBL_API_DEBUG(pFmt, ...) \
380 GBL_STMT_START { \
381 const GblSrcLoc src = GBL_SRC_LOC(GBL_SRC_FILE, GBL_SRC_FN, GBL_SRC_LN, GBL_SRC_COL); \
382 GBL_API_LOG_(src, GBL_LOG_LEVEL_DEBUG, pFmt, ##__VA_ARGS__); \
383 } GBL_STMT_END
384
385#define GBL_API_VERBOSE(pFmt, ...) \
386 GBL_STMT_START { \
387 const GblSrcLoc src = GBL_SRC_LOC(GBL_SRC_FILE, GBL_SRC_FN, GBL_SRC_LN, GBL_SRC_COL); \
388 GBL_API_LOG_(src, GBL_LOG_LEVEL_VERBOSE, pFmt, ##__VA_ARGS__); \
389 } GBL_STMT_END
390
391#define GBL_API_INFO(pFmt, ...) \
392 GBL_STMT_START { \
393 const GblSrcLoc src = GBL_SRC_LOC(GBL_SRC_FILE, GBL_SRC_FN, GBL_SRC_LN, GBL_SRC_COL); \
394 GBL_API_LOG_(src, GBL_LOG_LEVEL_INFO, pFmt, ##__VA_ARGS__); \
395 } GBL_STMT_END
396
397#define GBL_API_WARN(pFmt, ...) \
398 GBL_STMT_START { \
399 const GblSrcLoc src = GBL_SRC_LOC(GBL_SRC_FILE, GBL_SRC_FN, GBL_SRC_LN, GBL_SRC_COL); \
400 GBL_API_LOG_(src, GBL_LOG_LEVEL_WARNING, pFmt, ##__VA_ARGS__); \
401 } GBL_STMT_END
402
403#define GBL_API_ERROR(pFmt, ...) \
404 GBL_STMT_START { \
405 const GblSrcLoc src = GBL_SRC_LOC(GBL_SRC_FILE, GBL_SRC_FN, GBL_SRC_LN, GBL_SRC_COL); \
406 GBL_API_LOG_(src, GBL_LOG_LEVEL_ERROR, pFmt, ##__VA_ARGS__); \
407 } GBL_STMT_END
408
409
410#define GBL_API_EVENT_2(srcLoc, event) \
411 GBL_API_SOURCE_SCOPED(GBL_API_EXT, srcLoc, EVENT, type, NULL, 0)
412
413#define GBL_API_EVENT(event) \
414 GBL_STMT_START { \
415 const GblSrcLoc src_ = GBL_SRC_LOC(GBL_SRC_FILE, GBL_SRC_FN, GBL_SRC_LN, GBL_SRC_COL); \
416 GBL_UNUSED(src_); \
417 GblObject_sendEvent(GBL_API_OBJECT(), (GblEvent*)event); \
418 } GBL_STMT_END
419
420
421// ===================== RECORD = > ASSERT =========================
422
423// Base Enabled Logic
424#define GBL_API_RECORD_ASSERT_(record, test) \
425 GBL_STMT_START { \
426 GBL_ASSERT(!test(record->result), record->message); \
427 } GBL_STMT_END
428
429// Base Conditional Logic
430#define GBL_API_RECORD_ASSERT_CONDITIONAL_(enabled, record, test) \
431 GBL_MACRO_CONDITIONAL_CALL(enabled, GBL_API_RECORD_ASSERT_, record, test)
432
433// Partial Success
434#define GBL_API_RECORD_ASSERT_PARTIAL(record) \
435 GBL_API_RECORD_ASSERT_CONDITIONAL_(GBL_CONFIG_ASSERT_PARTIAL_ENABLED, \
436 record, GBL_RESULT_PARTIAL)
437// Error
438#define GBL_API_RECORD_ASSERT_ERROR(record) \
439 GBL_API_RECORD_ASSERT_CONDITIONAL_(GBL_CONFIG_ASSERT_ERROR_ENABLED, \
440 record, GBL_RESULT_ERROR)
441
442// Unknown
443#define GBL_API_RECORD_ASSERT_UNKNOWN(record) \
444 GBL_API_RECORD_ASSERT_CONDITIONAL_(GBL_CONFIG_ASSERT_UNKNOWN_ENABLED, \
445 record, GBL_RESULT_UNKNOWN)
446// Both Together
447#define GBL_API_RECORD_ASSERT(record) \
448 GBL_STMT_START { \
449 GBL_API_RECORD_ASSERT_ERROR(record); \
450 GBL_API_RECORD_ASSERT_PARTIAL(record); \
451 GBL_API_RECORD_ASSERT_UNKNOWN(record); \
452 } GBL_STMT_END
453
454
455// ========================== RECORD = > LOG ========================
456
457// Base Enabled Logic (uses a prefix prefix for all magic)
458#define GBL_API_RECORD_LOG_(prefix, record) \
459 GBL_STMT_START { \
460 if(GBL_RESULT_##prefix(record->result)) GBL_UNLIKELY { \
461 GBL_API_LOG(GBL_CONFIG_LOG_##prefix##_LEVEL, \
462 "%s: %s", \
463 gblResultString(record->result), record->message); \
464 } \
465 } GBL_STMT_END
466
467
468// Base Conditional Logic
469#define GBL_API_RECORD_LOG_CONDITIONAL_(prefix, record) \
470 GBL_MACRO_CONDITIONAL_CALL(GBL_CONFIG_LOG_##prefix##_ENABLED, \
471 GBL_API_RECORD_LOG_, prefix, record)
472
473// Partial Success
474#define GBL_API_RECORD_LOG_PARTIAL(record) \
475 GBL_API_RECORD_LOG_CONDITIONAL_(PARTIAL, record)
476
477// Error
478#define GBL_API_RECORD_LOG_ERROR(record) \
479 GBL_API_RECORD_LOG_CONDITIONAL_(ERROR, record)
480
481// Unknown
482#define GBL_API_RECORD_LOG_UNKNOWN(record) \
483 GBL_API_RECORD_LOG_CONDITIONAL_(UNKNOWN, record)
484
485// Combined
486#define GBL_API_RECORD_LOG(record) \
487 GBL_STMT_START { \
488 GBL_API_RECORD_LOG_ERROR(record); \
489 GBL_API_RECORD_LOG_PARTIAL(record); \
490 GBL_API_RECORD_LOG_UNKNOWN(record); \
491 } GBL_STMT_END
492
493
494// ================= RECORD => HANDLE::LAST_ERROR ==============
495#define GBL_API_RECORD_LAST_RECORD_(prefix, record) \
496 GBL_STMT_START { \
497 if(GBL_RESULT_##prefix(record->result)) { \
498 gblExtCallRecordSet(GBL_API_FRAME(), record); \
499 GblThread_setCallRecord(NULL, record); \
500 } \
501 } GBL_STMT_END
502
503
504#define GBL_API_RECORD_LAST_RECORD_CONDITIONAL_(prefix, record) \
505 GBL_MACRO_CONDITIONAL_CALL(GBL_CONFIG_LAST_CALL_RECORD_##prefix##_ENABLED, \
506 GBL_API_RECORD_LAST_RECORD_, prefix, record)
507
508#define GBL_API_RECORD_LAST_RECORD_PARTIAL(record) \
509 GBL_API_RECORD_LAST_RECORD_CONDITIONAL_(PARTIAL, record)
510
511#define GBL_API_RECORD_LAST_RECORD_ERROR(record) \
512 GBL_API_RECORD_LAST_RECORD_CONDITIONAL_(ERROR, record)
513
514#define GBL_API_RECORD_LAST_RECORD_UNKNOWN(record) \
515 GBL_API_RECORD_LAST_RECORD_CONDITIONAL_(UNKNOWN, record)
516
517#define GBL_API_RECORD_LAST_RECORD(record) \
518 GBL_STMT_START { \
519 GBL_API_RECORD_LAST_RECORD_ERROR(record); \
520 GBL_API_RECORD_LAST_RECORD_PARTIAL(record); \
521 GBL_API_RECORD_LAST_RECORD_UNKNOWN(record); \
522 } GBL_STMT_END
523
524
525// ================= RECORD => TOP-LEVEL DISPATCH ==============
526#define GBL_API_RECORD_HANDLER(record) \
527 GBL_STMT_START { \
528 GBL_API_RECORD_LOG((record)); \
529 GBL_API_RECORD_LAST_RECORD((record)); \
530 GBL_API_RECORD_ASSERT((record)); \
531 } GBL_STMT_END
532
533#define GBL_API_RECORD_SET_N(file, func, line, col, result, ...) \
534 GBL_STMT_START { \
535 GBL_API_SOURCE_LOC_PUSH(GBL_SRC_LOC(GBL_SRC_FILE, GBL_SRC_FN, GBL_SRC_LN, GBL_SRC_COL)); \
536 GBL_CALL_RECORD_CONSTRUCT(&GBL_API_RECORD(), GBL_API_OBJECT(), result, GBL_API_SOURCE(), __VA_ARGS__); \
537 GBL_API_RECORD_HANDLER(&GBL_API_RECORD()); \
538 GBL_API_SOURCE_POP(); \
539 } GBL_STMT_END
540
541#define GBL_API_RECORD_SET_6(file, func, line, col, result, pFmt) \
542 GBL_API_RECORD_SET_N(file, func, line, col, result, "%s", pFmt)
543
544#define GBL_API_RECORD_SET_5(file, func, line, col, result) \
545 GBL_API_RECORD_SET_6(file, func, line, col, result, gblResultString(result))
546
547#define GBL_API_RECORD_SET(...) \
548 GBL_VA_OVERLOAD_CALL(GBL_API_RECORD_SET, GBL_VA_OVERLOAD_SUFFIXER_6_N, GBL_SRC_FILE, GBL_SRC_FN, GBL_SRC_LN, GBL_SRC_COL, __VA_ARGS__)
549
550
551#define GBL_API_CALL_N(src, funcCall, ...) \
552 GBL_STMT_START { \
553 GBL_API_SOURCE_LOC_PUSH(src); \
554 GBL_MAYBE_UNUSED const GBL_RESULT localResult = (funcCall); \
555 if(!GBL_RESULT_SUCCESS(localResult)) GBL_UNLIKELY { \
556 GBL_API_RESULT() = localResult; \
557 } \
558 GBL_API_SOURCE_POP(); \
559 } GBL_STMT_END
560
561#define GBL_API_CALL_2(src, funcCall) \
562 GBL_API_CALL_N(src, funcCall, #funcCall);
563
564#define GBL_API_CALL(...) \
565 GBL_STMT_START { \
566 const GblSrcLoc src_ = GBL_SRC_LOC(GBL_SRC_FILE, GBL_SRC_FN, GBL_SRC_LN, GBL_SRC_COL); \
567 GBL_VA_OVERLOAD_SELECT(GBL_API_CALL, GBL_VA_OVERLOAD_SUFFIXER_2_N, src_, __VA_ARGS__)(src_, __VA_ARGS__); \
568 } GBL_STMT_END
569
570#define GBL_API_VERIFY_CALL(...) \
571 GBL_STMT_START { \
572 const GblSrcLoc src_ = GBL_SRC_LOC(GBL_SRC_FILE, GBL_SRC_FN, GBL_SRC_LN, GBL_SRC_COL); \
573 GBL_VA_OVERLOAD_SELECT(GBL_API_CALL, GBL_VA_OVERLOAD_SUFFIXER_2_N, src_, __VA_ARGS__)(src_, __VA_ARGS__); \
574 if(!GBL_RESULT_SUCCESS(GBL_API_RESULT())) goto GBL_API_END_LABEL; \
575 } GBL_STMT_END
576
577
578// ================= TOP-LEVEL API UTILITIES ==============
579
580#define GBL_API_BEGIN_FRAME(file, func, line, col, pObject, frame) \
581 const GblSrcLoc gblApiEntrySrcLoc_ = GBL_SRC_LOC(file, func, line, col); \
582 GBL_API_FRAME_DECLARE = frame; \
583 GBL_API_STACK_FRAME_CONSTRUCT(GBL_API_FRAME(), (GblObject*)pObject, GBL_RESULT_SUCCESS, gblApiEntrySrcLoc_); \
584 GBL_RESULT_SUCCESS(GblThread_stackFramePush(NULL, GBL_API_FRAME()))
585
586#define GBL_API_BEGIN_LOG_5(file, func, line, col, hHandle) \
587 GBL_API_BEGIN_FRAME(file, func, line, col, hHandle, ((GblStackFrame*)GBL_ALLOCA(sizeof(GblStackFrame))))
588
589#define GBL_API_BEGIN_LOG_N(file, func, line, col, hHandle, ...) \
590 GBL_API_BEGIN_LOG_5(file, func, line, col, hHandle); \
591 GBL_API_PUSH_VERBOSE(__VA_ARGS__);
592
593#define GBL_API_BEGIN(...) \
594 GBL_VA_OVERLOAD_CALL(GBL_API_BEGIN_LOG, GBL_VA_OVERLOAD_SUFFIXER_5_N, GBL_SRC_FILE, GBL_SRC_FN, GBL_SRC_LN, GBL_SRC_COL, __VA_ARGS__)
595
596#define GBL_API_DONE() \
597 goto GBL_API_END_LABEL
598
599#define GBL_API_END_BLOCK() \
600 goto GBL_API_END_LABEL; \
601 GBL_LABEL_EMPTY(GBL_API_END_LABEL); \
602 if(GBL_API_FRAME()->stackDepth) \
603 GBL_API_POP(GBL_API_FRAME()->stackDepth); \
604 GBL_RESULT_SUCCESS(GblThread_stackFramePop(NULL))
605
606#define GBL_API_END() \
607 GBL_API_END_BLOCK(); \
608 return GBL_API_RESULT()
609
610#define GBL_API_END_EMPTY() \
611 GBL_LABEL_EMPTY(GBL_API_END_LABEL)
612
613#define GBL_API_BLOCK_7(file, func, line, col, hHandle, frame, block) \
614 GBL_API_BEGIN_FRAME(file, func, line, col, hHandle, frame); \
615 block; \
616 GBL_API_END_BLOCK()
617
618#define GBL_API_BLOCK_6(file, func, line, col, hHandle, block) \
619 GBL_API_BLOCK_7(file, func, line, col, hHandle, ((GblStackFrame*)GBL_ALLOCA(sizeof(GblStackFrame))), block)
620
621#define GBL_API_BLOCK_5(file, func, line, col, block) \
622 GBL_API_BLOCK_6(file, func, line, col, NULL, block)
623
624#define GBL_API_BLOCK(...) \
625 GBL_VA_OVERLOAD_SELECT(GBL_API_BLOCK, GBL_VA_OVERLOAD_SUFFIXER_ARGC, GBL_SRC_FILE, GBL_SRC_FN, GBL_SRC_LN, GBL_SRC_COL, __VA_ARGS__)(GBL_SRC_FILE, GBL_SRC_FN, GBL_SRC_LN, GBL_SRC_COL, __VA_ARGS__)
626
627
628#ifdef __cplusplus
629}
630#endif
631
632#endif // GIMBAL_API_H
Helper defines for struct, enum, flags, handle delcarations.
Stack frame, call record, source capture debug utilities.
Optional Compile-time polymorphic context overrides.
GblThread, per-thread state and context management.