alpar@209: /* -*- mode: C++; indent-tabs-mode: nil; -*-
kpeter@66:  *
alpar@209:  * 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: 
deba@277:   inline void assert_fail_abort(const char *file, int line,
deba@277:                                 const char *function, const char* message,
deba@277:                                 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;
deba@108:     std::abort();
deba@108:   }
deba@108: 
deba@118:   namespace _assert_bits {
alpar@209: 
alpar@209: 
deba@118:     inline const char* cstringify(const std::string& str) {
deba@118:       return str.c_str();
deba@118:     }
deba@118: 
deba@118:     inline const char* cstringify(const char* str) {
deba@118:       return str;
alpar@209:     }
deba@108:   }
deba@118: }
deba@108: 
deba@108: #endif // LEMON_ASSERT_H
kpeter@66: 
kpeter@66: #undef LEMON_ASSERT
deba@118: #undef LEMON_DEBUG
kpeter@66: 
deba@277: #if (defined(LEMON_ASSERT_ABORT) ? 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@277: #if ((defined(LEMON_ASSERT_ABORT) ? 1 : 0) +            \
kpeter@212:      (defined(LEMON_ASSERT_CUSTOM) ? 1 : 0) == 1 ||     \
kpeter@212:      defined(LEMON_ENABLE_ASSERTS)) &&                  \
kpeter@212:   (defined(LEMON_DISABLE_ASSERTS) ||                    \
deba@118:    defined(NDEBUG))
kpeter@112: #error "LEMON assertion system is not set properly"
kpeter@66: #endif
kpeter@66: 
deba@108: 
deba@277: #if 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_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@118: #elif defined LEMON_DISABLE_ASSERTS
deba@108: #  undef LEMON_ASSERT_HANDLER
deba@118: #elif defined NDEBUG
deba@118: #  undef LEMON_ASSERT_HANDLER
deba@118: #else
deba@108: #  define LEMON_ASSERT_HANDLER ::lemon::assert_fail_abort
deba@108: #endif
deba@108: 
deba@108: #ifndef LEMON_FUNCTION_NAME
ladanyi@142: #  if defined __GNUC__
ladanyi@142: #    define LEMON_FUNCTION_NAME (__PRETTY_FUNCTION__)
ladanyi@142: #  elif defined _MSC_VER
ladanyi@142: #    define LEMON_FUNCTION_NAME (__FUNCSIG__)
ladanyi@266: #  elif __STDC_VERSION__ >= 199901L
ladanyi@266: #    define LEMON_FUNCTION_NAME (__func__)
ladanyi@142: #  else
ladanyi@266: #    define LEMON_FUNCTION_NAME ("<unknown>")
ladanyi@142: #  endif
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: ///
deba@290: /// Macro for assertion with customizable message.
deba@277: /// \param exp An expression that must be convertible to \c bool.  If it is \c
deba@277: /// false, then an assertion is raised. The concrete behaviour depends on the
deba@277: /// settings of the assertion system.
deba@277: /// \param msg A <tt>const char*</tt> parameter, which can be used to provide
deba@277: /// information about the circumstances of the failed assertion.
kpeter@66: ///
deba@118: /// The assertions are enabled in the default behaviour.
deba@118: /// You can disable them with the following code:
kpeter@66: /// \code
deba@118: /// #define LEMON_DISABLE_ASSERTS
kpeter@66: /// \endcode
deba@108: /// or with compilation parameters:
deba@108: /// \code
deba@118: /// g++ -DLEMON_DISABLE_ASSERTS
deba@118: /// make CXXFLAGS='-DLEMON_DISABLE_ASSERTS'
deba@108: /// \endcode
deba@118: /// The checking is also disabled when the standard macro \c NDEBUG is defined.
alpar@209: ///
deba@277: /// As a default behaviour the failed assertion prints a short log message to
deba@277: /// the standard error and aborts the execution.
kpeter@66: ///
deba@277: /// However, the following modes can be used in the assertion system:
deba@277: /// - \c LEMON_ASSERT_ABORT The failed assertion prints a short log message to
deba@277: ///   the standard error and aborts the program. It is the default behaviour.
kpeter@112: /// - \c LEMON_ASSERT_CUSTOM The user can define own assertion handler
deba@118: ///   function.
deba@108: ///   \code
alpar@210: ///     void custom_assert_handler(const char* file, int line,
alpar@210: ///                                const char* function, const char* message,
alpar@210: ///                                const char* assertion);
deba@108: ///   \endcode
deba@118: ///   The name of the function should be defined as the \c
alpar@209: ///   LEMON_CUSTOM_ASSERT_HANDLER macro name.
deba@108: ///   \code
deba@108: ///     #define LEMON_CUSTOM_ASSERT_HANDLER custom_assert_handler
deba@108: ///   \endcode
deba@118: ///   Whenever an assertion is occured, the custom assertion
deba@118: ///   handler 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.
alpar@209: #  define LEMON_ASSERT(exp, msg)                                        \
kpeter@212:   (static_cast<void> (!!(exp) ? 0 : (                                   \
kpeter@212:     LEMON_ASSERT_HANDLER(__FILE__, __LINE__,                            \
kpeter@212:                          LEMON_FUNCTION_NAME,                           \
alpar@209:                          ::lemon::_assert_bits::cstringify(msg), #exp), 0)))
deba@108: 
deba@108: /// \ingroup exceptions
kpeter@66: ///
deba@118: /// \brief Macro for internal assertions
deba@118: ///
deba@118: /// Macro for internal assertions, it is used in the library to check
deba@118: /// the consistency of results of algorithms, several pre- and
deba@118: /// postconditions and invariants. The checking is disabled by
deba@118: /// default, but it can be turned on with the macro \c
deba@118: /// LEMON_ENABLE_DEBUG.
deba@118: /// \code
deba@118: /// #define LEMON_ENABLE_DEBUG
deba@118: /// \endcode
deba@118: /// or with compilation parameters:
deba@118: /// \code
deba@118: /// g++ -DLEMON_ENABLE_DEBUG
deba@118: /// make CXXFLAGS='-DLEMON_ENABLE_DEBUG'
deba@118: /// \endcode
deba@118: ///
deba@118: /// This macro works like the \c LEMON_ASSERT macro, therefore the
deba@118: /// current behaviour depends on the settings of \c LEMON_ASSERT
deba@118: /// macro.
deba@118: ///
alpar@209: /// \see LEMON_ASSERT
kpeter@212: #  define LEMON_DEBUG(exp, msg)                                         \
kpeter@212:   (static_cast<void> (!!(exp) ? 0 : (                                   \
deba@118:     LEMON_ASSERT_HANDLER(__FILE__, __LINE__,                            \
kpeter@212:                          LEMON_FUNCTION_NAME,                           \
alpar@209:                          ::lemon::_assert_bits::cstringify(msg), #exp), 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@118: #    define LEMON_DEBUG(exp, msg) (static_cast<void>(0))
kpeter@66: #  else
kpeter@212: #    define LEMON_ASSERT(exp, msg)                                      \
kpeter@212:        (static_cast<void> (!!(exp) ? 0 : (                              \
deba@118:         LEMON_ASSERT_HANDLER(__FILE__, __LINE__,                        \
kpeter@212:                              LEMON_FUNCTION_NAME,                       \
kpeter@212:                              ::lemon::_assert_bits::cstringify(msg),    \
alpar@209:                              #exp), 0)))
deba@118: #    if LEMON_ENABLE_DEBUG
kpeter@218: #      define LEMON_DEBUG(exp, msg)                                     \
kpeter@212:          (static_cast<void> (!!(exp) ? 0 : (                            \
kpeter@212:            LEMON_ASSERT_HANDLER(__FILE__, __LINE__,                     \
kpeter@212:                                 LEMON_FUNCTION_NAME,                    \
kpeter@212:                                 ::lemon::_assert_bits::cstringify(msg), \
alpar@209:                                 #exp), 0)))
deba@118: #    else
deba@118: #      define LEMON_DEBUG(exp, msg) (static_cast<void>(0))
deba@118: #    endif
kpeter@66: #  endif
deba@108: 
kpeter@66: #endif