1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/lemon/error.h Thu Feb 07 21:28:39 2008 +0000
1.3 @@ -0,0 +1,675 @@
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_ERROR_H
1.23 +#define LEMON_ERROR_H
1.24 +
1.25 +/// \ingroup exceptions
1.26 +/// \file
1.27 +/// \brief Basic exception classes and error handling.
1.28 +
1.29 +#include <exception>
1.30 +#include <string>
1.31 +#include <sstream>
1.32 +#include <iostream>
1.33 +#include <cstdlib>
1.34 +#include <memory>
1.35 +
1.36 +namespace lemon {
1.37 +
1.38 + /// \addtogroup exceptions
1.39 + /// @{
1.40 +
1.41 + /// \brief Exception safe wrapper class.
1.42 + ///
1.43 + /// Exception safe wrapper class to implement the members of exceptions.
1.44 + template <typename _Type>
1.45 + class ExceptionMember {
1.46 + public:
1.47 + typedef _Type Type;
1.48 +
1.49 + ExceptionMember() throw() {
1.50 + try {
1.51 + ptr.reset(new Type());
1.52 + } catch (...) {}
1.53 + }
1.54 +
1.55 + ExceptionMember(const Type& type) throw() {
1.56 + try {
1.57 + ptr.reset(new Type());
1.58 + if (ptr.get() == 0) return;
1.59 + *ptr = type;
1.60 + } catch (...) {}
1.61 + }
1.62 +
1.63 + ExceptionMember(const ExceptionMember& copy) throw() {
1.64 + try {
1.65 + if (!copy.valid()) return;
1.66 + ptr.reset(new Type());
1.67 + if (ptr.get() == 0) return;
1.68 + *ptr = copy.get();
1.69 + } catch (...) {}
1.70 + }
1.71 +
1.72 + ExceptionMember& operator=(const ExceptionMember& copy) throw() {
1.73 + if (ptr.get() == 0) return;
1.74 + try {
1.75 + if (!copy.valid()) return;
1.76 + *ptr = copy.get();
1.77 + } catch (...) {}
1.78 + }
1.79 +
1.80 + void set(const Type& type) throw() {
1.81 + if (ptr.get() == 0) return;
1.82 + try {
1.83 + *ptr = type;
1.84 + } catch (...) {}
1.85 + }
1.86 +
1.87 + const Type& get() const {
1.88 + return *ptr;
1.89 + }
1.90 +
1.91 + bool valid() const throw() {
1.92 + return ptr.get() != 0;
1.93 + }
1.94 +
1.95 + private:
1.96 + std::auto_ptr<_Type> ptr;
1.97 + };
1.98 +
1.99 + /// Exception-safe convenient "error message" class.
1.100 +
1.101 + /// Helper class which provides a convenient ostream-like (operator <<
1.102 + /// based) interface to create a string message. Mostly useful in
1.103 + /// exception classes (therefore the name).
1.104 + class ErrorMessage {
1.105 + protected:
1.106 + ///\e
1.107 +
1.108 + ///\todo The good solution is boost::shared_ptr...
1.109 + ///
1.110 + mutable std::auto_ptr<std::ostringstream> buf;
1.111 +
1.112 + ///\e
1.113 + bool init() throw() {
1.114 + try {
1.115 + buf.reset(new std::ostringstream);
1.116 + }
1.117 + catch(...) {
1.118 + buf.reset();
1.119 + }
1.120 + return buf.get();
1.121 + }
1.122 +
1.123 + public:
1.124 +
1.125 + ///\e
1.126 + ErrorMessage() throw() { init(); }
1.127 +
1.128 + ErrorMessage(const ErrorMessage& em) throw() : buf(em.buf) { }
1.129 +
1.130 + ///\e
1.131 + ErrorMessage(const char *msg) throw() {
1.132 + init();
1.133 + *this << msg;
1.134 + }
1.135 +
1.136 + ///\e
1.137 + ErrorMessage(const std::string &msg) throw() {
1.138 + init();
1.139 + *this << msg;
1.140 + }
1.141 +
1.142 + ///\e
1.143 + template <typename T>
1.144 + ErrorMessage& operator<<(const T &t) throw() {
1.145 + if( ! buf.get() ) return *this;
1.146 +
1.147 + try {
1.148 + *buf << t;
1.149 + }
1.150 + catch(...) {
1.151 + buf.reset();
1.152 + }
1.153 + return *this;
1.154 + }
1.155 +
1.156 + ///\e
1.157 + const char* message() throw() {
1.158 + if( ! buf.get() ) return 0;
1.159 +
1.160 + const char* mes = 0;
1.161 + try {
1.162 + mes = buf->str().c_str();
1.163 + }
1.164 + catch(...) {}
1.165 + return mes;
1.166 + }
1.167 +
1.168 + };
1.169 +
1.170 + /// Generic exception class.
1.171 +
1.172 + /// Base class for exceptions used in LEMON.
1.173 + ///
1.174 + class Exception : public std::exception {
1.175 + public:
1.176 + ///\e
1.177 + Exception() {}
1.178 + ///\e
1.179 + virtual ~Exception() throw() {}
1.180 + ///\e
1.181 + virtual const char* what() const throw() {
1.182 + return "lemon::Exception";
1.183 + }
1.184 + };
1.185 +
1.186 + /// One of the two main subclasses of \ref Exception.
1.187 +
1.188 + /// Logic errors represent problems in the internal logic of a program;
1.189 + /// in theory, these are preventable, and even detectable before the
1.190 + /// program runs (e.g. violations of class invariants).
1.191 + ///
1.192 + /// A typical example for this is \ref UninitializedParameter.
1.193 + class LogicError : public Exception {
1.194 + public:
1.195 + virtual const char* what() const throw() {
1.196 + return "lemon::LogicError";
1.197 + }
1.198 + };
1.199 +
1.200 + /// \ref Exception for uninitialized parameters.
1.201 +
1.202 + /// This error represents problems in the initialization
1.203 + /// of the parameters of the algorithms.
1.204 + class UninitializedParameter : public LogicError {
1.205 + public:
1.206 + virtual const char* what() const throw() {
1.207 + return "lemon::UninitializedParameter";
1.208 + }
1.209 + };
1.210 +
1.211 +
1.212 + /// One of the two main subclasses of \ref Exception.
1.213 +
1.214 + /// Runtime errors represent problems outside the scope of a program;
1.215 + /// they cannot be easily predicted and can generally only be caught
1.216 + /// as the program executes.
1.217 + class RuntimeError : public Exception {
1.218 + public:
1.219 + virtual const char* what() const throw() {
1.220 + return "lemon::RuntimeError";
1.221 + }
1.222 + };
1.223 +
1.224 + ///\e
1.225 + class RangeError : public RuntimeError {
1.226 + public:
1.227 + virtual const char* what() const throw() {
1.228 + return "lemon::RangeError";
1.229 + }
1.230 + };
1.231 +
1.232 + ///\e
1.233 + class IoError : public RuntimeError {
1.234 + public:
1.235 + virtual const char* what() const throw() {
1.236 + return "lemon::IoError";
1.237 + }
1.238 + };
1.239 +
1.240 + ///\e
1.241 + class DataFormatError : public IoError {
1.242 + protected:
1.243 + ExceptionMember<std::string> _message;
1.244 + ExceptionMember<std::string> _file;
1.245 + int _line;
1.246 +
1.247 + mutable ExceptionMember<std::string> _message_holder;
1.248 + public:
1.249 +
1.250 + DataFormatError(const DataFormatError &dfe) :
1.251 + IoError(dfe), _message(dfe._message), _file(dfe._file),
1.252 + _line(dfe._line) {}
1.253 +
1.254 + ///\e
1.255 + explicit DataFormatError(const char *the_message)
1.256 + : _message(the_message), _line(0) {}
1.257 +
1.258 + ///\e
1.259 + DataFormatError(const std::string &file_name, int line_num,
1.260 + const char *the_message)
1.261 + : _message(the_message), _line(line_num) { file(file_name); }
1.262 +
1.263 + ///\e
1.264 + void line(int ln) { _line = ln; }
1.265 + ///\e
1.266 + void message(const std::string& msg) { _message.set(msg); }
1.267 + ///\e
1.268 + void file(const std::string &fl) { _file.set(fl); }
1.269 +
1.270 + ///\e
1.271 + int line() const { return _line; }
1.272 + ///\e
1.273 + const char* message() const {
1.274 + if (_message.valid() && !_message.get().empty()) {
1.275 + return _message.get().c_str();
1.276 + } else {
1.277 + return 0;
1.278 + }
1.279 + }
1.280 +
1.281 + /// \brief Returns the filename.
1.282 + ///
1.283 + /// Returns \e null if the filename was not specified.
1.284 + const char* file() const {
1.285 + if (_file.valid() && !_file.get().empty()) {
1.286 + return _file.get().c_str();
1.287 + } else {
1.288 + return 0;
1.289 + }
1.290 + }
1.291 +
1.292 + ///\e
1.293 + virtual const char* what() const throw() {
1.294 + try {
1.295 + std::ostringstream ostr;
1.296 + ostr << "lemon:DataFormatError" << ": ";
1.297 + if (message()) ostr << message();
1.298 + if( file() || line() != 0 ) {
1.299 + ostr << " (";
1.300 + if( file() ) ostr << "in file '" << file() << "'";
1.301 + if( file() && line() != 0 ) ostr << " ";
1.302 + if( line() != 0 ) ostr << "at line " << line();
1.303 + ostr << ")";
1.304 + }
1.305 + _message_holder.set(ostr.str());
1.306 + }
1.307 + catch (...) {}
1.308 + if( _message_holder.valid()) return _message_holder.get().c_str();
1.309 + return "lemon:DataFormatError";
1.310 + }
1.311 +
1.312 + virtual ~DataFormatError() throw() {}
1.313 + };
1.314 +
1.315 + ///\e
1.316 + class FileOpenError : public IoError {
1.317 + protected:
1.318 + ExceptionMember<std::string> _file;
1.319 +
1.320 + mutable ExceptionMember<std::string> _message_holder;
1.321 + public:
1.322 +
1.323 + FileOpenError(const FileOpenError &foe) :
1.324 + IoError(foe), _file(foe._file) {}
1.325 +
1.326 + ///\e
1.327 + explicit FileOpenError(const std::string& fl)
1.328 + : _file(fl) {}
1.329 +
1.330 +
1.331 + ///\e
1.332 + void file(const std::string &fl) { _file.set(fl); }
1.333 +
1.334 + /// \brief Returns the filename.
1.335 + ///
1.336 + /// Returns \e null if the filename was not specified.
1.337 + const char* file() const {
1.338 + if (_file.valid() && !_file.get().empty()) {
1.339 + return _file.get().c_str();
1.340 + } else {
1.341 + return 0;
1.342 + }
1.343 + }
1.344 +
1.345 + ///\e
1.346 + virtual const char* what() const throw() {
1.347 + try {
1.348 + std::ostringstream ostr;
1.349 + ostr << "lemon::FileOpenError" << ": ";
1.350 + ostr << "Cannot open file - " << file();
1.351 + _message_holder.set(ostr.str());
1.352 + }
1.353 + catch (...) {}
1.354 + if( _message_holder.valid()) return _message_holder.get().c_str();
1.355 + return "lemon::FileOpenError";
1.356 + }
1.357 + virtual ~FileOpenError() throw() {}
1.358 + };
1.359 +
1.360 + class IoParameterError : public IoError {
1.361 + protected:
1.362 + ExceptionMember<std::string> _message;
1.363 + ExceptionMember<std::string> _file;
1.364 +
1.365 + mutable ExceptionMember<std::string> _message_holder;
1.366 + public:
1.367 +
1.368 + IoParameterError(const IoParameterError &ile) :
1.369 + IoError(ile), _message(ile._message), _file(ile._file) {}
1.370 +
1.371 + ///\e
1.372 + explicit IoParameterError(const char *the_message)
1.373 + : _message(the_message) {}
1.374 +
1.375 + ///\e
1.376 + IoParameterError(const char *file_name, const char *the_message)
1.377 + : _message(the_message), _file(file_name) {}
1.378 +
1.379 + ///\e
1.380 + void message(const std::string& msg) { _message.set(msg); }
1.381 + ///\e
1.382 + void file(const std::string &fl) { _file.set(fl); }
1.383 +
1.384 + ///\e
1.385 + const char* message() const {
1.386 + if (_message.valid()) {
1.387 + return _message.get().c_str();
1.388 + } else {
1.389 + return 0;
1.390 + }
1.391 + }
1.392 +
1.393 + /// \brief Returns the filename.
1.394 + ///
1.395 + /// Returns \c 0 if the filename was not specified.
1.396 + const char* file() const {
1.397 + if (_file.valid()) {
1.398 + return _file.get().c_str();
1.399 + } else {
1.400 + return 0;
1.401 + }
1.402 + }
1.403 +
1.404 + ///\e
1.405 + virtual const char* what() const throw() {
1.406 + try {
1.407 + std::ostringstream ostr;
1.408 + if (message()) ostr << message();
1.409 + if (file()) ostr << "(when reading file '" << file() << "')";
1.410 + _message_holder.set(ostr.str());
1.411 + }
1.412 + catch (...) {}
1.413 + if( _message_holder.valid() ) return _message_holder.get().c_str();
1.414 + return "lemon:IoParameterError";
1.415 + }
1.416 + virtual ~IoParameterError() throw() {}
1.417 + };
1.418 +
1.419 +
1.420 + ///\e
1.421 + class AssertionFailedError : public LogicError {
1.422 + protected:
1.423 + const char *assertion;
1.424 + const char *file;
1.425 + int line;
1.426 + const char *function;
1.427 + const char *message;
1.428 +
1.429 + mutable ExceptionMember<std::string> _message_holder;
1.430 + public:
1.431 + ///\e
1.432 + AssertionFailedError(const char *_file, int _line, const char *func,
1.433 + const char *msg, const char *_assertion = 0) :
1.434 + assertion(_assertion), file(_file), line(_line), function(func),
1.435 + message(msg) {}
1.436 +
1.437 + ///\e
1.438 + const char* get_assertion() const { return assertion; }
1.439 + ///\e
1.440 + const char* get_message() const { return message; }
1.441 + ///\e
1.442 + const char* get_file() const { return file; }
1.443 + ///\e
1.444 + const char* get_function() const { return function; }
1.445 + ///\e
1.446 + int get_line() const { return line; }
1.447 +
1.448 +
1.449 + virtual const char* what() const throw() {
1.450 + try {
1.451 + std::ostringstream ostr;
1.452 + ostr << file << ":" << line << ": ";
1.453 + if( function )
1.454 + ostr << function << ": ";
1.455 + ostr << message;
1.456 + if( assertion )
1.457 + ostr << " (assertion '" << assertion << "' failed)";
1.458 + _message_holder.set(ostr.str());
1.459 + return ostr.str().c_str();
1.460 + }
1.461 + catch(...) {}
1.462 + if( _message_holder.valid() ) return _message_holder.get().c_str();
1.463 + return "lemon::AssertionFailedError";
1.464 + }
1.465 + virtual ~AssertionFailedError() throw() {}
1.466 + };
1.467 +
1.468 +
1.469 + /**************** Macros ****************/
1.470 +
1.471 +
1.472 + template <typename Exception>
1.473 + inline void assert_fail(const char *file, int line,
1.474 + const char *func,
1.475 + Exception exception,
1.476 + const char *assertion = 0,
1.477 + bool do_abort=true)
1.478 + {
1.479 + using namespace std;
1.480 + cerr << file << ":" << line << ": ";
1.481 + if (func)
1.482 + cerr << func << ": ";
1.483 + cerr << exception.what();
1.484 + if (assertion)
1.485 + cerr << " (assertion '" << assertion << "' failed)";
1.486 + cerr << endl;
1.487 + if (do_abort)
1.488 + abort();
1.489 + }
1.490 +
1.491 + template <>
1.492 + inline void assert_fail<const char *>(const char *file, int line,
1.493 + const char *func,
1.494 + const char *message,
1.495 + const char *assertion,
1.496 + bool do_abort)
1.497 + {
1.498 + using namespace std;
1.499 + cerr << file << ":" << line << ": ";
1.500 + if (func)
1.501 + cerr << func << ": ";
1.502 + cerr << message;
1.503 + if (assertion)
1.504 + cerr << " (assertion '" << assertion << "' failed)";
1.505 + cerr << endl;
1.506 + if (do_abort)
1.507 + abort();
1.508 + }
1.509 +
1.510 + template <>
1.511 + inline void assert_fail<std::string>(const char *file, int line,
1.512 + const char *func,
1.513 + std::string message,
1.514 + const char *assertion,
1.515 + bool do_abort)
1.516 + {
1.517 + assert_fail(file, line, func, message.c_str(), assertion, do_abort);
1.518 + }
1.519 +
1.520 + template <typename Exception>
1.521 + inline void assert_fail_failure(const char *file, int line, const char *func,
1.522 + Exception exception,
1.523 + const char *assertion = 0,
1.524 + bool = true)
1.525 + {
1.526 + throw AssertionFailedError(file, line, func, exception.what(), assertion);
1.527 + }
1.528 +
1.529 + template <>
1.530 + inline void assert_fail_failure<const char *>(const char *file, int line,
1.531 + const char *func,
1.532 + const char *message,
1.533 + const char *assertion,
1.534 + bool)
1.535 + {
1.536 + throw AssertionFailedError(file, line, func, message, assertion);
1.537 + }
1.538 +
1.539 + template <>
1.540 + inline void assert_fail_failure<std::string>(const char *file, int line,
1.541 + const char *func,
1.542 + std::string message,
1.543 + const char *assertion,
1.544 + bool)
1.545 + {
1.546 + assert_fail_failure(file, line, func, message.c_str(), assertion, true);
1.547 + }
1.548 +
1.549 + template <typename Exception>
1.550 + inline void assert_fail_exception(const char *file, int line, const char *func,
1.551 + Exception exception,
1.552 + const char *assertion = 0, bool = true)
1.553 + {
1.554 + throw exception;
1.555 + }
1.556 +
1.557 + template <>
1.558 + inline void assert_fail_exception<const char *>(const char *file, int line,
1.559 + const char *func,
1.560 + const char *message,
1.561 + const char *assertion,
1.562 + bool)
1.563 + {
1.564 + throw AssertionFailedError(file, line, func, message, assertion);
1.565 + }
1.566 +
1.567 + template <>
1.568 + inline void assert_fail_exception<std::string>(const char *file, int line,
1.569 + const char *func,
1.570 + std::string message,
1.571 + const char *assertion,
1.572 + bool)
1.573 + {
1.574 + assert_fail_exception(file, line, func, message.c_str(), assertion, true);
1.575 + }
1.576 +
1.577 +/// @}
1.578 +
1.579 +}
1.580 +#endif // LEMON_ERROR_H
1.581 +
1.582 +#undef LEMON_ASSERT
1.583 +#undef LEMON_FIXME
1.584 +
1.585 +#ifdef LEMON_ENABLE_ASSERTS
1.586 +# define LEMON_ASSERT_ABORT
1.587 +#endif
1.588 +
1.589 +#ifndef LEMON_ASSERT_DO_ABORT
1.590 +# define LEMON_ASSERT_DO_ABORT 1
1.591 +#endif
1.592 +
1.593 +#ifndef LEMON_ASSERT_HANDLER
1.594 +# if defined LEMON_ASSERT_EXCEPTION
1.595 +# define LEMON_ASSERT_HANDLER ::lemon::assert_fail_exception
1.596 +# elif defined LEMON_ASSERT_FAILURE
1.597 +# define LEMON_ASSERT_HANDLER ::lemon::assert_fail_failure
1.598 +# elif defined LEMON_ASSERT_ABORT
1.599 +# define LEMON_ASSERT_HANDLER ::lemon::assert_fail
1.600 +# else
1.601 +# define LEMON_DISABLE_ASSERTS
1.602 +# endif
1.603 +#endif
1.604 +
1.605 +#ifdef DOXYGEN
1.606 +
1.607 +/// \brief Macro for assertions with customizable message
1.608 +///
1.609 +/// Macro for assertions with customizable message.
1.610 +///
1.611 +/// The assertions are disabled in the default behaviour. You can
1.612 +/// enable the assertions with the
1.613 +/// \code
1.614 +/// #define LEMON_ENABLE_ASSERTS
1.615 +/// \endcode
1.616 +/// Then an assert
1.617 +/// provides a log on the standard error about the assertion and aborts
1.618 +/// the program if LEMON_ASSERT_DO_ABORT is also defined (otherwise the
1.619 +/// program keeps on running).
1.620 +/// By defining LEMON_ASSERT_FAILURE or
1.621 +/// LEMON_ASSERT_EXCEPTION, you can set other behaviour to the
1.622 +/// assertions. In case LEMON_ASSERT_FAILURE is given, LEMON_ASSERT
1.623 +/// will always throw an \c AssertionFailedError exception with
1.624 +/// the \c msg error message. By using
1.625 +/// LEMON_ASSERT_EXCEPTION, one can define an arbitrary exception to be thrown.
1.626 +///
1.627 +/// The LEMON_ASSERT macro should be called with the \c exp parameter
1.628 +/// which should be an expression convertible to bool. If the given
1.629 +/// parameter is false the assertion is raised and one of the assertion
1.630 +/// behaviour will be activated. The \c msg should be either a const
1.631 +/// char* message or an exception. When the \c msg is an exception the
1.632 +/// \ref lemon::Exception::what() "what()" function is called to retrieve and
1.633 +/// display the error message.
1.634 +///
1.635 +/// \todo We should provide some way to reset to the default behaviour,
1.636 +/// shouldn't we?
1.637 +///
1.638 +/// \todo This whole 'assert' business should be placed in a separate
1.639 +/// include file. The boost assert is not guarded by header sentries
1.640 +/// which may help to change the behaviour of the assertions in
1.641 +/// the files.
1.642 +///
1.643 +/// \todo __PRETTY_FUNCTION__ should be replaced by something
1.644 +/// compiler-independent, like BOOST_CURRENT_FUNCTION
1.645 +
1.646 +# define LEMON_ASSERT(exp, msg) \
1.647 + (static_cast<void> (!!(exp) ? 0 : ( \
1.648 + LEMON_ASSERT_HANDLER(__FILE__, __LINE__, \
1.649 + __PRETTY_FUNCTION__, \
1.650 + msg, #exp, LEMON_ASSERT_DO_ABORT), 0)))
1.651 +
1.652 +#else
1.653 +# if defined LEMON_DISABLE_ASSERTS
1.654 +
1.655 +# define LEMON_ASSERT(exp, msg) (static_cast<void> (0))
1.656 +
1.657 +# else
1.658 +# define LEMON_ASSERT(exp, msg) \
1.659 + (static_cast<void> (!!(exp) ? 0 : ( \
1.660 + LEMON_ASSERT_HANDLER(__FILE__, __LINE__, \
1.661 + __PRETTY_FUNCTION__, \
1.662 + msg, #exp, LEMON_ASSERT_DO_ABORT), 0)))
1.663 +# endif
1.664 +#endif
1.665 +
1.666 +/**
1.667 + * \brief Macro for mark not yet implemented features.
1.668 + *
1.669 + * \todo Is this the right place for this? It should be used only in
1.670 + * modules under development.
1.671 + *
1.672 + * \todo __PRETTY_FUNCTION__ should be replaced by something
1.673 + * compiler-independent, like BOOST_CURRENT_FUNCTION
1.674 + */
1.675 +
1.676 +#define LEMON_FIXME(msg) \
1.677 + (LEMON_ASSERT_HANDLER(__FILE__, __LINE__, __PRETTY_FUNCTION__, \
1.678 + "FIXME: " msg))