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