lemon/assert.h
author Alpar Juttner <alpar@cs.elte.hu>
Sat, 12 Apr 2008 19:41:48 +0100
changeset 121 91c0fed3181e
parent 66 5f7a8570687d
child 112 d2ee5e7f00ef
permissions -rw-r--r--
Change SubNoCounter to NoSubCounter
kpeter@66
     1
/* -*- C++ -*-
kpeter@66
     2
 *
kpeter@66
     3
 * This file is a part of LEMON, a generic C++ optimization library
kpeter@66
     4
 *
kpeter@66
     5
 * Copyright (C) 2003-2008
kpeter@66
     6
 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
kpeter@66
     7
 * (Egervary Research Group on Combinatorial Optimization, EGRES).
kpeter@66
     8
 *
kpeter@66
     9
 * Permission to use, modify and distribute this software is granted
kpeter@66
    10
 * provided that this copyright notice appears in all copies. For
kpeter@66
    11
 * precise terms see the accompanying LICENSE file.
kpeter@66
    12
 *
kpeter@66
    13
 * This software is provided "AS IS" with no warranty of any kind,
kpeter@66
    14
 * express or implied, and with no claim as to its suitability for any
kpeter@66
    15
 * purpose.
kpeter@66
    16
 *
kpeter@66
    17
 */
kpeter@66
    18
deba@108
    19
#ifndef LEMON_ASSERT_H
deba@108
    20
#define LEMON_ASSERT_H
kpeter@66
    21
kpeter@66
    22
/// \ingroup exceptions
kpeter@66
    23
/// \file
deba@108
    24
/// \brief Extended assertion handling
kpeter@66
    25
deba@108
    26
#include <lemon/error.h>
kpeter@66
    27
kpeter@66
    28
namespace lemon {
kpeter@66
    29
kpeter@66
    30
  /// @{
kpeter@66
    31
kpeter@66
    32
  ///\e
kpeter@66
    33
  class AssertionFailedError : public LogicError {
kpeter@66
    34
  protected:
deba@108
    35
    const char *_assertion;
deba@108
    36
    const char *_file;
deba@108
    37
    int _line;
deba@108
    38
    const char *_function;
deba@108
    39
    const char *_message;
kpeter@66
    40
kpeter@66
    41
    mutable ExceptionMember<std::string> _message_holder;
kpeter@66
    42
  public:
kpeter@66
    43
    ///\e
deba@108
    44
    AssertionFailedError(const char *file, int line, const char *function,
deba@108
    45
			 const char *msg, const char *assertion = 0) :
deba@108
    46
      _assertion(assertion), _file(file), _line(line), 
deba@108
    47
      _function(function), _message(msg) {}
kpeter@66
    48
kpeter@66
    49
    ///\e
deba@108
    50
    const char* assertion() const { return _assertion; }
kpeter@66
    51
    ///\e
deba@108
    52
    const char* message() const { return _message; }
kpeter@66
    53
    ///\e
deba@108
    54
    const char* file() const { return _file; }
kpeter@66
    55
    ///\e
deba@108
    56
    const char* function() const { return _function; }
kpeter@66
    57
    ///\e
deba@108
    58
    int line() const { return _line; }
kpeter@66
    59
kpeter@66
    60
kpeter@66
    61
    virtual const char* what() const throw() {
kpeter@66
    62
      try {
kpeter@66
    63
	std::ostringstream ostr;
deba@108
    64
	ostr << _file << ":" << _line << ": ";
deba@108
    65
	if (_function)
deba@108
    66
	  ostr << _function << ": ";
deba@108
    67
	ostr << _message;
deba@108
    68
	if (_assertion)
deba@108
    69
	   ostr << " (assertion '" << _assertion << "' failed)";
kpeter@66
    70
	_message_holder.set(ostr.str());
kpeter@66
    71
	return ostr.str().c_str();
kpeter@66
    72
      }
kpeter@66
    73
      catch(...) {}
kpeter@66
    74
      if( _message_holder.valid() ) return _message_holder.get().c_str();
kpeter@66
    75
      return "lemon::AssertionFailedError";
kpeter@66
    76
    }
deba@108
    77
    virtual ~AssertionFailedError() throw() {}
kpeter@66
    78
  };
kpeter@66
    79
kpeter@66
    80
deba@108
    81
  inline void assert_fail_log(const char *file, int line,
deba@108
    82
			      const char *function,
deba@108
    83
			      const std::exception& exception, 
deba@108
    84
			      const char *assertion)
kpeter@66
    85
  {
deba@108
    86
    std::cerr << file << ":" << line << ": ";
deba@108
    87
    if (function)
deba@108
    88
      std::cerr << function << ": ";
deba@108
    89
    std::cerr << exception.what();
kpeter@66
    90
    if (assertion)
deba@108
    91
      std::cerr << " (assertion '" << assertion << "' failed)";
deba@108
    92
    std::cerr << std::endl;
kpeter@66
    93
  }
kpeter@66
    94
deba@108
    95
  inline void assert_fail_log(const char *file, int line, const char *function,
deba@108
    96
			      const char *message, const char *assertion)
kpeter@66
    97
  {
deba@108
    98
    std::cerr << file << ":" << line << ": ";
deba@108
    99
    if (function)
deba@108
   100
      std::cerr << function << ": ";
deba@108
   101
    std::cerr << message;
kpeter@66
   102
    if (assertion)
deba@108
   103
      std::cerr << " (assertion '" << assertion << "' failed)";
deba@108
   104
    std::cerr << std::endl;
kpeter@66
   105
  }
kpeter@66
   106
deba@108
   107
  inline void assert_fail_log(const char *file, int line, const char *function, 
deba@108
   108
			      const std::string& message, const char *assertion)
kpeter@66
   109
  {
deba@108
   110
    assert_fail_log(file, line, function, message.c_str(), assertion);
deba@108
   111
  }
deba@108
   112
deba@108
   113
  inline void assert_fail_abort(const char *file, int line, 
deba@108
   114
				const char *function,
deba@108
   115
				const std::exception& exception,
deba@108
   116
				const char *assertion)
deba@108
   117
  {
deba@108
   118
    std::cerr << file << ":" << line << ": ";
deba@108
   119
    if (function)
deba@108
   120
      std::cerr << function << ": ";
deba@108
   121
    std::cerr << exception.what();
deba@108
   122
    if (assertion)
deba@108
   123
      std::cerr << " (assertion '" << assertion << "' failed)";
deba@108
   124
    std::cerr << std::endl;
deba@108
   125
    std::abort();
deba@108
   126
  }
deba@108
   127
deba@108
   128
  inline void assert_fail_abort(const char *file, int line,
deba@108
   129
				const char *function, const char* message,
deba@108
   130
				const char *assertion)
deba@108
   131
  {
deba@108
   132
    std::cerr << file << ":" << line << ": ";
deba@108
   133
    if (function)
deba@108
   134
      std::cerr << function << ": ";
deba@108
   135
    std::cerr << message;
deba@108
   136
    if (assertion)
deba@108
   137
      std::cerr << " (assertion '" << assertion << "' failed)";
deba@108
   138
    std::cerr << std::endl;
deba@108
   139
    std::abort();
deba@108
   140
  }
deba@108
   141
deba@108
   142
  inline void assert_fail_abort(const char *file, int line, 
deba@108
   143
				const char *function, 
deba@108
   144
				const std::string& message,
deba@108
   145
				const char *assertion)
deba@108
   146
  {
deba@108
   147
    assert_fail_abort(file, line, function, message.c_str(), assertion);
deba@108
   148
  }
deba@108
   149
deba@108
   150
  inline void assert_fail_error(const char *file, int line, 
deba@108
   151
				  const char *function,
deba@108
   152
				  const std::exception& exception,
deba@108
   153
				  const char *assertion)
deba@108
   154
  {
deba@108
   155
    throw AssertionFailedError(file, line, function, 
deba@108
   156
			       exception.what(), assertion);
deba@108
   157
  }
deba@108
   158
deba@108
   159
  inline void assert_fail_error(const char *file, int line,
deba@108
   160
				  const char *function, const char *message,
deba@108
   161
				  const char *assertion)
deba@108
   162
  {
deba@108
   163
    throw AssertionFailedError(file, line, function, message, assertion);
deba@108
   164
  }
deba@108
   165
deba@108
   166
  inline void assert_fail_error(const char *file, int line,
deba@108
   167
				  const char *function, 
deba@108
   168
				  const std::string& message,
deba@108
   169
				  const char *assertion)
deba@108
   170
  {
deba@108
   171
    assert_fail_error(file, line, function, message.c_str(), assertion);
kpeter@66
   172
  }
kpeter@66
   173
kpeter@66
   174
  template <typename Exception>
deba@108
   175
  inline void assert_fail_exception(const char *, int, const char *,
deba@108
   176
				    const Exception& exception,
deba@108
   177
				    const char *, const std::exception* = 
deba@108
   178
				    static_cast<const Exception*>(0))
kpeter@66
   179
  {
kpeter@66
   180
    throw exception;
kpeter@66
   181
  }
kpeter@66
   182
deba@108
   183
  inline void assert_fail_exception(const char *file, int line,
deba@108
   184
				    const char *function, const char *message,
deba@108
   185
				    const char *assertion)
kpeter@66
   186
  {
deba@108
   187
    throw AssertionFailedError(file, line, function, message, assertion);
kpeter@66
   188
  }
kpeter@66
   189
deba@108
   190
  inline void assert_fail_exception(const char *file, int line, 
deba@108
   191
				    const char *function, 
deba@108
   192
				    const std::string& message,
deba@108
   193
				    const char *assertion)
kpeter@66
   194
  {
deba@108
   195
    assert_fail_exception(file, line, function, message.c_str(), assertion);
kpeter@66
   196
  }
kpeter@66
   197
kpeter@66
   198
/// @}
kpeter@66
   199
kpeter@66
   200
}
deba@108
   201
#endif // LEMON_ASSERT_H
kpeter@66
   202
kpeter@66
   203
#undef LEMON_ASSERT
kpeter@66
   204
#undef LEMON_FIXME
kpeter@66
   205
deba@108
   206
#if (defined(LEMON_ASSERT_LOG) ? 1 : 0) +		\
deba@108
   207
  (defined(LEMON_ASSERT_ABORT) ? 1 : 0) +		\
deba@108
   208
  (defined(LEMON_ASSERT_ERROR) ? 1 : 0) +		\
deba@108
   209
  (defined(LEMON_ASSERT_EXCEPTION) ? 1 : 0) +		\
deba@108
   210
  (defined(LEMON_ASSERT_CUSTOM) ? 1 : 0) > 1
deba@108
   211
#error "Lemon assertion system is not set properly"
kpeter@66
   212
#endif
kpeter@66
   213
deba@108
   214
#if ((defined(LEMON_ASSERT_LOG) ? 1 : 0) +		\
deba@108
   215
     (defined(LEMON_ASSERT_ABORT) ? 1 : 0) +		\
deba@108
   216
     (defined(LEMON_ASSERT_ERROR) ? 1 : 0) +		\
deba@108
   217
     (defined(LEMON_ASSERT_EXCEPTION) ? 1 : 0) +	\
deba@108
   218
     (defined(LEMON_ASSERT_CUSTOM) ? 1 : 0) == 1 ||	\
deba@108
   219
     defined(LEMON_ENABLE_ASSERT)) &&			\
deba@108
   220
  defined(LEMON_DISABLE_ASSERTS)
deba@108
   221
#error "Lemon assertion system is not set properly"
kpeter@66
   222
#endif
kpeter@66
   223
deba@108
   224
deba@108
   225
#if defined LEMON_ASSERT_LOG
deba@108
   226
#  undef LEMON_ASSERT_HANDLER
deba@108
   227
#  define LEMON_ASSERT_HANDLER ::lemon::assert_fail_log
deba@108
   228
#elif defined LEMON_ASSERT_ABORT
deba@108
   229
#  undef LEMON_ASSERT_HANDLER
deba@108
   230
#  define LEMON_ASSERT_HANDLER ::lemon::assert_fail_abort
deba@108
   231
#elif defined LEMON_ASSERT_ERROR
deba@108
   232
#  undef LEMON_ASSERT_HANDLER
deba@108
   233
#  define LEMON_ASSERT_HANDLER ::lemon::assert_fail_error
deba@108
   234
#elif defined LEMON_ASSERT_EXCEPTION
deba@108
   235
#  undef LEMON_ASSERT_HANDLER
deba@108
   236
#  define LEMON_ASSERT_HANDLER ::lemon::assert_fail_exception
deba@108
   237
#elif defined LEMON_ASSERT_CUSTOM
deba@108
   238
#  undef LEMON_ASSERT_HANDLER
deba@108
   239
#  ifndef LEMON_CUSTOM_ASSERT_HANDLER
deba@108
   240
#    error "LEMON_CUSTOM_ASSERT_HANDLER is not set"
kpeter@66
   241
#  endif
deba@108
   242
#  define LEMON_ASSERT_HANDLER LEMON_CUSTOM_ASSERT_HANDLER
deba@108
   243
#elif defined LEMON_ENABLE_ASSERTS
deba@108
   244
#  undef LEMON_ASSERT_HANDLER
deba@108
   245
#  define LEMON_ASSERT_HANDLER ::lemon::assert_fail_abort
deba@108
   246
#else
deba@108
   247
#  undef LEMON_ASSERT_HANDLER
deba@108
   248
#endif
deba@108
   249
deba@108
   250
deba@108
   251
#ifndef LEMON_FUNCTION_NAME
deba@108
   252
#  define LEMON_FUNCTION_NAME (__PRETTY_FUNCTION__)
kpeter@66
   253
#endif
kpeter@66
   254
kpeter@66
   255
#ifdef DOXYGEN
kpeter@66
   256
deba@108
   257
/// \ingroup exceptions
deba@108
   258
///
kpeter@66
   259
/// \brief Macro for assertions with customizable message
kpeter@66
   260
///
deba@108
   261
/// Macro for assertions with customizable message.  
deba@108
   262
/// \param exp An expression convertible to bool. If the expression is
deba@108
   263
/// false, then an assertion is raised. The concrete behaviour depends
deba@108
   264
/// on the settings of the assertion system.
deba@108
   265
/// \param msg A \e const \e char*, a \e const std::string& or a \e
deba@108
   266
/// const \e std::exception& parameter. The variable can be used to
deba@108
   267
/// provide information about the circumstances of failed assertion.
kpeter@66
   268
///
kpeter@66
   269
/// The assertions are disabled in the default behaviour. You can
deba@108
   270
/// enable the assertions with the following code:
kpeter@66
   271
/// \code
kpeter@66
   272
/// #define LEMON_ENABLE_ASSERTS
kpeter@66
   273
/// \endcode
deba@108
   274
/// or with compilation parameters:
deba@108
   275
/// \code
deba@108
   276
/// g++ -DLEMON_ENABLE_ASSERTS
deba@108
   277
/// make CXXFLAGS='-DLEMON_ENABLE_ASSERTS'
deba@108
   278
/// \endcode
deba@108
   279
/// 
deba@108
   280
/// The %lemon assertion system has a wide range of customization
deba@108
   281
/// properties. As default behaviour the failed assertion prints a
deba@108
   282
/// short log message to the standard ouput and aborts the execution.
kpeter@66
   283
///
deba@108
   284
/// The following modes can be used in the assertion system: 
kpeter@66
   285
///
deba@108
   286
/// - \e LEMON_ASSERT_LOG The failed assert print a short convenient
deba@108
   287
///   error message to the standard error and continues the
deba@108
   288
///   execution.
deba@108
   289
/// - \e LEMON_ASSERT_ABORT This mode is similar to the \e
deba@108
   290
///   LEMON_ASSERT_LOG, but it aborts the program. It is the default
deba@108
   291
///   operation mode when the asserts are enabled with \e
deba@108
   292
///   LEMON_ENABLE_ASSERTS.
deba@108
   293
/// - \e LEMON_ASSERT_ERROR The assert throws an \ref
deba@108
   294
///   lemon::AssertionFailedError "AssertionFailedError". If the \c
deba@108
   295
///   msg parameter is an exception, then the result of the \ref
deba@108
   296
///   lemon::Exception::what() "what()" member function is passed as
deba@108
   297
///   error message.
deba@108
   298
/// - \e LEMON_ASSERT_EXCEPTION If the specified \c msg is an
deba@108
   299
///   exception then it raised directly (solving that the exception
deba@108
   300
///   can not be thrown polymorphically), otherwise an \ref
deba@108
   301
///   lemon::AssertionFailedError "AssertionFailedError" is thrown with
deba@108
   302
///   the given parameter.
deba@108
   303
/// - \e LEMON_ASSERT_CUSTOM The user can define an own assertion
deba@108
   304
///   handler functions. Three overloaded functions should be defined
deba@108
   305
///   with the following parameter lists:
deba@108
   306
///   \code
deba@108
   307
///     void custom_assert_handler(const char* file, int line, 
deba@108
   308
///                                const char* function, const char* message, const char* expression);
deba@108
   309
///     void custom_assert_handler(const char* file, int line, 
deba@108
   310
///                                const char* function, const std::string& message, const char* expression);
deba@108
   311
///     void custom_assert_handler(const char* file, int line, 
deba@108
   312
///                                const char* function, const std::exception& message, const char* expression);
deba@108
   313
///   \endcode
deba@108
   314
///   The name of the functions should be defined as the \c
deba@108
   315
///   LEMON_CUSTOM_ASSERT_HANDLER macro name. 
deba@108
   316
///   \code
deba@108
   317
///     #define LEMON_CUSTOM_ASSERT_HANDLER custom_assert_handler
deba@108
   318
///   \endcode
deba@108
   319
///   Whenever an assertion is occured, one of the custom assertion
deba@108
   320
///   handler is called with appropiate parameters.
kpeter@66
   321
///
deba@108
   322
/// The assertion mode can be changed within one compilation unit, if
deba@108
   323
/// the macros are redefined with other settings and the
deba@108
   324
/// lemon/assert.h file is reincluded then the behaviour is changed
deba@108
   325
/// appropiately to the new settings.
deba@108
   326
#  define LEMON_ASSERT(exp, msg)					\
deba@108
   327
  (static_cast<void> (!!(exp) ? 0 : (					\
deba@108
   328
    LEMON_ASSERT_HANDLER(__FILE__, __LINE__,				\
deba@108
   329
			 LEMON_FUNCTION_NAME,				\
deba@108
   330
			 msg, #exp), 0)))
deba@108
   331
deba@108
   332
deba@108
   333
/// \ingroup exceptions
kpeter@66
   334
///
deba@108
   335
/// \brief Macro for mark not yet implemented features.
deba@108
   336
///
deba@108
   337
/// Macro for mark not yet implemented features and outstanding bugs.
deba@108
   338
/// It is close to be the shortcut of the following code:
deba@108
   339
/// \code
deba@108
   340
///   LEMON_ASSERT(false, msg);
deba@108
   341
/// \endcode
deba@108
   342
#  define LEMON_FIXME(msg)						\
deba@108
   343
       (LEMON_ASSERT_HANDLER(__FILE__, __LINE__, LEMON_FUNCTION_NAME,	\
deba@108
   344
			     "FIXME: " msg, static_cast<const char*>(0)))
kpeter@66
   345
kpeter@66
   346
#else
kpeter@66
   347
deba@108
   348
#  ifndef LEMON_ASSERT_HANDLER
kpeter@66
   349
#    define LEMON_ASSERT(exp, msg)  (static_cast<void> (0))
deba@108
   350
#    define LEMON_FIXME(msg) (static_cast<void>(0))
kpeter@66
   351
#  else
kpeter@66
   352
#    define LEMON_ASSERT(exp, msg)                 \
kpeter@66
   353
       (static_cast<void> (!!(exp) ? 0 : (         \
kpeter@66
   354
         LEMON_ASSERT_HANDLER(__FILE__, __LINE__,  \
deba@108
   355
                              LEMON_FUNCTION_NAME, \
deba@108
   356
                              msg, #exp), 0)))
deba@108
   357
#    define LEMON_FIXME(msg) \
deba@108
   358
       (LEMON_ASSERT_HANDLER(__FILE__, __LINE__, LEMON_FUNCTION_NAME,	\
deba@108
   359
			     "FIXME: " msg,  static_cast<const char*>(0)))
kpeter@66
   360
#  endif
deba@108
   361
kpeter@66
   362
#endif
kpeter@66
   363
kpeter@66
   364