kpeter@66: /* -*- C++ -*- kpeter@66: * kpeter@66: * This file is a part of LEMON, a generic C++ optimization library kpeter@66: * kpeter@66: * Copyright (C) 2003-2008 kpeter@66: * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport kpeter@66: * (Egervary Research Group on Combinatorial Optimization, EGRES). kpeter@66: * kpeter@66: * Permission to use, modify and distribute this software is granted kpeter@66: * provided that this copyright notice appears in all copies. For kpeter@66: * precise terms see the accompanying LICENSE file. kpeter@66: * kpeter@66: * This software is provided "AS IS" with no warranty of any kind, kpeter@66: * express or implied, and with no claim as to its suitability for any kpeter@66: * purpose. kpeter@66: * kpeter@66: */ kpeter@66: deba@108: #ifndef LEMON_ASSERT_H deba@108: #define LEMON_ASSERT_H kpeter@66: kpeter@66: /// \ingroup exceptions kpeter@66: /// \file deba@108: /// \brief Extended assertion handling kpeter@66: deba@108: #include kpeter@66: kpeter@66: namespace lemon { kpeter@66: kpeter@66: /// @{ kpeter@66: kpeter@66: ///\e kpeter@66: class AssertionFailedError : public LogicError { kpeter@66: protected: deba@108: const char *_assertion; deba@108: const char *_file; deba@108: int _line; deba@108: const char *_function; deba@108: const char *_message; kpeter@66: kpeter@66: mutable ExceptionMember _message_holder; kpeter@66: public: kpeter@66: ///\e deba@108: AssertionFailedError(const char *file, int line, const char *function, deba@108: const char *msg, const char *assertion = 0) : deba@108: _assertion(assertion), _file(file), _line(line), deba@108: _function(function), _message(msg) {} kpeter@66: kpeter@66: ///\e deba@108: const char* assertion() const { return _assertion; } kpeter@66: ///\e deba@108: const char* message() const { return _message; } kpeter@66: ///\e deba@108: const char* file() const { return _file; } kpeter@66: ///\e deba@108: const char* function() const { return _function; } kpeter@66: ///\e deba@108: int line() const { return _line; } kpeter@66: kpeter@66: kpeter@66: virtual const char* what() const throw() { kpeter@66: try { kpeter@66: std::ostringstream ostr; deba@108: ostr << _file << ":" << _line << ": "; deba@108: if (_function) deba@108: ostr << _function << ": "; deba@108: ostr << _message; deba@108: if (_assertion) deba@108: ostr << " (assertion '" << _assertion << "' failed)"; kpeter@66: _message_holder.set(ostr.str()); kpeter@66: return ostr.str().c_str(); kpeter@66: } kpeter@66: catch(...) {} kpeter@66: if( _message_holder.valid() ) return _message_holder.get().c_str(); kpeter@66: return "lemon::AssertionFailedError"; kpeter@66: } deba@108: virtual ~AssertionFailedError() throw() {} kpeter@66: }; kpeter@66: kpeter@66: deba@108: inline void assert_fail_log(const char *file, int line, deba@108: const char *function, deba@108: const std::exception& exception, deba@108: const char *assertion) kpeter@66: { deba@108: std::cerr << file << ":" << line << ": "; deba@108: if (function) deba@108: std::cerr << function << ": "; deba@108: std::cerr << exception.what(); kpeter@66: if (assertion) deba@108: std::cerr << " (assertion '" << assertion << "' failed)"; deba@108: std::cerr << std::endl; kpeter@66: } kpeter@66: deba@108: inline void assert_fail_log(const char *file, int line, const char *function, deba@108: const char *message, const char *assertion) kpeter@66: { deba@108: std::cerr << file << ":" << line << ": "; deba@108: if (function) deba@108: std::cerr << function << ": "; deba@108: std::cerr << message; kpeter@66: if (assertion) deba@108: std::cerr << " (assertion '" << assertion << "' failed)"; deba@108: std::cerr << std::endl; kpeter@66: } kpeter@66: deba@108: inline void assert_fail_log(const char *file, int line, const char *function, deba@108: const std::string& message, const char *assertion) kpeter@66: { deba@108: assert_fail_log(file, line, function, message.c_str(), assertion); deba@108: } deba@108: deba@108: inline void assert_fail_abort(const char *file, int line, deba@108: const char *function, deba@108: const std::exception& exception, deba@108: const char *assertion) deba@108: { kpeter@112: assert_fail_log(file, line, function, exception, assertion); deba@108: std::abort(); deba@108: } deba@108: deba@108: inline void assert_fail_abort(const char *file, int line, deba@108: const char *function, const char* message, deba@108: const char *assertion) deba@108: { kpeter@112: assert_fail_log(file, line, function, message, assertion); deba@108: std::abort(); deba@108: } deba@108: deba@108: inline void assert_fail_abort(const char *file, int line, deba@108: const char *function, deba@108: const std::string& message, deba@108: const char *assertion) deba@108: { kpeter@112: assert_fail_log(file, line, function, message.c_str(), assertion); kpeter@112: std::abort(); deba@108: } deba@108: deba@108: inline void assert_fail_error(const char *file, int line, deba@108: const char *function, deba@108: const std::exception& exception, deba@108: const char *assertion) deba@108: { deba@108: throw AssertionFailedError(file, line, function, deba@108: exception.what(), assertion); deba@108: } deba@108: deba@108: inline void assert_fail_error(const char *file, int line, deba@108: const char *function, const char *message, deba@108: const char *assertion) deba@108: { deba@108: throw AssertionFailedError(file, line, function, message, assertion); deba@108: } deba@108: deba@108: inline void assert_fail_error(const char *file, int line, deba@108: const char *function, deba@108: const std::string& message, deba@108: const char *assertion) deba@108: { kpeter@112: throw AssertionFailedError(file, line, function, message.c_str(), assertion); kpeter@66: } kpeter@66: kpeter@66: template deba@108: inline void assert_fail_exception(const char *, int, const char *, deba@108: const Exception& exception, deba@108: const char *, const std::exception* = deba@108: static_cast(0)) kpeter@66: { kpeter@66: throw exception; kpeter@66: } kpeter@66: deba@108: inline void assert_fail_exception(const char *file, int line, deba@108: const char *function, const char *message, deba@108: const char *assertion) kpeter@66: { deba@108: throw AssertionFailedError(file, line, function, message, assertion); kpeter@66: } kpeter@66: deba@108: inline void assert_fail_exception(const char *file, int line, deba@108: const char *function, deba@108: const std::string& message, deba@108: const char *assertion) kpeter@66: { kpeter@112: throw AssertionFailedError(file, line, function, message.c_str(), assertion); kpeter@66: } kpeter@66: kpeter@66: /// @} kpeter@66: kpeter@66: } deba@108: #endif // LEMON_ASSERT_H kpeter@66: kpeter@66: #undef LEMON_ASSERT kpeter@66: #undef LEMON_FIXME kpeter@66: deba@108: #if (defined(LEMON_ASSERT_LOG) ? 1 : 0) + \ deba@108: (defined(LEMON_ASSERT_ABORT) ? 1 : 0) + \ deba@108: (defined(LEMON_ASSERT_ERROR) ? 1 : 0) + \ deba@108: (defined(LEMON_ASSERT_EXCEPTION) ? 1 : 0) + \ deba@108: (defined(LEMON_ASSERT_CUSTOM) ? 1 : 0) > 1 kpeter@112: #error "LEMON assertion system is not set properly" kpeter@66: #endif kpeter@66: deba@108: #if ((defined(LEMON_ASSERT_LOG) ? 1 : 0) + \ deba@108: (defined(LEMON_ASSERT_ABORT) ? 1 : 0) + \ deba@108: (defined(LEMON_ASSERT_ERROR) ? 1 : 0) + \ deba@108: (defined(LEMON_ASSERT_EXCEPTION) ? 1 : 0) + \ deba@108: (defined(LEMON_ASSERT_CUSTOM) ? 1 : 0) == 1 || \ kpeter@112: defined(LEMON_ENABLE_ASSERTS)) && \ deba@108: defined(LEMON_DISABLE_ASSERTS) kpeter@112: #error "LEMON assertion system is not set properly" kpeter@66: #endif kpeter@66: deba@108: deba@108: #if defined LEMON_ASSERT_LOG deba@108: # undef LEMON_ASSERT_HANDLER deba@108: # define LEMON_ASSERT_HANDLER ::lemon::assert_fail_log deba@108: #elif defined LEMON_ASSERT_ABORT deba@108: # undef LEMON_ASSERT_HANDLER deba@108: # define LEMON_ASSERT_HANDLER ::lemon::assert_fail_abort deba@108: #elif defined LEMON_ASSERT_ERROR deba@108: # undef LEMON_ASSERT_HANDLER deba@108: # define LEMON_ASSERT_HANDLER ::lemon::assert_fail_error deba@108: #elif defined LEMON_ASSERT_EXCEPTION deba@108: # undef LEMON_ASSERT_HANDLER deba@108: # define LEMON_ASSERT_HANDLER ::lemon::assert_fail_exception deba@108: #elif defined LEMON_ASSERT_CUSTOM deba@108: # undef LEMON_ASSERT_HANDLER deba@108: # ifndef LEMON_CUSTOM_ASSERT_HANDLER deba@108: # error "LEMON_CUSTOM_ASSERT_HANDLER is not set" kpeter@66: # endif deba@108: # define LEMON_ASSERT_HANDLER LEMON_CUSTOM_ASSERT_HANDLER deba@108: #elif defined LEMON_ENABLE_ASSERTS deba@108: # undef LEMON_ASSERT_HANDLER deba@108: # define LEMON_ASSERT_HANDLER ::lemon::assert_fail_abort deba@108: #else deba@108: # undef LEMON_ASSERT_HANDLER deba@108: #endif deba@108: deba@108: deba@108: #ifndef LEMON_FUNCTION_NAME deba@108: # define LEMON_FUNCTION_NAME (__PRETTY_FUNCTION__) kpeter@66: #endif kpeter@66: kpeter@66: #ifdef DOXYGEN kpeter@66: deba@108: /// \ingroup exceptions deba@108: /// kpeter@112: /// \brief Macro for assertion with customizable message kpeter@66: /// kpeter@112: /// Macro for assertion with customizable message. kpeter@112: /// \param exp An expression that must be convertible to \c bool. kpeter@112: /// If it is \c false, then an assertion is raised. The concrete kpeter@112: /// behaviour depends on the settings of the assertion system. kpeter@112: /// \param msg A const char*, a const std::string& or kpeter@112: /// a const std::exception& parameter, which can be used to kpeter@112: /// provide information about the circumstances of the failed assertion. kpeter@66: /// kpeter@112: /// The assertions are disabled in the default behaviour. kpeter@112: /// You can enable them with the following code: kpeter@66: /// \code kpeter@66: /// #define LEMON_ENABLE_ASSERTS kpeter@66: /// \endcode deba@108: /// or with compilation parameters: deba@108: /// \code deba@108: /// g++ -DLEMON_ENABLE_ASSERTS deba@108: /// make CXXFLAGS='-DLEMON_ENABLE_ASSERTS' deba@108: /// \endcode deba@108: /// kpeter@112: /// The LEMON assertion system has a wide range of customization kpeter@112: /// properties. As a default behaviour the failed assertion prints a kpeter@112: /// short log message to the standard error and aborts the execution. kpeter@66: /// deba@108: /// The following modes can be used in the assertion system: kpeter@66: /// kpeter@112: /// - \c LEMON_ASSERT_LOG The failed assertion prints a short log kpeter@112: /// message to the standard error and continues the execution. kpeter@112: /// - \c LEMON_ASSERT_ABORT This mode is similar to the kpeter@112: /// \c LEMON_ASSERT_LOG, but it aborts the program. It is the default kpeter@112: /// behaviour mode when the assertions are enabled with kpeter@112: /// \c LEMON_ENABLE_ASSERTS. kpeter@112: /// - \c LEMON_ASSERT_ERROR The assertion throws an kpeter@112: /// \ref lemon::AssertionFailedError "AssertionFailedError". kpeter@112: /// If the \c msg parameter is an exception, then the result of the kpeter@112: /// \ref lemon::Exception::what() "what()" member function is passed kpeter@112: /// as error message. kpeter@112: /// - \c LEMON_ASSERT_EXCEPTION If the specified \c msg is an kpeter@112: /// exception, then it raised directly (solving that the exception deba@108: /// can not be thrown polymorphically), otherwise an \ref deba@108: /// lemon::AssertionFailedError "AssertionFailedError" is thrown with kpeter@112: /// the given parameters. kpeter@112: /// - \c LEMON_ASSERT_CUSTOM The user can define own assertion handler kpeter@112: /// functions. Three overloaded functions should be defined with the kpeter@112: /// following parameter lists: deba@108: /// \code kpeter@112: /// void custom_assert_handler(const char* file, int line, const char* function, kpeter@112: /// const char* message, const char* assertion); kpeter@112: /// void custom_assert_handler(const char* file, int line, const char* function, kpeter@112: /// const std::string& message, const char* assertion); kpeter@112: /// void custom_assert_handler(const char* file, int line, const char* function, kpeter@112: /// const std::exception& message, const char* assertion); deba@108: /// \endcode deba@108: /// The name of the functions should be defined as the \c deba@108: /// LEMON_CUSTOM_ASSERT_HANDLER macro name. deba@108: /// \code deba@108: /// #define LEMON_CUSTOM_ASSERT_HANDLER custom_assert_handler deba@108: /// \endcode deba@108: /// Whenever an assertion is occured, one of the custom assertion kpeter@112: /// handlers is called with appropiate parameters. kpeter@66: /// kpeter@112: /// The assertion mode can also be changed within one compilation unit. kpeter@112: /// If the macros are redefined with other settings and the kpeter@112: /// \ref lemon/assert.h "assert.h" file is reincluded, then the kpeter@112: /// behaviour is changed appropiately to the new settings. deba@108: # define LEMON_ASSERT(exp, msg) \ deba@108: (static_cast (!!(exp) ? 0 : ( \ deba@108: LEMON_ASSERT_HANDLER(__FILE__, __LINE__, \ deba@108: LEMON_FUNCTION_NAME, \ deba@108: msg, #exp), 0))) deba@108: deba@108: deba@108: /// \ingroup exceptions kpeter@66: /// deba@108: /// \brief Macro for mark not yet implemented features. deba@108: /// deba@108: /// Macro for mark not yet implemented features and outstanding bugs. deba@108: /// It is close to be the shortcut of the following code: deba@108: /// \code deba@108: /// LEMON_ASSERT(false, msg); deba@108: /// \endcode deba@108: # define LEMON_FIXME(msg) \ deba@108: (LEMON_ASSERT_HANDLER(__FILE__, __LINE__, LEMON_FUNCTION_NAME, \ deba@108: "FIXME: " msg, static_cast(0))) kpeter@66: kpeter@66: #else kpeter@66: deba@108: # ifndef LEMON_ASSERT_HANDLER kpeter@112: # define LEMON_ASSERT(exp, msg) (static_cast(0)) deba@108: # define LEMON_FIXME(msg) (static_cast(0)) kpeter@66: # else kpeter@66: # define LEMON_ASSERT(exp, msg) \ kpeter@66: (static_cast (!!(exp) ? 0 : ( \ kpeter@66: LEMON_ASSERT_HANDLER(__FILE__, __LINE__, \ deba@108: LEMON_FUNCTION_NAME, \ deba@108: msg, #exp), 0))) deba@108: # define LEMON_FIXME(msg) \ deba@108: (LEMON_ASSERT_HANDLER(__FILE__, __LINE__, LEMON_FUNCTION_NAME, \ deba@108: "FIXME: " msg, static_cast(0))) kpeter@66: # endif deba@108: kpeter@66: #endif kpeter@66: kpeter@66: