IMP  2.0.1
The Integrative Modeling Platform
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 */