Disable "hard" examples in CI
[qpms.git] / qpms / qpms_error.h
blobf554035c6caa6f017550c8dae4265d543fe618ad
1 /*! \file qpms_error.h
3 * \brief QPMS miscellanous internal error handling functions and macros.
5 */
6 #ifndef QPMS_ERROR_H
7 #define QPMS_ERROR_H
9 #include "optim.h"
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().
16 /**
17 * Usually not used directly, but rather via some of the macros
18 * that fill the first arguments automatically.
20 * \see QPMS_PR_ERROR
22 QPMS_NORETURN void qpms_pr_error_at_flf(const char *filename, unsigned int linenum,
23 const char *func,
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,
28 const char *func,
29 const char *fmt, ...);
31 /// Classification of debugging messages.
32 /**
33 * \see qpms_dbgmsg_enabled, qpms_dbgmsg_enable(), qpms_dbgmsg_disable()
35 typedef enum {
36 QPMS_DBGMSG_MISC = 1,
37 QPMS_DBGMSG_THREADS = 2, ///< Multithreading-related debug messages.
38 QPMS_DBGMSG_INTEGRATION = 4 ///< Quadrature-related debug messages.
39 } qpms_dbgmsg_flags;
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,
43 const char *func,
44 qpms_dbgmsg_flags type,
45 const char *fmt, ...);
47 /// Global variable determining which types of debug messages shall be printed with QPMS_DEBUG().
48 /**
49 * Use qpms_dbgmsg_enable() and qpms_dbgmsg_disable() to manipulate
50 * this variable.
52 * \see QPMS_DEBUG()
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.
65 /**
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 warning to stderr and flush the buffer – only once per run (or current thread).
71 /**
72 * The arguments are the same as in standard printf().
74 #define QPMS_WARN_ONCE(msg, ...) {\
75 static _Bool already_bitched = 0; \
76 if (QPMS_UNLIKELY(!already_bitched)) {\
77 qpms_warn_at_flf(__FILE__,__LINE__,__func__,msg, ##__VA_ARGS__);\
78 already_bitched = 1;\
83 /// Print a debugging message to stderr and flush the buffer.
84 /**
85 * The arguments after \a type are the same as in standard printf().
87 * The debugging message is printed only if the corresponding \a type flag
88 * is set in qpms_dbgmsg_enabled.
90 * \see qpms_dbgmsg_enabled
92 #define QPMS_DEBUG(type /**< Debugging message type flag, see qpms_dbgmsg_flags */ , msg, ...) qpms_debug_at_flf(__FILE__,__LINE__,__func__,type,msg, ##__VA_ARGS__)
94 /// Wrapper macro of standard malloc(), crashing on failure.
95 /**
96 * Normally corresponds to a `pointer = malloc(size)`
97 * statement; however, if NULL is returned, this prints an
98 * error message and abort()s the program.
100 * The arguments are expanded several times.
102 * Note that this macro expands to a code block, to be kept in mind when using
103 * together with if/else etc.
105 * Assigned memory block is to be deallocated with standard free().
107 * \see QPMS_CRASHING_CALLOC.
109 #define QPMS_CRASHING_MALLOC(pointer, size) {\
110 (pointer) = malloc(size);\
111 if(QPMS_UNLIKELY(!(pointer) && (size)))\
112 qpms_pr_error_at_flf(__FILE__,__LINE__,__func__,\
113 "Allocation of %zd bytes for " #pointer " failed.",\
114 (size_t) (size));\
117 /// Allocate and copy.
119 * Behaves as QPMS_CRASHING_MALLOC(dest, size), but
120 * additionaly copies a chunk of memory from \a src to \a dest.
122 * \see QPMS_CRASHING_MALLOC()
124 #define QPMS_CRASHING_MALLOCPY(dest, src, size) {\
125 (dest) = malloc(size);\
126 if(QPMS_UNLIKELY(!(dest) && (size)))\
127 qpms_pr_error_at_flf(__FILE__,__LINE__,__func__,\
128 "Allocation of %zd bytes for " #dest " failed.",\
129 (size_t) (size));\
130 memcpy((dest), (src), (size));\
133 /// Wrapper macro of standard calloc(), crashing on failure.
134 /**
135 * Normally corresponds to a `pointer = calloc(nmemb, size)`
136 * statement; however, if NULL is returned, this prints an
137 * error message and abort()s the program.
139 * The arguments are expanded several times.
141 * Note that this macro expands to a code block, to be kept in mind when using
142 * together with if/else etc.
144 * Assigned memory block is to be deallocated with standard free().
146 * \see QPMS_CRASHING_MALLOC, QPMS_CRASHING_REALLOC.
148 #define QPMS_CRASHING_CALLOC(pointer, nmemb, size) {\
149 (pointer) = calloc((nmemb), (size));\
150 if(QPMS_UNLIKELY(!(pointer) && (nmemb) && (size)))\
151 qpms_pr_error_at_flf(__FILE__,__LINE__,__func__,\
152 "Allocation of %zd bytes for " #pointer " failed.",\
153 (size_t)((nmemb)*(size)));\
156 /// Wrapper macro of standard realloc(), crashing on failure.
157 /**
158 * Normally corresponds to a `pointer = realloc(pointer, size)`
159 * statement; however, if NULL is returned, this prints an
160 * error message and abort()s the program.
162 * The arguments are expanded several times.
164 * Note that this macro expands to a code block, to be kept in mind when using
165 * together with if/else etc.
167 * Assigned memory block is to be deallocated with standard free().
169 * \see QPMS_CRASHING_MALLOC.
171 #define QPMS_CRASHING_REALLOC(pointer, size) {\
172 (pointer) = realloc((pointer), size);\
173 if(QPMS_UNLIKELY(!(pointer) && (size)))\
174 qpms_pr_error_at_flf(__FILE__,__LINE__,__func__,\
175 "Rellocation of %zd bytes for " #pointer " failed.",\
176 (size_t) (size));\
179 /// Prints an "unexpected error" message and aborts the program.
180 /** Usually only put to presumably unreachable places in the code and similar. */
181 #define QPMS_WTF qpms_pr_error_at_flf(__FILE__,__LINE__,__func__,"Unexpected error.")
183 /// Aborts the program with "invalid enumerator" error message.
184 #define QPMS_INVALID_ENUM(x) qpms_pr_error_at_flf(__FILE__,__LINE__,__func__,"Invalid enum value (" #x " == %d)", (int) (x))
186 /// Prints an "untested function/feature" warning once when reached in the code.
187 #define QPMS_UNTESTED {\
188 static _Bool already_bitched = 0; \
189 if (QPMS_UNLIKELY(!already_bitched)) {\
190 qpms_warn_at_flf(__FILE__,__LINE__,__func__,"Warning: untested function/feature!");\
191 already_bitched = 1;\
195 /// Prints a given error message and aborts the program.
196 /** The arguments are as in standard printf(). */
197 #define QPMS_PR_ERROR(msg, ...) qpms_pr_error_at_flf(__FILE__,__LINE__,__func__,msg, ##__VA_ARGS__)
199 /// Raises an error if \a x is not zero.
200 #define QPMS_ENSURE_SUCCESS(x) { \
201 int errorcode = (x); /* evaluate x only once */ \
202 if(QPMS_UNLIKELY(errorcode)) \
203 qpms_pr_error_at_flf(__FILE__,__LINE__,__func__,"Unexpected error (%d)", errorcode); \
206 /// Raises an error if \a x is not zero, with custom error message.
207 #define QPMS_ENSURE_SUCCESS_M(x, msg, ...) { \
208 int errorcode = (x); \
209 if(QPMS_UNLIKELY(errorcode)) \
210 qpms_pr_error_at_flf(__FILE__,__LINE__,__func__,msg, ##__VA_ARGS__); \
213 /// Raises an error if \a x is not zero or one of the values listed in arguments.
214 #define QPMS_ENSURE_SUCCESS_OR(x, ...) { \
215 int errorcode = (x); /* evaluate x only once */ \
216 static const int allowed_errorcodes[] = {0, ##__VA_ARGS__};\
217 static const int n_allowed = sizeof(allowed_errorcodes) / sizeof(int); \
218 int i; \
219 for(i = 0; i < n_allowed; ++i) \
220 if (errorcode == allowed_errorcodes[i]) break; \
221 if (QPMS_UNLIKELY(i >= n_allowed)) \
222 qpms_pr_error_at_flf(__FILE__,__LINE__,__func__,"Unexpected error (%d)", errorcode); \
225 /// Raises an error if \a x is not true, with custom error message.
226 #define QPMS_ENSURE(x, msg, ...) {if(QPMS_UNLIKELY(!(x))) qpms_pr_error_at_flf(__FILE__,__LINE__,__func__,msg, ##__VA_ARGS__); }
228 /// Raises an error if \a x is false.
229 /**
230 * Currently, this is always expanded, ignoring the possible NDEBUG macro.
231 * In places where the evaluation could have significant performance impact,
232 * consider using QPMS_PARANOID_ASSERT() instead.
234 #define QPMS_ASSERT(x) {\
235 if(QPMS_UNLIKELY(!(x)))\
236 qpms_pr_error_at_flf(__FILE__,__LINE__,__func__,\
237 "Unexpected error. This is most certainly a bug.");\
240 #ifdef QPMS_EVALUATE_PARANOID_ASSERTS
241 /** \brief Raises an error if \a x is false.
243 * Expanded only if QPMS_EVALUATE_PARANOID_ASSERTS macro is defined.
245 #define QPMS_PARANOID_ASSERT(x) {\
246 if(QPMS_UNLIKELY(!(x)))\
247 qpms_pr_error_at_flf(__FILE__,__LINE__,__func__,\
248 "Unexpected error. This is most certainly a bug.");\
250 #else
251 #define QPMS_PARANOID_ASSERT(x) {;}
252 #endif
254 /// Raises a "not implemented" error with additional custom message.
255 /** Serves also as a label/placeholder of not implemented parts of the code. */
256 #define QPMS_NOT_IMPLEMENTED(msg, ...) qpms_pr_error_at_flf(__FILE__,__LINE__,__func__, \
257 "Not implemented:" msg, ##__VA_ARGS__)
259 /// Prints an "incomplete implementation" warning once with a custom message.
260 /** Serves mainly as a label/placeholder of incomplete parts of the code. */
261 #define QPMS_INCOMPLETE_IMPLEMENTATION(msg, ...) {\
262 static _Bool already_bitched = 0; \
263 if (QPMS_UNLIKELY(!already_bitched)) {\
264 qpms_warn_at_flf(__FILE__,__LINE__,__func__,msg, ##__VA_ARGS__);\
265 already_bitched = 1;\
269 #endif