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