mutable
A Database System for Research and Fast Prototyping
Loading...
Searching...
No Matches
macro.hpp
Go to the documentation of this file.
1/*--- macros.hpp -------------------------------------------------------------------------------------------------------
2 *
3 * This file provides macros.
4 *
5 *--------------------------------------------------------------------------------------------------------------------*/
6
7#pragma once
8
9#include <boost/preprocessor/seq/for_each.hpp>
10#include <cstdlib>
11#include <initializer_list>
12#include <iostream>
13#include <memory>
14
15namespace m {
16
17/*===== Macro utilities ==============================================================================================*/
18#define M_ID(X) X
19#define M_CAT(X, Y) M_CAT_(X, Y)
20#define M_CAT_(X, Y) X ## Y
21#define M_EMPTY()
22#define M_DEFER1(X) X M_EMPTY()
23#define M_COMMA(X) X,
24#define M_COMMA_PRE(X) ,X
25#define M_UNPACK(...) __VA_ARGS__
26
27#define M_EVAL(...) M_EVAL1(M_EVAL1(M_EVAL1(__VA_ARGS__)))
28#define M_EVAL1(...) M_EVAL2(M_EVAL2(M_EVAL2(__VA_ARGS__)))
29#define M_EVAL2(...) M_EVAL3(M_EVAL3(M_EVAL3(__VA_ARGS__)))
30#define M_EVAL3(...) M_EVAL4(M_EVAL4(M_EVAL4(__VA_ARGS__)))
31#define M_EVAL4(...) M_EVAL5(M_EVAL5(M_EVAL5(__VA_ARGS__)))
32#define M_EVAL5(...) __VA_ARGS__
33
34/*===== Stringify (useful when #X is too eager) ======================================================================*/
35#define M_STR_(X) #X
36#define M_STR(X) M_STR_(X)
37#define M_STRCOMMA(X) M_STR(X),
38
39#define M_PASTE_(X, Y) X ## Y
40#define M_PASTE(X, Y) M_PASTE_(X, Y)
41
42/*===== First and second element of pair =============================================================================*/
43#define M_PAIR_FIRST(A, B) A
44#define M_PAIR_SECOND(A, B) B
45
46/*===== Head and tail of list ========================================================================================*/
47#define M_HEAD(X, ...) X
48#define M_TAIL(X, ...) __VA_ARGS__
49
50/*===== Count elements in a list macro ===============================================================================*/
51#define M_COUNT(LIST) (std::initializer_list<const char*>{ LIST(M_STRCOMMA) }.size())
52
53/*===== constexpr conditional-operator ===============================================================================*/
54#define M_CONSTEXPR_COND(COND, IF_TRUE, IF_FALSE) [&](){ \
55 if constexpr (COND) { return (IF_TRUE); } else { return (IF_FALSE); } \
56}()
57#define M_CONSTEXPR_COND_UNCAPTURED(COND, IF_TRUE, IF_FALSE) [](){ \
58 if constexpr (COND) { return (IF_TRUE); } else { return (IF_FALSE); } \
59}()
60
61/*===== Transform X macro into other X macro =========================================================================*/
62#define M_PAIR_XFORM_MACRO_(_, PAIR, ELEM) \
63 M_PAIR_FIRST PAIR ( M_PAIR_SECOND PAIR (ELEM) )
64#define M_PAIR_XFORM_(PAIR, SEQ) \
65 BOOST_PP_SEQ_FOR_EACH(M_PAIR_XFORM_MACRO_, PAIR, SEQ)
66
67#define M_TRANSFORM_X_MACRO(X, SEQ, FUNC) M_PAIR_XFORM_((X, FUNC), SEQ())
68
69/*===== Define enum ==================================================================================================*/
70#define M_DECLARE_ENUM(LIST) \
71 enum LIST { \
72 LIST(M_COMMA) \
73 LIST##_MAX = M_COUNT(LIST) - 1U /* MAX takes the same value as the last *real* enum value */ \
74 }
75#define M_ENUM_TO_STR(LIST) LIST(M_STRCOMMA)
76#define M_DECL(NAME, TYPE) TYPE NAME;
77
78/*===== Number of elements in an array ===============================================================================*/
79#define M_ARR_SIZE(ARR) (sizeof(ARR) / sizeof(*(ARR)))
80
81/*===== DEBUG(MSG): Print a message in debug build with location information. ========================================*/
82#ifndef NDEBUG
83#define M_DEBUG(MSG) \
84 std::cout.flush(); \
85 std::cerr << __FILE__ << ':' << __LINE__ << ": " << __FUNCTION__ << ' ' << MSG << std::endl
86#else
87#define M_DEBUG
88#endif
89
90/*===== Define Coverage Exclusion Block ==============================================================================*/
91#define M_LCOV_EXCL_START /* Start exclusion block */
92#define M_LCOV_EXCL_STOP /* Stop exclusion block */
93#define M_LCOV_EXCL_LINE /* Exclude line */
94
95/*===== Prevent inlining of functions. Useful for functions that should be callable from the debugger, e.g. dump() ==*/
96#define M_NOINLINE __attribute__((noinline))
97
98/*======================================================================================================================
99 * M_insist(COND [, MSG])
100 *
101 * Similarly to `assert()`, checks a condition in debug build and aborts if it evaluates to `false`. Prints location
102 * information. Optionally, a message can be provided to describe the condition.
103 *====================================================================================================================*/
104
105#ifndef NDEBUG
106inline void _insist(const bool cond, const char *filename, const unsigned line, const char *condstr, const char *msg)
107{
108 if (cond) return;
109
110 std::cout.flush();
111 std::cerr << filename << ':' << line << ": Condition '" << condstr << "' failed.";
112 if (msg)
113 std::cerr << " " << msg << '.';
114 std::cerr << std::endl;
115
116 abort();
117 __builtin_unreachable();
118}
119#define M_INSIST2_(COND, MSG) ::m::_insist((COND), __FILE__, __LINE__, #COND, MSG)
120#define M_INSIST1_(COND) M_INSIST2_(COND, nullptr)
121
122#else
123#define M_INSIST2_(COND, MSG) while (0) { ((void) (COND), (void) (MSG)); }
124#define M_INSIST1_(COND) while (0) { ((void) (COND)); }
125
126#endif
127
128#define M_GET_INSIST_(_1, _2, NAME, ...) NAME
129#define M_insist(...) M_GET_INSIST_(__VA_ARGS__, M_INSIST2_, M_INSIST1_, XXX)(__VA_ARGS__)
130
131/*======================================================================================================================
132 * M_unreachable(MSG)
133 *
134 * Identifies unreachable code. When executed in debug build, prints a error message and aborts execution. In release
135 * build, hints to the compiler that this code is unreachable.
136 *====================================================================================================================*/
137
138#ifndef NDEBUG
139[[noreturn]] inline void _abort(const char *filename, const unsigned line, const char *msg)
140{
141 std::cout.flush();
142 std::cerr << filename << ':' << line << ": " << msg << std::endl;
143 abort();
144 __builtin_unreachable();
145}
146#define M_unreachable(MSG) m::_abort(__FILE__, __LINE__, (MSG))
147
148#else
149#define M_unreachable(MSG) __builtin_unreachable()
150
151#endif
152
153/*======================================================================================================================
154 * M_notnull(ARG)
155 *
156 * In debug build, checks whether ARG is NULL. If this is the case, prints an error message and aborts execution.
157 * Otherwise, the original value of ARG is returned. In release build, evaluates to ARG.
158 *====================================================================================================================*/
159
160#ifndef NDEBUG
161template<typename T>
162T * _notnull(T *arg, const char *filename, const unsigned line, const char *argstr)
163{
164 if (not arg) {
165 std::cout.flush();
166 std::cerr << filename << ':' << line << ": " << argstr << " was NULL" << std::endl;
167 abort();
168 }
169 return arg;
170}
171
172template<typename T>
173std::unique_ptr<T> _notnull(std::unique_ptr<T> arg, const char *filename, const unsigned line, const char *argstr)
174{
175 if (not bool(arg)) {
176 std::cout.flush();
177 std::cerr << filename << ':' << line << ": " << argstr << " was NULL" << std::endl;
178 abort();
179 }
180 return std::move(arg);
181}
182#define M_notnull(ARG) m::_notnull((ARG), __FILE__, __LINE__, #ARG)
183
184#else
185#define M_notnull(ARG) (ARG)
186
187#endif
188
189/*======================================================================================================================
190 * M_nothrow(ARG)
191 *
192 * In debug build, checks whether ARG throws an exception. If this is the case, prints an error message and aborts
193 * execution. Otherwise, the original value of ARG is returned. In release build, evaluates to ARG.
194 *====================================================================================================================*/
195
196#ifndef NDEBUG
197#define M_nothrow(ARG) [&](){ \
198 try { \
199 return (ARG); \
200 } catch (const std::exception &e) { \
201 std::cout.flush(); \
202 std::cerr << __FILE__ << ':' << __LINE__ << ": " << #ARG << " has thrown exception '" << e.what() << "'" \
203 << std::endl; \
204 abort(); \
205 } \
206}()
207
208#else
209#define M_nothrow(ARG) (ARG)
210
211#endif
212
213#define M_DISCARD (void)
214
215}
‍mutable namespace
Definition: Backend.hpp:10
void _abort(const char *filename, const unsigned line, const char *msg)
Definition: macro.hpp:139
T(x)
T * _notnull(T *arg, const char *filename, const unsigned line, const char *argstr)
Definition: macro.hpp:162
void _insist(const bool cond, const char *filename, const unsigned line, const char *condstr, const char *msg)
Definition: macro.hpp:106