lemon/assert.h
author Peter Kovacs <kpeter@inf.elte.hu>
Thu, 27 Mar 2008 13:26:16 +0100
changeset 112 d2ee5e7f00ef
parent 108 889d0c289d19
child 118 407c08a0eae9
permissions -rw-r--r--
Improvements in assert.h
     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