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