| 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 | assert_fail_log(file, line, function, exception, assertion); |
|---|
| 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 | { |
|---|
| 126 | assert_fail_log(file, line, function, message, assertion); |
|---|
| 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 | { |
|---|
| 135 | assert_fail_log(file, line, function, message.c_str(), assertion); |
|---|
| 136 | std::abort(); |
|---|
| 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 | { |
|---|
| 160 | throw AssertionFailedError(file, line, function, message.c_str(), assertion); |
|---|
| 161 | } |
|---|
| 162 | |
|---|
| 163 | template <typename Exception> |
|---|
| 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)) |
|---|
| 168 | { |
|---|
| 169 | throw exception; |
|---|
| 170 | } |
|---|
| 171 | |
|---|
| 172 | inline void assert_fail_exception(const char *file, int line, |
|---|
| 173 | const char *function, const char *message, |
|---|
| 174 | const char *assertion) |
|---|
| 175 | { |
|---|
| 176 | throw AssertionFailedError(file, line, function, message, assertion); |
|---|
| 177 | } |
|---|
| 178 | |
|---|
| 179 | inline void assert_fail_exception(const char *file, int line, |
|---|
| 180 | const char *function, |
|---|
| 181 | const std::string& message, |
|---|
| 182 | const char *assertion) |
|---|
| 183 | { |
|---|
| 184 | throw AssertionFailedError(file, line, function, message.c_str(), assertion); |
|---|
| 185 | } |
|---|
| 186 | |
|---|
| 187 | /// @} |
|---|
| 188 | |
|---|
| 189 | } |
|---|
| 190 | #endif // LEMON_ASSERT_H |
|---|
| 191 | |
|---|
| 192 | #undef LEMON_ASSERT |
|---|
| 193 | #undef LEMON_FIXME |
|---|
| 194 | |
|---|
| 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 |
|---|
| 200 | #error "LEMON assertion system is not set properly" |
|---|
| 201 | #endif |
|---|
| 202 | |
|---|
| 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 || \ |
|---|
| 208 | defined(LEMON_ENABLE_ASSERTS)) && \ |
|---|
| 209 | defined(LEMON_DISABLE_ASSERTS) |
|---|
| 210 | #error "LEMON assertion system is not set properly" |
|---|
| 211 | #endif |
|---|
| 212 | |
|---|
| 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" |
|---|
| 230 | # endif |
|---|
| 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__) |
|---|
| 242 | #endif |
|---|
| 243 | |
|---|
| 244 | #ifdef DOXYGEN |
|---|
| 245 | |
|---|
| 246 | /// \ingroup exceptions |
|---|
| 247 | /// |
|---|
| 248 | /// \brief Macro for assertion with customizable message |
|---|
| 249 | /// |
|---|
| 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. |
|---|
| 257 | /// |
|---|
| 258 | /// The assertions are disabled in the default behaviour. |
|---|
| 259 | /// You can enable them with the following code: |
|---|
| 260 | /// \code |
|---|
| 261 | /// #define LEMON_ENABLE_ASSERTS |
|---|
| 262 | /// \endcode |
|---|
| 263 | /// or with compilation parameters: |
|---|
| 264 | /// \code |
|---|
| 265 | /// g++ -DLEMON_ENABLE_ASSERTS |
|---|
| 266 | /// make CXXFLAGS='-DLEMON_ENABLE_ASSERTS' |
|---|
| 267 | /// \endcode |
|---|
| 268 | /// |
|---|
| 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. |
|---|
| 272 | /// |
|---|
| 273 | /// The following modes can be used in the assertion system: |
|---|
| 274 | /// |
|---|
| 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 |
|---|
| 288 | /// can not be thrown polymorphically), otherwise an \ref |
|---|
| 289 | /// lemon::AssertionFailedError "AssertionFailedError" is thrown with |
|---|
| 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: |
|---|
| 294 | /// \code |
|---|
| 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); |
|---|
| 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 |
|---|
| 308 | /// handlers is called with appropiate parameters. |
|---|
| 309 | /// |
|---|
| 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. |
|---|
| 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 |
|---|
| 322 | /// |
|---|
| 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))) |
|---|
| 333 | |
|---|
| 334 | #else |
|---|
| 335 | |
|---|
| 336 | # ifndef LEMON_ASSERT_HANDLER |
|---|
| 337 | # define LEMON_ASSERT(exp, msg) (static_cast<void>(0)) |
|---|
| 338 | # define LEMON_FIXME(msg) (static_cast<void>(0)) |
|---|
| 339 | # else |
|---|
| 340 | # define LEMON_ASSERT(exp, msg) \ |
|---|
| 341 | (static_cast<void> (!!(exp) ? 0 : ( \ |
|---|
| 342 | LEMON_ASSERT_HANDLER(__FILE__, __LINE__, \ |
|---|
| 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))) |
|---|
| 348 | # endif |
|---|
| 349 | |
|---|
| 350 | #endif |
|---|
| 351 | |
|---|
| 352 | |
|---|