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 <lemon/error.h>
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<std::string> _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 <typename Exception>
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<const Exception*>(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 <tt>const char*</tt>, a <tt>const std::string&</tt> or
kpeter@112: /// a <tt>const std::exception&</tt> 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<void> (!!(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<const char*>(0)))
kpeter@66: 
kpeter@66: #else
kpeter@66: 
deba@108: #  ifndef LEMON_ASSERT_HANDLER
kpeter@112: #    define LEMON_ASSERT(exp, msg)  (static_cast<void>(0))
deba@108: #    define LEMON_FIXME(msg) (static_cast<void>(0))
kpeter@66: #  else
kpeter@66: #    define LEMON_ASSERT(exp, msg)                 \
kpeter@66:        (static_cast<void> (!!(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<const char*>(0)))
kpeter@66: #  endif
deba@108: 
kpeter@66: #endif
kpeter@66: 
kpeter@66: