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 +