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