CX Framework
Cross-platform C utility framework
Loading...
Searching...
No Matches
block.h
Go to the documentation of this file.
1#pragma once
2
5
57
58// Block wrapping using complex for statements
59// Inspired by P99 preprocessor macros, modified (in some cases heavily)
60// to fit with CX design philosophy.
61// https://gustedt.gitlabpages.inria.fr/p99/p99-html/
62
63#include <cx/platform/base.h>
64#include <cx/stype/stype.h>
66
67// -------------------- Compile-Time Feature Inhibition --------------------
68
81
82#define _inhibit_name(name) _inhibit_##name
83
89#define inhibitDeclare(name) enum { _inhibit_name(name) = 0 }
90
101#if (!defined(_MSC_VER) || _MSC_VER > 1930) && !defined(__cplusplus)
102#define inhibitCheck(name) \
103 switch (tokstring(_inhibit_name(name))[_inhibit_name(name)]) \
104 default:
105#else
106#define inhibitCheck(name)
107#endif
108
109#define _inhibitDisallow(name) \
110 _blkCond(const int* const _inhibit_name(name) = 0, !_inhibit_name(name))
111
128#define inhibitDisallow(name) _blkStart _inhibitDisallow(name)
129
130#define _inhibitAllow(name) _blkCond(const int _inhibit_name(name) = 0, !_inhibit_name(name))
131
140#define inhibitAllow(name) _blkStart _inhibitAllow(name)
141
143
144// The "RETURN" feature is used internally for correctness checks
145
146// If this is being compiled in debug/dev mode, redefine "return" to check it for correctness
147#if DEBUG_LEVEL >= 1 && !defined(_PREFAST_)
148inhibitDeclare(RETURN);
149#define _inhibitReturn _inhibitDisallow(RETURN)
150#define _allowReturn _inhibitAllow(RETURN)
151#define return inhibitCheck(RETURN) return
152#else
153#define _inhibitReturn _blkStart
154#define _allowReturn _blkStart
155#endif
156
157// -------------------- Block Wrapping Macros --------------------
158
159#define _BLK_VAR _block_done
160
161// Internal building blocks (no pun intended)
162
163#define _blkDef(before) for (tokeval(before); _BLK_VAR; _BLK_VAR = 0)
164#define _blkCond(before, cond) for (tokeval(before); (cond) && _BLK_VAR; _BLK_VAR = 0)
165#define _blkFull(before, cond, ...) \
166 for (tokeval(before); (cond) && _BLK_VAR; (__VA_ARGS__), _BLK_VAR = 0)
167
168// _blkStart should be the first token used when building a structure that uses blocks.
169// It declares the marker variable that is used to ensure the various for loop abuse only executes
170// once.
171#define _blkStart _blkDef(bool _BLK_VAR = 1)
172#define _blkBefore(...) for (tokeval(__VA_ARGS__); _BLK_VAR; _BLK_VAR = 0)
173#define _blkBeforeAfter(before, ...) _inhibitReturn _blkFull(tokeval(before), true, __VA_ARGS__)
174#define _blkAfter(...) _blkBeforeAfter(, (__VA_ARGS__))
175// _blkEnd is used as an inner loop around a user-provided block to swallow 'break' so it
176// doesn't interrupt control flow.
177#define _blkEnd _blkBefore()
178
179// Special helper for declaring a scoped variable that can refer to a variable in the outer scope
180// with the same name. It does this by using a temporary variable with a different name.
181#define _blkDefRecursive(type, name, ...) \
182 _blkDef(type tokcat2(_block_decl_, name) = tokeval(__VA_ARGS__)) \
183 _blkCond(type name = tokcat2(_block_decl_, name), ((void)name, true))
184
230#define blkWrap(before, ...) _blkStart _blkBeforeAfter(tokeval(before), __VA_ARGS__) _blkEnd
231
Compiler and platform detection macros.
#define inhibitDeclare(name)
Definition block.h:89
Runtime type system and type descriptor infrastructure.
Token pasting and stringification macros.