lemon/assert.h
author Balazs Dezso <deba@inf.elte.hu>
Tue, 25 Mar 2008 16:36:44 +0100
changeset 108 889d0c289d19
parent 66 lemon/error.h@5f7a8570687d
child 112 d2ee5e7f00ef
permissions -rw-r--r--
Reworking assertions and moving to distinict file
     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     std::cerr << file << ":" << line << ": ";
   119     if (function)
   120       std::cerr << function << ": ";
   121     std::cerr << exception.what();
   122     if (assertion)
   123       std::cerr << " (assertion '" << assertion << "' failed)";
   124     std::cerr << std::endl;
   125     std::abort();
   126   }
   127 
   128   inline void assert_fail_abort(const char *file, int line,
   129 				const char *function, const char* message,
   130 				const char *assertion)
   131   {
   132     std::cerr << file << ":" << line << ": ";
   133     if (function)
   134       std::cerr << function << ": ";
   135     std::cerr << message;
   136     if (assertion)
   137       std::cerr << " (assertion '" << assertion << "' failed)";
   138     std::cerr << std::endl;
   139     std::abort();
   140   }
   141 
   142   inline void assert_fail_abort(const char *file, int line, 
   143 				const char *function, 
   144 				const std::string& message,
   145 				const char *assertion)
   146   {
   147     assert_fail_abort(file, line, function, message.c_str(), assertion);
   148   }
   149 
   150   inline void assert_fail_error(const char *file, int line, 
   151 				  const char *function,
   152 				  const std::exception& exception,
   153 				  const char *assertion)
   154   {
   155     throw AssertionFailedError(file, line, function, 
   156 			       exception.what(), assertion);
   157   }
   158 
   159   inline void assert_fail_error(const char *file, int line,
   160 				  const char *function, const char *message,
   161 				  const char *assertion)
   162   {
   163     throw AssertionFailedError(file, line, function, message, assertion);
   164   }
   165 
   166   inline void assert_fail_error(const char *file, int line,
   167 				  const char *function, 
   168 				  const std::string& message,
   169 				  const char *assertion)
   170   {
   171     assert_fail_error(file, line, function, message.c_str(), assertion);
   172   }
   173 
   174   template <typename Exception>
   175   inline void assert_fail_exception(const char *, int, const char *,
   176 				    const Exception& exception,
   177 				    const char *, const std::exception* = 
   178 				    static_cast<const Exception*>(0))
   179   {
   180     throw exception;
   181   }
   182 
   183   inline void assert_fail_exception(const char *file, int line,
   184 				    const char *function, const char *message,
   185 				    const char *assertion)
   186   {
   187     throw AssertionFailedError(file, line, function, message, assertion);
   188   }
   189 
   190   inline void assert_fail_exception(const char *file, int line, 
   191 				    const char *function, 
   192 				    const std::string& message,
   193 				    const char *assertion)
   194   {
   195     assert_fail_exception(file, line, function, message.c_str(), assertion);
   196   }
   197 
   198 /// @}
   199 
   200 }
   201 #endif // LEMON_ASSERT_H
   202 
   203 #undef LEMON_ASSERT
   204 #undef LEMON_FIXME
   205 
   206 #if (defined(LEMON_ASSERT_LOG) ? 1 : 0) +		\
   207   (defined(LEMON_ASSERT_ABORT) ? 1 : 0) +		\
   208   (defined(LEMON_ASSERT_ERROR) ? 1 : 0) +		\
   209   (defined(LEMON_ASSERT_EXCEPTION) ? 1 : 0) +		\
   210   (defined(LEMON_ASSERT_CUSTOM) ? 1 : 0) > 1
   211 #error "Lemon assertion system is not set properly"
   212 #endif
   213 
   214 #if ((defined(LEMON_ASSERT_LOG) ? 1 : 0) +		\
   215      (defined(LEMON_ASSERT_ABORT) ? 1 : 0) +		\
   216      (defined(LEMON_ASSERT_ERROR) ? 1 : 0) +		\
   217      (defined(LEMON_ASSERT_EXCEPTION) ? 1 : 0) +	\
   218      (defined(LEMON_ASSERT_CUSTOM) ? 1 : 0) == 1 ||	\
   219      defined(LEMON_ENABLE_ASSERT)) &&			\
   220   defined(LEMON_DISABLE_ASSERTS)
   221 #error "Lemon assertion system is not set properly"
   222 #endif
   223 
   224 
   225 #if defined LEMON_ASSERT_LOG
   226 #  undef LEMON_ASSERT_HANDLER
   227 #  define LEMON_ASSERT_HANDLER ::lemon::assert_fail_log
   228 #elif defined LEMON_ASSERT_ABORT
   229 #  undef LEMON_ASSERT_HANDLER
   230 #  define LEMON_ASSERT_HANDLER ::lemon::assert_fail_abort
   231 #elif defined LEMON_ASSERT_ERROR
   232 #  undef LEMON_ASSERT_HANDLER
   233 #  define LEMON_ASSERT_HANDLER ::lemon::assert_fail_error
   234 #elif defined LEMON_ASSERT_EXCEPTION
   235 #  undef LEMON_ASSERT_HANDLER
   236 #  define LEMON_ASSERT_HANDLER ::lemon::assert_fail_exception
   237 #elif defined LEMON_ASSERT_CUSTOM
   238 #  undef LEMON_ASSERT_HANDLER
   239 #  ifndef LEMON_CUSTOM_ASSERT_HANDLER
   240 #    error "LEMON_CUSTOM_ASSERT_HANDLER is not set"
   241 #  endif
   242 #  define LEMON_ASSERT_HANDLER LEMON_CUSTOM_ASSERT_HANDLER
   243 #elif defined LEMON_ENABLE_ASSERTS
   244 #  undef LEMON_ASSERT_HANDLER
   245 #  define LEMON_ASSERT_HANDLER ::lemon::assert_fail_abort
   246 #else
   247 #  undef LEMON_ASSERT_HANDLER
   248 #endif
   249 
   250 
   251 #ifndef LEMON_FUNCTION_NAME
   252 #  define LEMON_FUNCTION_NAME (__PRETTY_FUNCTION__)
   253 #endif
   254 
   255 #ifdef DOXYGEN
   256 
   257 /// \ingroup exceptions
   258 ///
   259 /// \brief Macro for assertions with customizable message
   260 ///
   261 /// Macro for assertions with customizable message.  
   262 /// \param exp An expression convertible to bool. If the expression is
   263 /// false, then an assertion is raised. The concrete behaviour depends
   264 /// on the settings of the assertion system.
   265 /// \param msg A \e const \e char*, a \e const std::string& or a \e
   266 /// const \e std::exception& parameter. The variable can be used to
   267 /// provide information about the circumstances of failed assertion.
   268 ///
   269 /// The assertions are disabled in the default behaviour. You can
   270 /// enable the assertions with the following code:
   271 /// \code
   272 /// #define LEMON_ENABLE_ASSERTS
   273 /// \endcode
   274 /// or with compilation parameters:
   275 /// \code
   276 /// g++ -DLEMON_ENABLE_ASSERTS
   277 /// make CXXFLAGS='-DLEMON_ENABLE_ASSERTS'
   278 /// \endcode
   279 /// 
   280 /// The %lemon assertion system has a wide range of customization
   281 /// properties. As default behaviour the failed assertion prints a
   282 /// short log message to the standard ouput and aborts the execution.
   283 ///
   284 /// The following modes can be used in the assertion system: 
   285 ///
   286 /// - \e LEMON_ASSERT_LOG The failed assert print a short convenient
   287 ///   error message to the standard error and continues the
   288 ///   execution.
   289 /// - \e LEMON_ASSERT_ABORT This mode is similar to the \e
   290 ///   LEMON_ASSERT_LOG, but it aborts the program. It is the default
   291 ///   operation mode when the asserts are enabled with \e
   292 ///   LEMON_ENABLE_ASSERTS.
   293 /// - \e LEMON_ASSERT_ERROR The assert throws an \ref
   294 ///   lemon::AssertionFailedError "AssertionFailedError". If the \c
   295 ///   msg parameter is an exception, then the result of the \ref
   296 ///   lemon::Exception::what() "what()" member function is passed as
   297 ///   error message.
   298 /// - \e LEMON_ASSERT_EXCEPTION If the specified \c msg is an
   299 ///   exception then it raised directly (solving that the exception
   300 ///   can not be thrown polymorphically), otherwise an \ref
   301 ///   lemon::AssertionFailedError "AssertionFailedError" is thrown with
   302 ///   the given parameter.
   303 /// - \e LEMON_ASSERT_CUSTOM The user can define an own assertion
   304 ///   handler functions. Three overloaded functions should be defined
   305 ///   with the following parameter lists:
   306 ///   \code
   307 ///     void custom_assert_handler(const char* file, int line, 
   308 ///                                const char* function, const char* message, const char* expression);
   309 ///     void custom_assert_handler(const char* file, int line, 
   310 ///                                const char* function, const std::string& message, const char* expression);
   311 ///     void custom_assert_handler(const char* file, int line, 
   312 ///                                const char* function, const std::exception& message, const char* expression);
   313 ///   \endcode
   314 ///   The name of the functions should be defined as the \c
   315 ///   LEMON_CUSTOM_ASSERT_HANDLER macro name. 
   316 ///   \code
   317 ///     #define LEMON_CUSTOM_ASSERT_HANDLER custom_assert_handler
   318 ///   \endcode
   319 ///   Whenever an assertion is occured, one of the custom assertion
   320 ///   handler is called with appropiate parameters.
   321 ///
   322 /// The assertion mode can be changed within one compilation unit, if
   323 /// the macros are redefined with other settings and the
   324 /// lemon/assert.h file is reincluded then the behaviour is changed
   325 /// appropiately to the new settings.
   326 #  define LEMON_ASSERT(exp, msg)					\
   327   (static_cast<void> (!!(exp) ? 0 : (					\
   328     LEMON_ASSERT_HANDLER(__FILE__, __LINE__,				\
   329 			 LEMON_FUNCTION_NAME,				\
   330 			 msg, #exp), 0)))
   331 
   332 
   333 /// \ingroup exceptions
   334 ///
   335 /// \brief Macro for mark not yet implemented features.
   336 ///
   337 /// Macro for mark not yet implemented features and outstanding bugs.
   338 /// It is close to be the shortcut of the following code:
   339 /// \code
   340 ///   LEMON_ASSERT(false, msg);
   341 /// \endcode
   342 #  define LEMON_FIXME(msg)						\
   343        (LEMON_ASSERT_HANDLER(__FILE__, __LINE__, LEMON_FUNCTION_NAME,	\
   344 			     "FIXME: " msg, static_cast<const char*>(0)))
   345 
   346 #else
   347 
   348 #  ifndef LEMON_ASSERT_HANDLER
   349 #    define LEMON_ASSERT(exp, msg)  (static_cast<void> (0))
   350 #    define LEMON_FIXME(msg) (static_cast<void>(0))
   351 #  else
   352 #    define LEMON_ASSERT(exp, msg)                 \
   353        (static_cast<void> (!!(exp) ? 0 : (         \
   354          LEMON_ASSERT_HANDLER(__FILE__, __LINE__,  \
   355                               LEMON_FUNCTION_NAME, \
   356                               msg, #exp), 0)))
   357 #    define LEMON_FIXME(msg) \
   358        (LEMON_ASSERT_HANDLER(__FILE__, __LINE__, LEMON_FUNCTION_NAME,	\
   359 			     "FIXME: " msg,  static_cast<const char*>(0)))
   360 #  endif
   361 
   362 #endif
   363 
   364