[66] | 1 | /* -*- C++ -*- |
---|
| 2 | * |
---|
| 3 | * This file is a part of LEMON, a generic C++ optimization library |
---|
| 4 | * |
---|
| 5 | * Copyright (C) 2003-2008 |
---|
| 6 | * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport |
---|
| 7 | * (Egervary Research Group on Combinatorial Optimization, EGRES). |
---|
| 8 | * |
---|
| 9 | * Permission to use, modify and distribute this software is granted |
---|
| 10 | * provided that this copyright notice appears in all copies. For |
---|
| 11 | * precise terms see the accompanying LICENSE file. |
---|
| 12 | * |
---|
| 13 | * This software is provided "AS IS" with no warranty of any kind, |
---|
| 14 | * express or implied, and with no claim as to its suitability for any |
---|
| 15 | * purpose. |
---|
| 16 | * |
---|
| 17 | */ |
---|
| 18 | |
---|
[108] | 19 | #ifndef LEMON_ASSERT_H |
---|
| 20 | #define LEMON_ASSERT_H |
---|
[66] | 21 | |
---|
| 22 | /// \ingroup exceptions |
---|
| 23 | /// \file |
---|
[108] | 24 | /// \brief Extended assertion handling |
---|
[66] | 25 | |
---|
[108] | 26 | #include <lemon/error.h> |
---|
[66] | 27 | |
---|
| 28 | namespace lemon { |
---|
| 29 | |
---|
| 30 | /// @{ |
---|
| 31 | |
---|
| 32 | ///\e |
---|
| 33 | class AssertionFailedError : public LogicError { |
---|
| 34 | protected: |
---|
[108] | 35 | const char *_assertion; |
---|
| 36 | const char *_file; |
---|
| 37 | int _line; |
---|
| 38 | const char *_function; |
---|
| 39 | const char *_message; |
---|
[66] | 40 | |
---|
| 41 | mutable ExceptionMember<std::string> _message_holder; |
---|
| 42 | public: |
---|
| 43 | ///\e |
---|
[108] | 44 | AssertionFailedError(const char *file, int line, const char *function, |
---|
| 45 | const char *msg, const char *assertion = 0) : |
---|
| 46 | _assertion(assertion), _file(file), _line(line), |
---|
| 47 | _function(function), _message(msg) {} |
---|
[66] | 48 | |
---|
| 49 | ///\e |
---|
[108] | 50 | const char* assertion() const { return _assertion; } |
---|
[66] | 51 | ///\e |
---|
[108] | 52 | const char* message() const { return _message; } |
---|
[66] | 53 | ///\e |
---|
[108] | 54 | const char* file() const { return _file; } |
---|
[66] | 55 | ///\e |
---|
[108] | 56 | const char* function() const { return _function; } |
---|
[66] | 57 | ///\e |
---|
[108] | 58 | int line() const { return _line; } |
---|
[66] | 59 | |
---|
| 60 | |
---|
| 61 | virtual const char* what() const throw() { |
---|
| 62 | try { |
---|
| 63 | std::ostringstream ostr; |
---|
[108] | 64 | ostr << _file << ":" << _line << ": "; |
---|
| 65 | if (_function) |
---|
| 66 | ostr << _function << ": "; |
---|
| 67 | ostr << _message; |
---|
| 68 | if (_assertion) |
---|
| 69 | ostr << " (assertion '" << _assertion << "' failed)"; |
---|
[66] | 70 | _message_holder.set(ostr.str()); |
---|
| 71 | return ostr.str().c_str(); |
---|
| 72 | } |
---|
| 73 | catch(...) {} |
---|
| 74 | if( _message_holder.valid() ) return _message_holder.get().c_str(); |
---|
| 75 | return "lemon::AssertionFailedError"; |
---|
| 76 | } |
---|
[108] | 77 | virtual ~AssertionFailedError() throw() {} |
---|
[66] | 78 | }; |
---|
| 79 | |
---|
| 80 | |
---|
[108] | 81 | inline void assert_fail_log(const char *file, int line, |
---|
| 82 | const char *function, |
---|
| 83 | const std::exception& exception, |
---|
| 84 | const char *assertion) |
---|
[66] | 85 | { |
---|
[108] | 86 | std::cerr << file << ":" << line << ": "; |
---|
| 87 | if (function) |
---|
| 88 | std::cerr << function << ": "; |
---|
| 89 | std::cerr << exception.what(); |
---|
[66] | 90 | if (assertion) |
---|
[108] | 91 | std::cerr << " (assertion '" << assertion << "' failed)"; |
---|
| 92 | std::cerr << std::endl; |
---|
[66] | 93 | } |
---|
| 94 | |
---|
[108] | 95 | inline void assert_fail_log(const char *file, int line, const char *function, |
---|
| 96 | const char *message, const char *assertion) |
---|
[66] | 97 | { |
---|
[108] | 98 | std::cerr << file << ":" << line << ": "; |
---|
| 99 | if (function) |
---|
| 100 | std::cerr << function << ": "; |
---|
| 101 | std::cerr << message; |
---|
[66] | 102 | if (assertion) |
---|
[108] | 103 | std::cerr << " (assertion '" << assertion << "' failed)"; |
---|
| 104 | std::cerr << std::endl; |
---|
[66] | 105 | } |
---|
| 106 | |
---|
[108] | 107 | inline void assert_fail_log(const char *file, int line, const char *function, |
---|
| 108 | const std::string& message, const char *assertion) |
---|
[66] | 109 | { |
---|
[108] | 110 | assert_fail_log(file, line, function, message.c_str(), assertion); |
---|
| 111 | } |
---|
| 112 | |
---|
| 113 | inline void assert_fail_abort(const char *file, int line, |
---|
| 114 | const char *function, |
---|
| 115 | const std::exception& exception, |
---|
| 116 | const char *assertion) |
---|
| 117 | { |
---|
[112] | 118 | assert_fail_log(file, line, function, exception, assertion); |
---|
[108] | 119 | std::abort(); |
---|
| 120 | } |
---|
| 121 | |
---|
| 122 | inline void assert_fail_abort(const char *file, int line, |
---|
| 123 | const char *function, const char* message, |
---|
| 124 | const char *assertion) |
---|
| 125 | { |
---|
[112] | 126 | assert_fail_log(file, line, function, message, assertion); |
---|
[108] | 127 | std::abort(); |
---|
| 128 | } |
---|
| 129 | |
---|
| 130 | inline void assert_fail_abort(const char *file, int line, |
---|
| 131 | const char *function, |
---|
| 132 | const std::string& message, |
---|
| 133 | const char *assertion) |
---|
| 134 | { |
---|
[112] | 135 | assert_fail_log(file, line, function, message.c_str(), assertion); |
---|
| 136 | std::abort(); |
---|
[108] | 137 | } |
---|
| 138 | |
---|
| 139 | inline void assert_fail_error(const char *file, int line, |
---|
| 140 | const char *function, |
---|
| 141 | const std::exception& exception, |
---|
| 142 | const char *assertion) |
---|
| 143 | { |
---|
| 144 | throw AssertionFailedError(file, line, function, |
---|
| 145 | exception.what(), assertion); |
---|
| 146 | } |
---|
| 147 | |
---|
| 148 | inline void assert_fail_error(const char *file, int line, |
---|
| 149 | const char *function, const char *message, |
---|
| 150 | const char *assertion) |
---|
| 151 | { |
---|
| 152 | throw AssertionFailedError(file, line, function, message, assertion); |
---|
| 153 | } |
---|
| 154 | |
---|
| 155 | inline void assert_fail_error(const char *file, int line, |
---|
| 156 | const char *function, |
---|
| 157 | const std::string& message, |
---|
| 158 | const char *assertion) |
---|
| 159 | { |
---|
[112] | 160 | throw AssertionFailedError(file, line, function, message.c_str(), assertion); |
---|
[66] | 161 | } |
---|
| 162 | |
---|
| 163 | template <typename Exception> |
---|
[108] | 164 | inline void assert_fail_exception(const char *, int, const char *, |
---|
| 165 | const Exception& exception, |
---|
| 166 | const char *, const std::exception* = |
---|
| 167 | static_cast<const Exception*>(0)) |
---|
[66] | 168 | { |
---|
| 169 | throw exception; |
---|
| 170 | } |
---|
| 171 | |
---|
[108] | 172 | inline void assert_fail_exception(const char *file, int line, |
---|
| 173 | const char *function, const char *message, |
---|
| 174 | const char *assertion) |
---|
[66] | 175 | { |
---|
[108] | 176 | throw AssertionFailedError(file, line, function, message, assertion); |
---|
[66] | 177 | } |
---|
| 178 | |
---|
[108] | 179 | inline void assert_fail_exception(const char *file, int line, |
---|
| 180 | const char *function, |
---|
| 181 | const std::string& message, |
---|
| 182 | const char *assertion) |
---|
[66] | 183 | { |
---|
[112] | 184 | throw AssertionFailedError(file, line, function, message.c_str(), assertion); |
---|
[66] | 185 | } |
---|
| 186 | |
---|
| 187 | /// @} |
---|
| 188 | |
---|
| 189 | } |
---|
[108] | 190 | #endif // LEMON_ASSERT_H |
---|
[66] | 191 | |
---|
| 192 | #undef LEMON_ASSERT |
---|
| 193 | #undef LEMON_FIXME |
---|
| 194 | |
---|
[108] | 195 | #if (defined(LEMON_ASSERT_LOG) ? 1 : 0) + \ |
---|
| 196 | (defined(LEMON_ASSERT_ABORT) ? 1 : 0) + \ |
---|
| 197 | (defined(LEMON_ASSERT_ERROR) ? 1 : 0) + \ |
---|
| 198 | (defined(LEMON_ASSERT_EXCEPTION) ? 1 : 0) + \ |
---|
| 199 | (defined(LEMON_ASSERT_CUSTOM) ? 1 : 0) > 1 |
---|
[112] | 200 | #error "LEMON assertion system is not set properly" |
---|
[66] | 201 | #endif |
---|
| 202 | |
---|
[108] | 203 | #if ((defined(LEMON_ASSERT_LOG) ? 1 : 0) + \ |
---|
| 204 | (defined(LEMON_ASSERT_ABORT) ? 1 : 0) + \ |
---|
| 205 | (defined(LEMON_ASSERT_ERROR) ? 1 : 0) + \ |
---|
| 206 | (defined(LEMON_ASSERT_EXCEPTION) ? 1 : 0) + \ |
---|
| 207 | (defined(LEMON_ASSERT_CUSTOM) ? 1 : 0) == 1 || \ |
---|
[112] | 208 | defined(LEMON_ENABLE_ASSERTS)) && \ |
---|
[108] | 209 | defined(LEMON_DISABLE_ASSERTS) |
---|
[112] | 210 | #error "LEMON assertion system is not set properly" |
---|
[66] | 211 | #endif |
---|
| 212 | |
---|
[108] | 213 | |
---|
| 214 | #if defined LEMON_ASSERT_LOG |
---|
| 215 | # undef LEMON_ASSERT_HANDLER |
---|
| 216 | # define LEMON_ASSERT_HANDLER ::lemon::assert_fail_log |
---|
| 217 | #elif defined LEMON_ASSERT_ABORT |
---|
| 218 | # undef LEMON_ASSERT_HANDLER |
---|
| 219 | # define LEMON_ASSERT_HANDLER ::lemon::assert_fail_abort |
---|
| 220 | #elif defined LEMON_ASSERT_ERROR |
---|
| 221 | # undef LEMON_ASSERT_HANDLER |
---|
| 222 | # define LEMON_ASSERT_HANDLER ::lemon::assert_fail_error |
---|
| 223 | #elif defined LEMON_ASSERT_EXCEPTION |
---|
| 224 | # undef LEMON_ASSERT_HANDLER |
---|
| 225 | # define LEMON_ASSERT_HANDLER ::lemon::assert_fail_exception |
---|
| 226 | #elif defined LEMON_ASSERT_CUSTOM |
---|
| 227 | # undef LEMON_ASSERT_HANDLER |
---|
| 228 | # ifndef LEMON_CUSTOM_ASSERT_HANDLER |
---|
| 229 | # error "LEMON_CUSTOM_ASSERT_HANDLER is not set" |
---|
[66] | 230 | # endif |
---|
[108] | 231 | # define LEMON_ASSERT_HANDLER LEMON_CUSTOM_ASSERT_HANDLER |
---|
| 232 | #elif defined LEMON_ENABLE_ASSERTS |
---|
| 233 | # undef LEMON_ASSERT_HANDLER |
---|
| 234 | # define LEMON_ASSERT_HANDLER ::lemon::assert_fail_abort |
---|
| 235 | #else |
---|
| 236 | # undef LEMON_ASSERT_HANDLER |
---|
| 237 | #endif |
---|
| 238 | |
---|
| 239 | |
---|
| 240 | #ifndef LEMON_FUNCTION_NAME |
---|
| 241 | # define LEMON_FUNCTION_NAME (__PRETTY_FUNCTION__) |
---|
[66] | 242 | #endif |
---|
| 243 | |
---|
| 244 | #ifdef DOXYGEN |
---|
| 245 | |
---|
[108] | 246 | /// \ingroup exceptions |
---|
| 247 | /// |
---|
[112] | 248 | /// \brief Macro for assertion with customizable message |
---|
[66] | 249 | /// |
---|
[112] | 250 | /// Macro for assertion with customizable message. |
---|
| 251 | /// \param exp An expression that must be convertible to \c bool. |
---|
| 252 | /// If it is \c false, then an assertion is raised. The concrete |
---|
| 253 | /// behaviour depends on the settings of the assertion system. |
---|
| 254 | /// \param msg A <tt>const char*</tt>, a <tt>const std::string&</tt> or |
---|
| 255 | /// a <tt>const std::exception&</tt> parameter, which can be used to |
---|
| 256 | /// provide information about the circumstances of the failed assertion. |
---|
[66] | 257 | /// |
---|
[112] | 258 | /// The assertions are disabled in the default behaviour. |
---|
| 259 | /// You can enable them with the following code: |
---|
[66] | 260 | /// \code |
---|
| 261 | /// #define LEMON_ENABLE_ASSERTS |
---|
| 262 | /// \endcode |
---|
[108] | 263 | /// or with compilation parameters: |
---|
| 264 | /// \code |
---|
| 265 | /// g++ -DLEMON_ENABLE_ASSERTS |
---|
| 266 | /// make CXXFLAGS='-DLEMON_ENABLE_ASSERTS' |
---|
| 267 | /// \endcode |
---|
| 268 | /// |
---|
[112] | 269 | /// The LEMON assertion system has a wide range of customization |
---|
| 270 | /// properties. As a default behaviour the failed assertion prints a |
---|
| 271 | /// short log message to the standard error and aborts the execution. |
---|
[66] | 272 | /// |
---|
[108] | 273 | /// The following modes can be used in the assertion system: |
---|
[66] | 274 | /// |
---|
[112] | 275 | /// - \c LEMON_ASSERT_LOG The failed assertion prints a short log |
---|
| 276 | /// message to the standard error and continues the execution. |
---|
| 277 | /// - \c LEMON_ASSERT_ABORT This mode is similar to the |
---|
| 278 | /// \c LEMON_ASSERT_LOG, but it aborts the program. It is the default |
---|
| 279 | /// behaviour mode when the assertions are enabled with |
---|
| 280 | /// \c LEMON_ENABLE_ASSERTS. |
---|
| 281 | /// - \c LEMON_ASSERT_ERROR The assertion throws an |
---|
| 282 | /// \ref lemon::AssertionFailedError "AssertionFailedError". |
---|
| 283 | /// If the \c msg parameter is an exception, then the result of the |
---|
| 284 | /// \ref lemon::Exception::what() "what()" member function is passed |
---|
| 285 | /// as error message. |
---|
| 286 | /// - \c LEMON_ASSERT_EXCEPTION If the specified \c msg is an |
---|
| 287 | /// exception, then it raised directly (solving that the exception |
---|
[108] | 288 | /// can not be thrown polymorphically), otherwise an \ref |
---|
| 289 | /// lemon::AssertionFailedError "AssertionFailedError" is thrown with |
---|
[112] | 290 | /// the given parameters. |
---|
| 291 | /// - \c LEMON_ASSERT_CUSTOM The user can define own assertion handler |
---|
| 292 | /// functions. Three overloaded functions should be defined with the |
---|
| 293 | /// following parameter lists: |
---|
[108] | 294 | /// \code |
---|
[112] | 295 | /// void custom_assert_handler(const char* file, int line, const char* function, |
---|
| 296 | /// const char* message, const char* assertion); |
---|
| 297 | /// void custom_assert_handler(const char* file, int line, const char* function, |
---|
| 298 | /// const std::string& message, const char* assertion); |
---|
| 299 | /// void custom_assert_handler(const char* file, int line, const char* function, |
---|
| 300 | /// const std::exception& message, const char* assertion); |
---|
[108] | 301 | /// \endcode |
---|
| 302 | /// The name of the functions should be defined as the \c |
---|
| 303 | /// LEMON_CUSTOM_ASSERT_HANDLER macro name. |
---|
| 304 | /// \code |
---|
| 305 | /// #define LEMON_CUSTOM_ASSERT_HANDLER custom_assert_handler |
---|
| 306 | /// \endcode |
---|
| 307 | /// Whenever an assertion is occured, one of the custom assertion |
---|
[112] | 308 | /// handlers is called with appropiate parameters. |
---|
[66] | 309 | /// |
---|
[112] | 310 | /// The assertion mode can also be changed within one compilation unit. |
---|
| 311 | /// If the macros are redefined with other settings and the |
---|
| 312 | /// \ref lemon/assert.h "assert.h" file is reincluded, then the |
---|
| 313 | /// behaviour is changed appropiately to the new settings. |
---|
[108] | 314 | # define LEMON_ASSERT(exp, msg) \ |
---|
| 315 | (static_cast<void> (!!(exp) ? 0 : ( \ |
---|
| 316 | LEMON_ASSERT_HANDLER(__FILE__, __LINE__, \ |
---|
| 317 | LEMON_FUNCTION_NAME, \ |
---|
| 318 | msg, #exp), 0))) |
---|
| 319 | |
---|
| 320 | |
---|
| 321 | /// \ingroup exceptions |
---|
[66] | 322 | /// |
---|
[108] | 323 | /// \brief Macro for mark not yet implemented features. |
---|
| 324 | /// |
---|
| 325 | /// Macro for mark not yet implemented features and outstanding bugs. |
---|
| 326 | /// It is close to be the shortcut of the following code: |
---|
| 327 | /// \code |
---|
| 328 | /// LEMON_ASSERT(false, msg); |
---|
| 329 | /// \endcode |
---|
| 330 | # define LEMON_FIXME(msg) \ |
---|
| 331 | (LEMON_ASSERT_HANDLER(__FILE__, __LINE__, LEMON_FUNCTION_NAME, \ |
---|
| 332 | "FIXME: " msg, static_cast<const char*>(0))) |
---|
[66] | 333 | |
---|
| 334 | #else |
---|
| 335 | |
---|
[108] | 336 | # ifndef LEMON_ASSERT_HANDLER |
---|
[112] | 337 | # define LEMON_ASSERT(exp, msg) (static_cast<void>(0)) |
---|
[108] | 338 | # define LEMON_FIXME(msg) (static_cast<void>(0)) |
---|
[66] | 339 | # else |
---|
| 340 | # define LEMON_ASSERT(exp, msg) \ |
---|
| 341 | (static_cast<void> (!!(exp) ? 0 : ( \ |
---|
| 342 | LEMON_ASSERT_HANDLER(__FILE__, __LINE__, \ |
---|
[108] | 343 | LEMON_FUNCTION_NAME, \ |
---|
| 344 | msg, #exp), 0))) |
---|
| 345 | # define LEMON_FIXME(msg) \ |
---|
| 346 | (LEMON_ASSERT_HANDLER(__FILE__, __LINE__, LEMON_FUNCTION_NAME, \ |
---|
| 347 | "FIXME: " msg, static_cast<const char*>(0))) |
---|
[66] | 348 | # endif |
---|
[108] | 349 | |
---|
[66] | 350 | #endif |
---|
| 351 | |
---|
| 352 | |
---|