3 * \brief QPMS miscellanous internal error handling functions and macros.
11 /// Print error message and abort();
12 QPMS_NORETURN
void qpms_pr_error(const char *fmt
, ...);
13 //void qpms_error(const char *fmt, ...);
15 /// Print an error message, indicating source, function name and line number, and abort().
17 * Usually not used directly, but rather via some of the macros
18 * that fill the first arguments automatically.
22 QPMS_NORETURN
void qpms_pr_error_at_flf(const char *filename
, unsigned int linenum
,
24 const char *fmt
, ...);
26 /// Print a warning message to stderr and flush the buffer. Don't call this directly, use QPMS_WARN().
27 void qpms_warn_at_flf(const char *filename
, unsigned int linenum
,
29 const char *fmt
, ...);
31 /// Classification of debugging messages.
33 * \see qpms_dbgmsg_enabled, qpms_dbgmsg_enable(), qpms_dbgmsg_disable()
37 QPMS_DBGMSG_THREADS
= 2, ///< Multithreading-related debug messages.
38 QPMS_DBGMSG_INTEGRATION
= 4 ///< Quadrature-related debug messages.
41 /// Print a debugging message to stderr and flush the buffer. Don't call this directly, use QPMS_DEBUG().
42 void qpms_debug_at_flf(const char *filename
, unsigned int linenum
,
44 qpms_dbgmsg_flags type
,
45 const char *fmt
, ...);
47 /// Global variable determining which types of debug messages shall be printed with QPMS_DEBUG().
49 * Use qpms_dbgmsg_enable() and qpms_dbgmsg_disable() to manipulate
54 extern qpms_dbgmsg_flags qpms_dbgmsg_enabled
;
56 /// Enable debugging messages of given \a types.
57 /** \see qpms_dbgmsg_disable() */
58 qpms_dbgmsg_flags
qpms_dbgmsg_disable(qpms_dbgmsg_flags types
);
60 /// Disable debugging messages of given \a types.
61 /** \see qpms_dbgmsg_enable() */
62 qpms_dbgmsg_flags
qpms_dbgmsg_enable(qpms_dbgmsg_flags types
);
64 /// Print a warning to stderr and flush the buffer.
66 * The arguments are the same as in standard printf().
68 #define QPMS_WARN(msg, ...) qpms_warn_at_flf(__FILE__,__LINE__,__func__,msg, ##__VA_ARGS__)
70 /// Print a debugging message to stderr and flush the buffer.
72 * The arguments after \a type are the same as in standard printf().
74 * The debugging message is printed only if the corresponding \a type flag
75 * is set in qpms_dbgmsg_enabled.
77 * \see qpms_dbgmsg_enabled
79 #define QPMS_DEBUG(type /**< Debugging message type flag, see qpms_dbgmsg_flags */ , msg, ...) qpms_debug_at_flf(__FILE__,__LINE__,__func__,type,msg, ##__VA_ARGS__)
81 /// Wrapper macro of standard malloc(), crashing on failure.
83 * Normally corresponds to a `pointer = malloc(size)`
84 * statement; however, if NULL is returned, this prints an
85 * error message and abort()s the program.
87 * The arguments are expanded several times.
89 * Note that this macro expands to a code block, to be kept in mind when using
90 * together with if/else etc.
92 * Assigned memory block is to be deallocated with standard free().
94 * \see QPMS_CRASHING_CALLOC.
96 #define QPMS_CRASHING_MALLOC(pointer, size) {\
97 (pointer) = malloc(size);\
98 if(QPMS_UNLIKELY(!(pointer) && (size)))\
99 qpms_pr_error_at_flf(__FILE__,__LINE__,__func__,\
100 "Allocation of %zd bytes for " #pointer " failed.",\
104 /// Allocate and copy.
106 * Behaves as QPMS_CRASHING_MALLOC(dest, size), but
107 * additionaly copies a chunk of memory from \a src to \a dest.
109 * \see QPMS_CRASHING_MALLOC()
111 #define QPMS_CRASHING_MALLOCPY(dest, src, size) {\
112 (dest) = malloc(size);\
113 if(QPMS_UNLIKELY(!(dest) && (size)))\
114 qpms_pr_error_at_flf(__FILE__,__LINE__,__func__,\
115 "Allocation of %zd bytes for " #dest " failed.",\
117 memcpy((dest), (src), (size));\
120 /// Wrapper macro of standard calloc(), crashing on failure.
122 * Normally corresponds to a `pointer = calloc(nmemb, size)`
123 * statement; however, if NULL is returned, this prints an
124 * error message and abort()s the program.
126 * The arguments are expanded several times.
128 * Note that this macro expands to a code block, to be kept in mind when using
129 * together with if/else etc.
131 * Assigned memory block is to be deallocated with standard free().
133 * \see QPMS_CRASHING_MALLOC, QPMS_CRASHING_REALLOC.
135 #define QPMS_CRASHING_CALLOC(pointer, nmemb, size) {\
136 (pointer) = calloc((nmemb), (size));\
137 if(QPMS_UNLIKELY(!(pointer) && (nmemb) && (size)))\
138 qpms_pr_error_at_flf(__FILE__,__LINE__,__func__,\
139 "Allocation of %zd bytes for " #pointer " failed.",\
140 (size_t)((nmemb)*(size)));\
143 /// Wrapper macro of standard realloc(), crashing on failure.
145 * Normally corresponds to a `pointer = realloc(pointer, size)`
146 * statement; however, if NULL is returned, this prints an
147 * error message and abort()s the program.
149 * The arguments are expanded several times.
151 * Note that this macro expands to a code block, to be kept in mind when using
152 * together with if/else etc.
154 * Assigned memory block is to be deallocated with standard free().
156 * \see QPMS_CRASHING_MALLOC.
158 #define QPMS_CRASHING_REALLOC(pointer, size) {\
159 (pointer) = realloc((pointer), size);\
160 if(QPMS_UNLIKELY(!(pointer) && (size)))\
161 qpms_pr_error_at_flf(__FILE__,__LINE__,__func__,\
162 "Rellocation of %zd bytes for " #pointer " failed.",\
166 /// Prints an "unexpected error" message and aborts the program.
167 /** Usually only put to presumably unreachable places in the code and similar. */
168 #define QPMS_WTF qpms_pr_error_at_flf(__FILE__,__LINE__,__func__,"Unexpected error.")
170 /// Aborts the program with "invalid enumerator" error message.
171 #define QPMS_INVALID_ENUM(x) qpms_pr_error_at_flf(__FILE__,__LINE__,__func__,"Invalid enum value (" #x " == %d)", (int) (x))
173 /// Prints an "untested function/feature" warning once when reached in the code.
174 #define QPMS_UNTESTED {\
175 static _Bool already_bitched = 0; \
176 if (QPMS_UNLIKELY(!already_bitched)) {\
177 qpms_warn_at_flf(__FILE__,__LINE__,__func__,"Warning: untested function/feature!");\
178 already_bitched = 1;\
182 /// Prints a given error message and aborts the program.
183 /** The arguments are as in standard printf(). */
184 #define QPMS_PR_ERROR(msg, ...) qpms_pr_error_at_flf(__FILE__,__LINE__,__func__,msg, ##__VA_ARGS__)
186 /// Raises an error if \a x is not zero.
187 #define QPMS_ENSURE_SUCCESS(x) { \
188 int errorcode = (x); /* evaluate x only once */ \
189 if(QPMS_UNLIKELY(errorcode)) \
190 qpms_pr_error_at_flf(__FILE__,__LINE__,__func__,"Unexpected error (%d)", errorcode); \
193 /// Raises an error if \a x is not zero, with custom error message.
194 #define QPMS_ENSURE_SUCCESS_M(x, msg, ...) { \
195 int errorcode = (x); \
196 if(QPMS_UNLIKELY(errorcode)) \
197 qpms_pr_error_at_flf(__FILE__,__LINE__,__func__,msg, ##__VA_ARGS__); \
200 /// Raises an error if \a x is not zero or one of the values listed in arguments.
201 #define QPMS_ENSURE_SUCCESS_OR(x, ...) { \
202 int errorcode = (x); /* evaluate x only once */ \
203 static const int allowed_errorcodes[] = {0, ##__VA_ARGS__};\
204 static const int n_allowed = sizeof(allowed_errorcodes) / sizeof(int); \
206 for(i = 0; i < n_allowed; ++i) \
207 if (errorcode == allowed_errorcodes[i]) break; \
208 if (QPMS_UNLIKELY(i >= n_allowed)) \
209 qpms_pr_error_at_flf(__FILE__,__LINE__,__func__,"Unexpected error (%d)", errorcode); \
212 /// Raises an error if \a x is not true, with custom error message.
213 #define QPMS_ENSURE(x, msg, ...) {if(QPMS_UNLIKELY(!(x))) qpms_pr_error_at_flf(__FILE__,__LINE__,__func__,msg, ##__VA_ARGS__); }
215 /// Raises an error if \a x is false.
217 * Currently, this is always expanded, ignoring the possible NDEBUG macro.
218 * In places where the evaluation could have significant performance impact,
219 * consider using QPMS_PARANOID_ASSERT() instead.
221 #define QPMS_ASSERT(x) {\
222 if(QPMS_UNLIKELY(!(x)))\
223 qpms_pr_error_at_flf(__FILE__,__LINE__,__func__,\
224 "Unexpected error. This is most certainly a bug.");\
227 #ifdef QPMS_EVALUATE_PARANOID_ASSERTS
228 /** \brief Raises an error if \a x is false.
230 * Expanded only if QPMS_EVALUATE_PARANOID_ASSERTS macro is defined.
232 #define QPMS_PARANOID_ASSERT(x) {\
233 if(QPMS_UNLIKELY(!(x)))\
234 qpms_pr_error_at_flf(__FILE__,__LINE__,__func__,\
235 "Unexpected error. This is most certainly a bug.");\
238 #define QPMS_PARANOID_ASSERT(x) {;}
241 /// Raises a "not implemented" error with additional custom message.
242 /** Serves also as a label/placeholder of not implemented parts of the code. */
243 #define QPMS_NOT_IMPLEMENTED(msg, ...) qpms_pr_error_at_flf(__FILE__,__LINE__,__func__, \
244 "Not implemented:" msg, ##__VA_ARGS__)
246 /// Prints an "incomplete implementation" warning once with a custom message.
247 /** Serves mainly as a label/placeholder of incomplete parts of the code. */
248 #define QPMS_INCOMPLETE_IMPLEMENTATION(msg, ...) {\
249 static _Bool already_bitched = 0; \
250 if (QPMS_UNLIKELY(!already_bitched)) {\
251 qpms_warn_at_flf(__FILE__,__LINE__,__func__,msg, ##__VA_ARGS__);\
252 already_bitched = 1;\