home
about
news
download
doc
source
systems
tests
bugs
contact
IMP Reference Guide
develop.63b38c487d,2024/12/21
The Integrative Modeling Platform
IMP Manual
Reference Guide
Tutorial Index
Modules
Classes
Examples
include
IMP
version 20241221.develop.63b38c487d
check_macros.h
Go to the documentation of this file.
1
/**
2
* \file IMP/check_macros.h
3
* \brief Helper macros for throwing and handling exceptions
4
*
5
* Copyright 2007-2022 IMP Inventors. All rights reserved.
6
*
7
*/
8
9
#ifndef IMPKERNEL_CHECK_MACROS_H
10
#define IMPKERNEL_CHECK_MACROS_H
11
12
#include <IMP/kernel_config.h>
13
#include "
exception.h
"
14
#include "
compiler_macros.h
"
15
#include <iostream>
16
#include <cmath>
17
18
#if !defined(IMP_HAS_CHECKS)
19
#error "IMP_HAS_CHECKS is not defined, compilation is broken"
20
#endif
21
22
#if !defined(IMP_NONE)
23
#error "IMP_NONE is not defined, compilation is broken"
24
#endif
25
26
/** Catch any IMP exception thrown by expr and terminate with an
27
error message. Use this for basic error handling in main functions
28
in C++. Do not use within the \imp library.
29
*/
30
#define IMP_CATCH_AND_TERMINATE(expr) \
31
try { \
32
expr; \
33
} \
34
catch (const IMP::Exception &e) { \
35
std::cerr << "Application terminated with error :" << e.what() \
36
<< std::endl; \
37
exit(1); \
38
}
39
40
//! Throw an exception with a message
41
/** The exception thrown must inherit from Exception and not be
42
UsageException or InternalException as those are reserved for
43
disableable checks (the IMP_INTERNAL_CHECK() and IMP_USAGE_CHECK()
44
macros).
45
\code
46
IMP_THROW("Could not open file " << file_name,
47
IOException);
48
\endcode
49
*/
50
#define IMP_THROW(message, exception_name) \
51
do { \
52
std::ostringstream imp_throw_oss; \
53
imp_throw_oss << message << std::endl; \
54
throw exception_name(imp_throw_oss.str().c_str()); \
55
} while (true)
56
57
//! Throw an exception if a check fails
58
/** Do IMP_THROW() if the check as the first argument fails. Unlike
59
IMP_USAGE_CHECK() and IMP_INTERNAL_CHECK() these checks are
60
always present.*/
61
#define IMP_ALWAYS_CHECK(condition, message, exception_name) \
62
if (!(condition)) { \
63
IMP_THROW(message, exception_name); \
64
}
65
66
//! A runtime failure for IMP.
67
/** \param[in] message Failure message to write.
68
This macro is used to provide nice error messages when there is
69
an internal error in \imp. It causes an IMP::InternalException to be
70
thrown.
71
*/
72
#define IMP_FAILURE(message) \
73
do { \
74
std::ostringstream imp_failure_oss; \
75
imp_failure_oss << message << std::endl; \
76
IMP::handle_error(imp_failure_oss.str().c_str()); \
77
throw IMP::InternalException(imp_failure_oss.str().c_str()); \
78
} while (true)
79
80
//! Use this to mark that the method is not implemented yet
81
#define IMP_NOT_IMPLEMENTED \
82
do { \
83
IMP::handle_error("This method is not implemented."); \
84
throw IMP::InternalException("Not implemented"); \
85
} while (true)
86
87
#ifdef IMP_DOXYGEN
88
89
//! Execute the code block if a certain level checks are on
90
/**
91
The next code block (delimited by { }) is executed if
92
get_check_level() <= level.
93
94
For example:
95
\code
96
IMP_IF_CHECK(USAGE) {
97
Vector<Particle*> testp(input.begin(), input.end());
98
std::sort(testp.begin(), testp.end());
99
IMP_USAGE_CHECK(std::unique(testp.begin(), testp.end()) == testp.end(),
100
"Duplicate particles found in the input list.");
101
}
102
\endcode
103
*/
104
#define IMP_IF_CHECK(level)
105
106
//! Only compile the code if checks are enabled
107
/** For example
108
\code
109
IMP_CHECK_CODE({
110
Vector<Particle*> testp(input.begin(), input.end());
111
std::sort(testp.begin(), testp.end());
112
IMP_USAGE_CHECK(std::unique(testp.begin(), testp.end()) == testp.end(),
113
"Duplicate particles found in the input list.");
114
});
115
\endcode
116
**/
117
#define IMP_CHECK_CODE(expr)
118
119
/** \brief An assertion to check for internal errors in \imp. An
120
IMP::ErrorException will be thrown.
121
122
Since it is a debug-only check and no attempt should be made to
123
recover from it, the exception type cannot be specified.
124
125
For example:
126
\code
127
IMP_INTERNAL_CHECK((3.14-PI) < .01,
128
"PI is not close to 3.14. It is instead " << PI);
129
\endcode
130
131
\note if the code is compiled with 'fast', or the check level is
132
less than IMP::USAGE_AND_INTERNAL, the check is not performed. Do
133
not use asserts as a shorthand to throw exceptions (throw the
134
exception yourself); use them only to check for logic errors.
135
136
\param[in] expr The assertion expression.
137
\param[in] message Write this message if the assertion fails.
138
*/
139
#define IMP_INTERNAL_CHECK(expr, message)
140
141
/** This is like IMP_INTERNAL_CHECK, however designed to check if
142
two floating point numbers are almost equal. The check looks something
143
like
144
\code
145
std::abs(a-b) < .1*(a+b)+.1
146
\endcode
147
Using this makes such tests a bit easier to spot and not mess up.
148
*/
149
#define IMP_INTERNAL_CHECK_FLOAT_EQUAL(expra, exprb, message)
150
151
//! A runtime test for incorrect usage of a class or method.
152
/** \param[in] expr The assertion expression.
153
\param[in] message Write this message if the assertion fails.
154
155
It should be used to check arguments to function. For example
156
\code
157
IMP_USAGE_CHECK(positive_argument >0,
158
"Argument positive_argument to function my_function "
159
<< " must be positive. Instead got " << positive_argument);
160
\endcode
161
162
\note if the build is 'fast', or the check level
163
is less than IMP::USAGE, the check is not performed. Do not use these
164
checks as a shorthand to throw necessary exceptions (throw the
165
exception yourself); use them only to check for errors, such as
166
inappropriate input.
167
*/
168
#define IMP_USAGE_CHECK(expr, message)
169
170
/** This is like IMP_USAGE_CHECK, however designed to check if
171
two floating point numbers are almost equal. The check looks something
172
like
173
\code
174
std::abs(a-b) < .1*(a+b)+.1
175
\endcode
176
Using this makes such tests a bit easier to spot and not mess up.
177
*/
178
#define IMP_USAGE_CHECK_FLOAT_EQUAL(expra, exprb, message)
179
180
#ifndef IMP_DOXYGEN
181
/** Mark a variable as one that is only used in checks. This disables
182
unused variable warnings on it in fast mode.
183
*/
184
#define IMP_CHECK_VARIABLE(variable)
185
#endif
186
187
/** Mark a variable as one that is only used in checks. This disables
188
unused variable warnings on it in fast mode.
189
*/
190
#define IMP_USAGE_CHECK_VARIABLE(variable)
191
192
/** Mark a variable as one that is only used in checks. This disables
193
unused variable warnings on it in fast mode.
194
*/
195
#define IMP_INTERNAL_CHECK_VARIABLE(variable)
196
197
#else // IMP_DOXYGEN
198
199
#if IMP_HAS_CHECKS == IMP_INTERNAL
200
#define IMP_CHECK_VARIABLE(variable)
201
#define IMP_USAGE_CHECK_VARIABLE(variable)
202
#define IMP_INTERNAL_CHECK_VARIABLE(variable)
203
#elif IMP_HAS_CHECKS == IMP_USAGE
204
#define IMP_CHECK_VARIABLE(variable)
205
#define IMP_USAGE_CHECK_VARIABLE(variable)
206
#define IMP_INTERNAL_CHECK_VARIABLE(variable) IMP_UNUSED(variable)
207
#else
208
#define IMP_CHECK_VARIABLE(variable) IMP_UNUSED(variable)
209
#define IMP_USAGE_CHECK_VARIABLE(variable) IMP_UNUSED(variable)
210
#define IMP_INTERNAL_CHECK_VARIABLE(variable) IMP_UNUSED(variable)
211
#endif
212
213
#if IMP_HAS_CHECKS > IMP_NONE
214
#define IMP_IF_CHECK(level) \
215
if (level <= ::IMP::get_check_level())
216
217
#define IMP_CHECK_CODE(expr) expr
218
219
#if IMP_KERNEL_HAS_LOG4CXX
220
#define IMP_KERNEL_CONTEXT
221
#else
222
#define IMP_KERNEL_CONTEXT << IMP::get_context_message()
223
#endif
224
225
#else // IMP_HAS_CHECKS == IMP_NONE
226
#define IMP_IF_CHECK(level) if (0)
227
#define IMP_CHECK_CODE(expr)
228
#endif // IMP_HAS_CHECKS
229
230
#if IMP_HAS_CHECKS >= IMP_INTERNAL
231
#define IMP_INTERNAL_CHECK(expr, message) \
232
do { \
233
if (IMP::get_check_level() >= IMP::USAGE_AND_INTERNAL && \
234
!(expr)) { \
235
std::ostringstream imp_check_oss; \
236
imp_check_oss << "Internal check failure: " << message << std::endl \
237
<< " File \"" << __FILE__ << "\", line " \
238
<< __LINE__ IMP_KERNEL_CONTEXT << std::endl; \
239
IMP::handle_error(imp_check_oss.str().c_str()); \
240
throw IMP::InternalException(imp_check_oss.str().c_str()); \
241
} \
242
} while (false)
243
244
#define IMP_INTERNAL_CHECK_FLOAT_EQUAL(expra, exprb, message) \
245
IMP_INTERNAL_CHECK( \
246
std::abs((expra) - (exprb)) < .1 * std::abs((expra) + (exprb)) + .1, \
247
(expra) << " != " << (exprb) << " - " << message)
248
#else
249
#define IMP_INTERNAL_CHECK(expr, message)
250
#define IMP_INTERNAL_CHECK_FLOAT_EQUAL(expra, exprb, message)
251
#endif
252
253
#if IMP_HAS_CHECKS >= IMP_USAGE
254
#define IMP_USAGE_CHECK(expr, message) \
255
do { \
256
if (IMP::get_check_level() >= IMP::USAGE && !(expr)) { \
257
std::ostringstream imp_check_oss; \
258
imp_check_oss << "Usage check failure: " << message IMP_KERNEL_CONTEXT \
259
<< std::endl; \
260
IMP::handle_error(imp_check_oss.str().c_str()); \
261
throw IMP::UsageException(imp_check_oss.str().c_str()); \
262
} \
263
} while (false)
264
#define IMP_USAGE_CHECK_FLOAT_EQUAL(expra, exprb, message) \
265
IMP_USAGE_CHECK( \
266
std::abs((expra) - (exprb)) < .1 * std::abs((expra) + (exprb)) + .1, \
267
expra << " != " << exprb << " - " << message)
268
#else
269
#define IMP_USAGE_CHECK(expr, message)
270
#define IMP_USAGE_CHECK_FLOAT_EQUAL(expra, exprb, message)
271
#endif
272
273
#endif // IMP_DOXYGEN
274
275
#if defined(IMP_DOXYGEN) || IMP_HAS_CHECKS == IMP_NONE
276
//! Perform some basic validity checks on the object for memory debugging
277
#define IMP_CHECK_OBJECT(obj) IMP_UNUSED(obj)
278
#define IMP_CHECK_OBJECT_IF_NOT_nullptr(obj) IMP_UNUSED(obj)
279
#else
280
281
#define IMP_CHECK_OBJECT(obj) \
282
do { \
283
IMP_UNUSED(obj); \
284
IMP_INTERNAL_CHECK((obj!=nullptr), "nullptr object"); \
285
IMP_INTERNAL_CHECK((obj)->get_is_valid(), \
286
"Check object " << static_cast<const void *>(obj) \
287
<< " was previously freed"); \
288
} while (false)
289
290
#define IMP_CHECK_OBJECT_IF_NOT_nullptr(obj) \
291
do { \
292
if (obj) { \
293
IMP_INTERNAL_CHECK((obj)->get_is_valid(), \
294
"Check object " << static_cast<const void *>(obj) \
295
<< " was previously freed"); \
296
} \
297
} while (false)
298
#endif
299
300
#endif
/* IMPKERNEL_CHECK_MACROS_H */
exception.h
Exception definitions and assertions.
compiler_macros.h
Various compiler workarounds.