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