lemon/assert.h
changeset 108 889d0c289d19
parent 66 5f7a8570687d
child 112 d2ee5e7f00ef
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/lemon/assert.h	Tue Mar 25 16:36:44 2008 +0100
     1.3 @@ -0,0 +1,364 @@
     1.4 +/* -*- C++ -*-
     1.5 + *
     1.6 + * This file is a part of LEMON, a generic C++ optimization library
     1.7 + *
     1.8 + * Copyright (C) 2003-2008
     1.9 + * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
    1.10 + * (Egervary Research Group on Combinatorial Optimization, EGRES).
    1.11 + *
    1.12 + * Permission to use, modify and distribute this software is granted
    1.13 + * provided that this copyright notice appears in all copies. For
    1.14 + * precise terms see the accompanying LICENSE file.
    1.15 + *
    1.16 + * This software is provided "AS IS" with no warranty of any kind,
    1.17 + * express or implied, and with no claim as to its suitability for any
    1.18 + * purpose.
    1.19 + *
    1.20 + */
    1.21 +
    1.22 +#ifndef LEMON_ASSERT_H
    1.23 +#define LEMON_ASSERT_H
    1.24 +
    1.25 +/// \ingroup exceptions
    1.26 +/// \file
    1.27 +/// \brief Extended assertion handling
    1.28 +
    1.29 +#include <lemon/error.h>
    1.30 +
    1.31 +namespace lemon {
    1.32 +
    1.33 +  /// @{
    1.34 +
    1.35 +  ///\e
    1.36 +  class AssertionFailedError : public LogicError {
    1.37 +  protected:
    1.38 +    const char *_assertion;
    1.39 +    const char *_file;
    1.40 +    int _line;
    1.41 +    const char *_function;
    1.42 +    const char *_message;
    1.43 +
    1.44 +    mutable ExceptionMember<std::string> _message_holder;
    1.45 +  public:
    1.46 +    ///\e
    1.47 +    AssertionFailedError(const char *file, int line, const char *function,
    1.48 +			 const char *msg, const char *assertion = 0) :
    1.49 +      _assertion(assertion), _file(file), _line(line), 
    1.50 +      _function(function), _message(msg) {}
    1.51 +
    1.52 +    ///\e
    1.53 +    const char* assertion() const { return _assertion; }
    1.54 +    ///\e
    1.55 +    const char* message() const { return _message; }
    1.56 +    ///\e
    1.57 +    const char* file() const { return _file; }
    1.58 +    ///\e
    1.59 +    const char* function() const { return _function; }
    1.60 +    ///\e
    1.61 +    int line() const { return _line; }
    1.62 +
    1.63 +
    1.64 +    virtual const char* what() const throw() {
    1.65 +      try {
    1.66 +	std::ostringstream ostr;
    1.67 +	ostr << _file << ":" << _line << ": ";
    1.68 +	if (_function)
    1.69 +	  ostr << _function << ": ";
    1.70 +	ostr << _message;
    1.71 +	if (_assertion)
    1.72 +	   ostr << " (assertion '" << _assertion << "' failed)";
    1.73 +	_message_holder.set(ostr.str());
    1.74 +	return ostr.str().c_str();
    1.75 +      }
    1.76 +      catch(...) {}
    1.77 +      if( _message_holder.valid() ) return _message_holder.get().c_str();
    1.78 +      return "lemon::AssertionFailedError";
    1.79 +    }
    1.80 +    virtual ~AssertionFailedError() throw() {}
    1.81 +  };
    1.82 +
    1.83 +
    1.84 +  inline void assert_fail_log(const char *file, int line,
    1.85 +			      const char *function,
    1.86 +			      const std::exception& exception, 
    1.87 +			      const char *assertion)
    1.88 +  {
    1.89 +    std::cerr << file << ":" << line << ": ";
    1.90 +    if (function)
    1.91 +      std::cerr << function << ": ";
    1.92 +    std::cerr << exception.what();
    1.93 +    if (assertion)
    1.94 +      std::cerr << " (assertion '" << assertion << "' failed)";
    1.95 +    std::cerr << std::endl;
    1.96 +  }
    1.97 +
    1.98 +  inline void assert_fail_log(const char *file, int line, const char *function,
    1.99 +			      const char *message, const char *assertion)
   1.100 +  {
   1.101 +    std::cerr << file << ":" << line << ": ";
   1.102 +    if (function)
   1.103 +      std::cerr << function << ": ";
   1.104 +    std::cerr << message;
   1.105 +    if (assertion)
   1.106 +      std::cerr << " (assertion '" << assertion << "' failed)";
   1.107 +    std::cerr << std::endl;
   1.108 +  }
   1.109 +
   1.110 +  inline void assert_fail_log(const char *file, int line, const char *function, 
   1.111 +			      const std::string& message, const char *assertion)
   1.112 +  {
   1.113 +    assert_fail_log(file, line, function, message.c_str(), assertion);
   1.114 +  }
   1.115 +
   1.116 +  inline void assert_fail_abort(const char *file, int line, 
   1.117 +				const char *function,
   1.118 +				const std::exception& exception,
   1.119 +				const char *assertion)
   1.120 +  {
   1.121 +    std::cerr << file << ":" << line << ": ";
   1.122 +    if (function)
   1.123 +      std::cerr << function << ": ";
   1.124 +    std::cerr << exception.what();
   1.125 +    if (assertion)
   1.126 +      std::cerr << " (assertion '" << assertion << "' failed)";
   1.127 +    std::cerr << std::endl;
   1.128 +    std::abort();
   1.129 +  }
   1.130 +
   1.131 +  inline void assert_fail_abort(const char *file, int line,
   1.132 +				const char *function, const char* message,
   1.133 +				const char *assertion)
   1.134 +  {
   1.135 +    std::cerr << file << ":" << line << ": ";
   1.136 +    if (function)
   1.137 +      std::cerr << function << ": ";
   1.138 +    std::cerr << message;
   1.139 +    if (assertion)
   1.140 +      std::cerr << " (assertion '" << assertion << "' failed)";
   1.141 +    std::cerr << std::endl;
   1.142 +    std::abort();
   1.143 +  }
   1.144 +
   1.145 +  inline void assert_fail_abort(const char *file, int line, 
   1.146 +				const char *function, 
   1.147 +				const std::string& message,
   1.148 +				const char *assertion)
   1.149 +  {
   1.150 +    assert_fail_abort(file, line, function, message.c_str(), assertion);
   1.151 +  }
   1.152 +
   1.153 +  inline void assert_fail_error(const char *file, int line, 
   1.154 +				  const char *function,
   1.155 +				  const std::exception& exception,
   1.156 +				  const char *assertion)
   1.157 +  {
   1.158 +    throw AssertionFailedError(file, line, function, 
   1.159 +			       exception.what(), assertion);
   1.160 +  }
   1.161 +
   1.162 +  inline void assert_fail_error(const char *file, int line,
   1.163 +				  const char *function, const char *message,
   1.164 +				  const char *assertion)
   1.165 +  {
   1.166 +    throw AssertionFailedError(file, line, function, message, assertion);
   1.167 +  }
   1.168 +
   1.169 +  inline void assert_fail_error(const char *file, int line,
   1.170 +				  const char *function, 
   1.171 +				  const std::string& message,
   1.172 +				  const char *assertion)
   1.173 +  {
   1.174 +    assert_fail_error(file, line, function, message.c_str(), assertion);
   1.175 +  }
   1.176 +
   1.177 +  template <typename Exception>
   1.178 +  inline void assert_fail_exception(const char *, int, const char *,
   1.179 +				    const Exception& exception,
   1.180 +				    const char *, const std::exception* = 
   1.181 +				    static_cast<const Exception*>(0))
   1.182 +  {
   1.183 +    throw exception;
   1.184 +  }
   1.185 +
   1.186 +  inline void assert_fail_exception(const char *file, int line,
   1.187 +				    const char *function, const char *message,
   1.188 +				    const char *assertion)
   1.189 +  {
   1.190 +    throw AssertionFailedError(file, line, function, message, assertion);
   1.191 +  }
   1.192 +
   1.193 +  inline void assert_fail_exception(const char *file, int line, 
   1.194 +				    const char *function, 
   1.195 +				    const std::string& message,
   1.196 +				    const char *assertion)
   1.197 +  {
   1.198 +    assert_fail_exception(file, line, function, message.c_str(), assertion);
   1.199 +  }
   1.200 +
   1.201 +/// @}
   1.202 +
   1.203 +}
   1.204 +#endif // LEMON_ASSERT_H
   1.205 +
   1.206 +#undef LEMON_ASSERT
   1.207 +#undef LEMON_FIXME
   1.208 +
   1.209 +#if (defined(LEMON_ASSERT_LOG) ? 1 : 0) +		\
   1.210 +  (defined(LEMON_ASSERT_ABORT) ? 1 : 0) +		\
   1.211 +  (defined(LEMON_ASSERT_ERROR) ? 1 : 0) +		\
   1.212 +  (defined(LEMON_ASSERT_EXCEPTION) ? 1 : 0) +		\
   1.213 +  (defined(LEMON_ASSERT_CUSTOM) ? 1 : 0) > 1
   1.214 +#error "Lemon assertion system is not set properly"
   1.215 +#endif
   1.216 +
   1.217 +#if ((defined(LEMON_ASSERT_LOG) ? 1 : 0) +		\
   1.218 +     (defined(LEMON_ASSERT_ABORT) ? 1 : 0) +		\
   1.219 +     (defined(LEMON_ASSERT_ERROR) ? 1 : 0) +		\
   1.220 +     (defined(LEMON_ASSERT_EXCEPTION) ? 1 : 0) +	\
   1.221 +     (defined(LEMON_ASSERT_CUSTOM) ? 1 : 0) == 1 ||	\
   1.222 +     defined(LEMON_ENABLE_ASSERT)) &&			\
   1.223 +  defined(LEMON_DISABLE_ASSERTS)
   1.224 +#error "Lemon assertion system is not set properly"
   1.225 +#endif
   1.226 +
   1.227 +
   1.228 +#if defined LEMON_ASSERT_LOG
   1.229 +#  undef LEMON_ASSERT_HANDLER
   1.230 +#  define LEMON_ASSERT_HANDLER ::lemon::assert_fail_log
   1.231 +#elif defined LEMON_ASSERT_ABORT
   1.232 +#  undef LEMON_ASSERT_HANDLER
   1.233 +#  define LEMON_ASSERT_HANDLER ::lemon::assert_fail_abort
   1.234 +#elif defined LEMON_ASSERT_ERROR
   1.235 +#  undef LEMON_ASSERT_HANDLER
   1.236 +#  define LEMON_ASSERT_HANDLER ::lemon::assert_fail_error
   1.237 +#elif defined LEMON_ASSERT_EXCEPTION
   1.238 +#  undef LEMON_ASSERT_HANDLER
   1.239 +#  define LEMON_ASSERT_HANDLER ::lemon::assert_fail_exception
   1.240 +#elif defined LEMON_ASSERT_CUSTOM
   1.241 +#  undef LEMON_ASSERT_HANDLER
   1.242 +#  ifndef LEMON_CUSTOM_ASSERT_HANDLER
   1.243 +#    error "LEMON_CUSTOM_ASSERT_HANDLER is not set"
   1.244 +#  endif
   1.245 +#  define LEMON_ASSERT_HANDLER LEMON_CUSTOM_ASSERT_HANDLER
   1.246 +#elif defined LEMON_ENABLE_ASSERTS
   1.247 +#  undef LEMON_ASSERT_HANDLER
   1.248 +#  define LEMON_ASSERT_HANDLER ::lemon::assert_fail_abort
   1.249 +#else
   1.250 +#  undef LEMON_ASSERT_HANDLER
   1.251 +#endif
   1.252 +
   1.253 +
   1.254 +#ifndef LEMON_FUNCTION_NAME
   1.255 +#  define LEMON_FUNCTION_NAME (__PRETTY_FUNCTION__)
   1.256 +#endif
   1.257 +
   1.258 +#ifdef DOXYGEN
   1.259 +
   1.260 +/// \ingroup exceptions
   1.261 +///
   1.262 +/// \brief Macro for assertions with customizable message
   1.263 +///
   1.264 +/// Macro for assertions with customizable message.  
   1.265 +/// \param exp An expression convertible to bool. If the expression is
   1.266 +/// false, then an assertion is raised. The concrete behaviour depends
   1.267 +/// on the settings of the assertion system.
   1.268 +/// \param msg A \e const \e char*, a \e const std::string& or a \e
   1.269 +/// const \e std::exception& parameter. The variable can be used to
   1.270 +/// provide information about the circumstances of failed assertion.
   1.271 +///
   1.272 +/// The assertions are disabled in the default behaviour. You can
   1.273 +/// enable the assertions with the following code:
   1.274 +/// \code
   1.275 +/// #define LEMON_ENABLE_ASSERTS
   1.276 +/// \endcode
   1.277 +/// or with compilation parameters:
   1.278 +/// \code
   1.279 +/// g++ -DLEMON_ENABLE_ASSERTS
   1.280 +/// make CXXFLAGS='-DLEMON_ENABLE_ASSERTS'
   1.281 +/// \endcode
   1.282 +/// 
   1.283 +/// The %lemon assertion system has a wide range of customization
   1.284 +/// properties. As default behaviour the failed assertion prints a
   1.285 +/// short log message to the standard ouput and aborts the execution.
   1.286 +///
   1.287 +/// The following modes can be used in the assertion system: 
   1.288 +///
   1.289 +/// - \e LEMON_ASSERT_LOG The failed assert print a short convenient
   1.290 +///   error message to the standard error and continues the
   1.291 +///   execution.
   1.292 +/// - \e LEMON_ASSERT_ABORT This mode is similar to the \e
   1.293 +///   LEMON_ASSERT_LOG, but it aborts the program. It is the default
   1.294 +///   operation mode when the asserts are enabled with \e
   1.295 +///   LEMON_ENABLE_ASSERTS.
   1.296 +/// - \e LEMON_ASSERT_ERROR The assert throws an \ref
   1.297 +///   lemon::AssertionFailedError "AssertionFailedError". If the \c
   1.298 +///   msg parameter is an exception, then the result of the \ref
   1.299 +///   lemon::Exception::what() "what()" member function is passed as
   1.300 +///   error message.
   1.301 +/// - \e LEMON_ASSERT_EXCEPTION If the specified \c msg is an
   1.302 +///   exception then it raised directly (solving that the exception
   1.303 +///   can not be thrown polymorphically), otherwise an \ref
   1.304 +///   lemon::AssertionFailedError "AssertionFailedError" is thrown with
   1.305 +///   the given parameter.
   1.306 +/// - \e LEMON_ASSERT_CUSTOM The user can define an own assertion
   1.307 +///   handler functions. Three overloaded functions should be defined
   1.308 +///   with the following parameter lists:
   1.309 +///   \code
   1.310 +///     void custom_assert_handler(const char* file, int line, 
   1.311 +///                                const char* function, const char* message, const char* expression);
   1.312 +///     void custom_assert_handler(const char* file, int line, 
   1.313 +///                                const char* function, const std::string& message, const char* expression);
   1.314 +///     void custom_assert_handler(const char* file, int line, 
   1.315 +///                                const char* function, const std::exception& message, const char* expression);
   1.316 +///   \endcode
   1.317 +///   The name of the functions should be defined as the \c
   1.318 +///   LEMON_CUSTOM_ASSERT_HANDLER macro name. 
   1.319 +///   \code
   1.320 +///     #define LEMON_CUSTOM_ASSERT_HANDLER custom_assert_handler
   1.321 +///   \endcode
   1.322 +///   Whenever an assertion is occured, one of the custom assertion
   1.323 +///   handler is called with appropiate parameters.
   1.324 +///
   1.325 +/// The assertion mode can be changed within one compilation unit, if
   1.326 +/// the macros are redefined with other settings and the
   1.327 +/// lemon/assert.h file is reincluded then the behaviour is changed
   1.328 +/// appropiately to the new settings.
   1.329 +#  define LEMON_ASSERT(exp, msg)					\
   1.330 +  (static_cast<void> (!!(exp) ? 0 : (					\
   1.331 +    LEMON_ASSERT_HANDLER(__FILE__, __LINE__,				\
   1.332 +			 LEMON_FUNCTION_NAME,				\
   1.333 +			 msg, #exp), 0)))
   1.334 +
   1.335 +
   1.336 +/// \ingroup exceptions
   1.337 +///
   1.338 +/// \brief Macro for mark not yet implemented features.
   1.339 +///
   1.340 +/// Macro for mark not yet implemented features and outstanding bugs.
   1.341 +/// It is close to be the shortcut of the following code:
   1.342 +/// \code
   1.343 +///   LEMON_ASSERT(false, msg);
   1.344 +/// \endcode
   1.345 +#  define LEMON_FIXME(msg)						\
   1.346 +       (LEMON_ASSERT_HANDLER(__FILE__, __LINE__, LEMON_FUNCTION_NAME,	\
   1.347 +			     "FIXME: " msg, static_cast<const char*>(0)))
   1.348 +
   1.349 +#else
   1.350 +
   1.351 +#  ifndef LEMON_ASSERT_HANDLER
   1.352 +#    define LEMON_ASSERT(exp, msg)  (static_cast<void> (0))
   1.353 +#    define LEMON_FIXME(msg) (static_cast<void>(0))
   1.354 +#  else
   1.355 +#    define LEMON_ASSERT(exp, msg)                 \
   1.356 +       (static_cast<void> (!!(exp) ? 0 : (         \
   1.357 +         LEMON_ASSERT_HANDLER(__FILE__, __LINE__,  \
   1.358 +                              LEMON_FUNCTION_NAME, \
   1.359 +                              msg, #exp), 0)))
   1.360 +#    define LEMON_FIXME(msg) \
   1.361 +       (LEMON_ASSERT_HANDLER(__FILE__, __LINE__, LEMON_FUNCTION_NAME,	\
   1.362 +			     "FIXME: " msg,  static_cast<const char*>(0)))
   1.363 +#  endif
   1.364 +
   1.365 +#endif
   1.366 +
   1.367 +