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