1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/lemon/error.h Mon May 23 04:48:14 2005 +0000
1.3 @@ -0,0 +1,539 @@
1.4 +/* -*- C++ -*-
1.5 + * lemon/error.h - Part of LEMON, a generic C++ optimization library
1.6 + *
1.7 + * Copyright (C) 2005 Egervary Jeno Kombinatorikus Optimalizalasi
1.8 + * Kutatocsoport (Egervary Research Group on Combinatorial Optimization,
1.9 + * EGRES).
1.10 + *
1.11 + * Permission to use, modify and distribute this software is granted
1.12 + * provided that this copyright notice appears in all copies. For
1.13 + * precise terms see the accompanying LICENSE file.
1.14 + *
1.15 + * This software is provided "AS IS" with no warranty of any kind,
1.16 + * express or implied, and with no claim as to its suitability for any
1.17 + * purpose.
1.18 + *
1.19 + */
1.20 +
1.21 +#ifndef LEMON_ERROR_H
1.22 +#define LEMON_ERROR_H
1.23 +
1.24 +//! \ingroup exceptions
1.25 +//! \file
1.26 +//! \brief Basic exception classes and error handling.
1.27 +
1.28 +#include <exception>
1.29 +#include <string>
1.30 +#include <sstream>
1.31 +#include <iostream>
1.32 +#include <cstdlib>
1.33 +#include <memory>
1.34 +
1.35 +namespace lemon {
1.36 +
1.37 + /// \addtogroup exceptions
1.38 + /// @{
1.39 +
1.40 + /// \brief Exception safe wrapper class.
1.41 + ///
1.42 + /// Exception safe wrapper class to implement the members of exceptions.
1.43 + template <typename _Type>
1.44 + class ExceptionMember {
1.45 + public:
1.46 + typedef _Type Type;
1.47 +
1.48 + ExceptionMember() throw () {
1.49 + try {
1.50 + ptr.reset(new Type());
1.51 + } catch (...) {}
1.52 + }
1.53 +
1.54 + ExceptionMember(const Type& type) throw () {
1.55 + try {
1.56 + ptr.reset(new Type());
1.57 + if (ptr.get() == 0) return;
1.58 + *ptr = type;
1.59 + } catch (...) {}
1.60 + }
1.61 +
1.62 + ExceptionMember(const ExceptionMember& copy) throw() {
1.63 + try {
1.64 + if (!copy.valid()) return;
1.65 + ptr.reset(new Type());
1.66 + if (ptr.get() == 0) return;
1.67 + *ptr = copy.get();
1.68 + } catch (...) {}
1.69 + }
1.70 +
1.71 + ExceptionMember& operator=(const ExceptionMember& copy) {
1.72 + if (ptr.get() == 0) return;
1.73 + try {
1.74 + if (!copy.valid()) return;
1.75 + *ptr = copy.get();
1.76 + } catch (...) {}
1.77 + }
1.78 +
1.79 + void set(const Type& type) {
1.80 + if (ptr.get() == 0) return;
1.81 + try {
1.82 + *ptr = type;
1.83 + } catch (...) {}
1.84 + }
1.85 +
1.86 + const Type& get() const {
1.87 + return *ptr;
1.88 + }
1.89 +
1.90 + bool valid() const {
1.91 + return ptr.get() != 0;
1.92 + }
1.93 +
1.94 + private:
1.95 + std::auto_ptr<_Type> ptr;
1.96 + };
1.97 +
1.98 + /// Exception-safe convenient "error message" class.
1.99 +
1.100 + /// Helper class which provides a convenient ostream-like (operator <<
1.101 + /// based) interface to create a string message. Mostly useful in
1.102 + /// exception classes (therefore the name).
1.103 + class ErrorMessage {
1.104 + protected:
1.105 + ///\e
1.106 + ///\todo The good solution is boost:shared_ptr...
1.107 + mutable
1.108 + std::auto_ptr<std::ostringstream> buf;
1.109 +
1.110 + ///\e
1.111 + bool init() throw() {
1.112 + try {
1.113 + buf.reset(new std::ostringstream);
1.114 + }
1.115 + catch(...) {
1.116 + buf.reset();
1.117 + }
1.118 + return buf.get();
1.119 + }
1.120 +
1.121 + public:
1.122 +
1.123 + ///\e
1.124 + ErrorMessage() throw() { init(); }
1.125 +
1.126 + ErrorMessage(const ErrorMessage& em) throw() : buf(em.buf) { }
1.127 +
1.128 + ///\e
1.129 + ErrorMessage(const char *message) throw() {
1.130 + init();
1.131 + *this << message;
1.132 + }
1.133 +
1.134 + ///\e
1.135 + ErrorMessage(const std::string &message) throw() {
1.136 + init();
1.137 + *this << message;
1.138 + }
1.139 +
1.140 + ///\e
1.141 + template <typename T>
1.142 + ErrorMessage& operator<<(const T &t) throw() {
1.143 + if( ! buf.get() ) return *this;
1.144 +
1.145 + try {
1.146 + *buf << t;
1.147 + }
1.148 + catch(...) {
1.149 + buf.reset();
1.150 + }
1.151 + return *this;
1.152 + }
1.153 +
1.154 + ///\e
1.155 + const char* message() throw() {
1.156 + if( ! buf.get() ) return 0;
1.157 +
1.158 + const char* mes = 0;
1.159 + try {
1.160 + mes = buf->str().c_str();
1.161 + }
1.162 + catch(...) {}
1.163 + return mes;
1.164 + }
1.165 +
1.166 + };
1.167 +
1.168 + /**
1.169 + * \brief Generic exception class.
1.170 + *
1.171 + * Base class for exceptions used in LEMON.
1.172 + */
1.173 + class Exception : public std::exception {
1.174 + public:
1.175 + ///\e
1.176 + Exception() {}
1.177 + ///\e
1.178 + virtual ~Exception() throw() {}
1.179 +
1.180 + ///\e
1.181 + virtual const char* exceptionName() const {
1.182 + return "lemon::Exception";
1.183 + }
1.184 +
1.185 + ///\e
1.186 + virtual const char* what() const throw() {
1.187 + return exceptionName();
1.188 + }
1.189 + };
1.190 +
1.191 + /**
1.192 + * \brief One of the two main subclasses of \ref Exception.
1.193 + *
1.194 + * Logic errors represent problems in the internal logic of a program;
1.195 + * in theory, these are preventable, and even detectable before the
1.196 + * program runs (e.g., violations of class invariants).
1.197 + *
1.198 + * A typical example for this is \ref UninitializedParameter.
1.199 + */
1.200 + class LogicError : public Exception {
1.201 + public:
1.202 + virtual const char* exceptionName() const {
1.203 + return "lemon::LogicError";
1.204 + }
1.205 + };
1.206 +
1.207 + /**
1.208 + * \brief \ref Exception for uninitialized parameters.
1.209 + *
1.210 + * This error represents problems in the initialization
1.211 + * of the parameters of the algorithms.
1.212 + */
1.213 + class UninitializedParameter : public LogicError {
1.214 + public:
1.215 + virtual const char* exceptionName() const {
1.216 + return "lemon::UninitializedParameter";
1.217 + }
1.218 + };
1.219 +
1.220 +
1.221 + /**
1.222 + * \brief One of the two main subclasses of \ref Exception.
1.223 + *
1.224 + * Runtime errors represent problems outside the scope of a program;
1.225 + * they cannot be easily predicted and can generally only be caught as
1.226 + * the program executes.
1.227 + */
1.228 + class RuntimeError : public Exception {
1.229 + public:
1.230 + virtual const char* exceptionName() const {
1.231 + return "lemon::RuntimeError";
1.232 + }
1.233 + };
1.234 +
1.235 + ///\e
1.236 + class RangeError : public RuntimeError {
1.237 + public:
1.238 + virtual const char* exceptionName() const {
1.239 + return "lemon::RangeError";
1.240 + }
1.241 + };
1.242 +
1.243 + ///\e
1.244 + class IOError : public RuntimeError {
1.245 + public:
1.246 + virtual const char* exceptionName() const {
1.247 + return "lemon::IOError";
1.248 + }
1.249 + };
1.250 +
1.251 + ///\e
1.252 + class DataFormatError : public IOError {
1.253 + protected:
1.254 + ExceptionMember<std::string> _message;
1.255 + ExceptionMember<std::string> _file;
1.256 + int _line;
1.257 +
1.258 + mutable ExceptionMember<std::string> _message_holder;
1.259 + public:
1.260 +
1.261 + DataFormatError(const DataFormatError &dfe) :
1.262 + IOError(dfe), _message(dfe._message), _file(dfe._file),
1.263 + _line(dfe._line) {}
1.264 +
1.265 + ///\e
1.266 + explicit DataFormatError(const char *the_message)
1.267 + : _message(the_message), _line(0) {}
1.268 +
1.269 + ///\e
1.270 + DataFormatError(const std::string &file_name, int line_num,
1.271 + const char *the_message)
1.272 + : _message(the_message), _line(line_num) { file(file_name); }
1.273 +
1.274 + ///\e
1.275 + void line(int line) { _line = line; }
1.276 + ///\e
1.277 + void message(const std::string& message) { _message.set(message); }
1.278 + ///\e
1.279 + void file(const std::string &file) { _file.set(file); }
1.280 +
1.281 + ///\e
1.282 + int line() const { return _line; }
1.283 + ///\e
1.284 + const char* message() const {
1.285 + if (_message.valid() && !_message.get().empty()) {
1.286 + return _message.get().c_str();
1.287 + } else {
1.288 + return 0;
1.289 + }
1.290 + }
1.291 +
1.292 + /// \brief Returns the filename.
1.293 + ///
1.294 + /// Returns \e null if the filename was not specified.
1.295 + const char* file() const {
1.296 + if (_file.valid() && !_file.get().empty()) {
1.297 + return _file.get().c_str();
1.298 + } else {
1.299 + return 0;
1.300 + }
1.301 + }
1.302 +
1.303 + ///\e
1.304 + virtual const char* what() const throw() {
1.305 + try {
1.306 + std::ostringstream ostr;
1.307 + ostr << exceptionName() << ": ";
1.308 + if (message()) ostr << message();
1.309 + if( file() || line() != 0 ) {
1.310 + ostr << " (";
1.311 + if( file() ) ostr << "in file '" << file() << "'";
1.312 + if( file() && line() != 0 ) ostr << " ";
1.313 + if( line() != 0 ) ostr << "at line " << line();
1.314 + ostr << ")";
1.315 + }
1.316 + _message_holder.set(ostr.str());
1.317 + }
1.318 + catch (...) {}
1.319 + if( _message_holder.valid()) return _message_holder.get().c_str();
1.320 + return exceptionName();
1.321 + }
1.322 +
1.323 + virtual const char* exceptionName() const {
1.324 + return "lemon::DataFormatError";
1.325 + }
1.326 +
1.327 + virtual ~DataFormatError() throw() {}
1.328 + };
1.329 +
1.330 + class IOParameterError : public LogicError {
1.331 + protected:
1.332 + ExceptionMember<std::string> _message;
1.333 + ExceptionMember<std::string> _file;
1.334 +
1.335 + mutable ExceptionMember<std::string> _message_holder;
1.336 + public:
1.337 +
1.338 + IOParameterError(const IOParameterError &ile) :
1.339 + LogicError(ile), _message(ile._message), _file(ile._file) {}
1.340 +
1.341 + ///\e
1.342 + explicit IOParameterError(const char *the_message)
1.343 + : _message(the_message) {}
1.344 +
1.345 + ///\e
1.346 + IOParameterError(const char *file_name, const char *the_message)
1.347 + : _message(the_message), _file(file_name) {}
1.348 +
1.349 + ///\e
1.350 + void message(const std::string& message) { _message.set(message); }
1.351 + ///\e
1.352 + void file(const std::string &file) { _file.set(file); }
1.353 +
1.354 + ///\e
1.355 + const char* message() const {
1.356 + if (_message.valid()) {
1.357 + return _message.get().c_str();
1.358 + } else {
1.359 + return 0;
1.360 + }
1.361 + }
1.362 +
1.363 + /// \brief Returns the filename.
1.364 + ///
1.365 + /// Returns \e null if the filename was not specified.
1.366 + const char* file() const {
1.367 + if (_file.valid()) {
1.368 + return _file.get().c_str();
1.369 + } else {
1.370 + return 0;
1.371 + }
1.372 + }
1.373 +
1.374 + ///\e
1.375 + virtual const char* what() const throw() {
1.376 + try {
1.377 + std::ostringstream ostr;
1.378 + if (message()) ostr << message();
1.379 + if (file()) ostr << "(when reading file '" << file() << "')";
1.380 + _message_holder.set(ostr.str());
1.381 + }
1.382 + catch (...) {}
1.383 + if( _message_holder.valid() ) return _message_holder.get().c_str();
1.384 + return exceptionName();
1.385 + }
1.386 +
1.387 + virtual const char* exceptionName() const {
1.388 + return "lemon::IOParameterError";
1.389 + }
1.390 +
1.391 + virtual ~IOParameterError() throw() {}
1.392 + };
1.393 +
1.394 +
1.395 + ///\e
1.396 + class AssertionFailedError : public LogicError {
1.397 + protected:
1.398 + const char *assertion;
1.399 + const char *file;
1.400 + int line;
1.401 + const char *function;
1.402 + const char *message;
1.403 +
1.404 + mutable ExceptionMember<std::string> _message_holder;
1.405 + public:
1.406 + ///\e
1.407 + AssertionFailedError(const char *_file, int _line, const char *func,
1.408 + const char *msg, const char *_assertion = 0) :
1.409 + assertion(_assertion), file(_file), line(_line), function(func),
1.410 + message(msg) {}
1.411 +
1.412 + ///\e
1.413 + const char* get_assertion() const { return assertion; }
1.414 + ///\e
1.415 + const char* get_message() const { return message; }
1.416 + ///\e
1.417 + const char* get_file() const { return file; }
1.418 + ///\e
1.419 + const char* get_function() const { return function; }
1.420 + ///\e
1.421 + int get_line() const { return line; }
1.422 +
1.423 +
1.424 + virtual const char* what() const throw() {
1.425 + try {
1.426 + std::ostringstream ostr;
1.427 + ostr << file << ":" << line << ": ";
1.428 + if( function )
1.429 + ostr << function << ": ";
1.430 + ostr << message;
1.431 + if( assertion )
1.432 + ostr << " (assertion '" << assertion << "' failed)";
1.433 + _message_holder.set(ostr.str());
1.434 + return ostr.str().c_str();
1.435 + }
1.436 + catch(...) {}
1.437 + if( _message_holder.valid() ) return _message_holder.get().c_str();
1.438 + return exceptionName();
1.439 + }
1.440 +
1.441 + virtual const char* exceptionName() const {
1.442 + return "lemon::AssertionFailedError";
1.443 + }
1.444 +
1.445 + virtual ~AssertionFailedError() throw() {}
1.446 + };
1.447 +
1.448 +
1.449 + /**************** Macros ****************/
1.450 +
1.451 +
1.452 + inline
1.453 + void assert_fail(const char *file, int line, const char *func,
1.454 + const char *message, const char *assertion = 0,
1.455 + bool do_abort=true)
1.456 + {
1.457 + using namespace std;
1.458 + cerr << file << ":" << line << ": ";
1.459 + if( func )
1.460 + cerr << func << ": ";
1.461 + cerr << message;
1.462 + if( assertion )
1.463 + cerr << " (assertion '" << assertion << "' failed)";
1.464 + cerr << endl;
1.465 + if(do_abort)
1.466 + abort();
1.467 + }
1.468 +
1.469 + inline
1.470 + void assert_fail_throw(const char *file, int line, const char *func,
1.471 + const char *message, const char *assertion = 0,
1.472 + bool = true)
1.473 + {
1.474 + throw AssertionFailedError(file, line, func, message, assertion);
1.475 + }
1.476 +
1.477 +/// @}
1.478 +
1.479 +}
1.480 +#endif // LEMON_ERROR_H
1.481 +
1.482 +#undef LEMON_ASSERT
1.483 +#undef LEMON_FIXME
1.484 +
1.485 +#ifndef LEMON_ASSERT_ABORT
1.486 +# define LEMON_ASSERT_ABORT 1
1.487 +#endif
1.488 +
1.489 +#ifndef LEMON_ASSERT_HANDLER
1.490 +# ifdef LEMON_ASSERT_EXCEPTION
1.491 +# define LEMON_ASSERT_HANDLER ::lemon::assert_fail_throw
1.492 +# else
1.493 +# define LEMON_ASSERT_HANDLER ::lemon::assert_fail
1.494 +# endif
1.495 +#endif
1.496 +
1.497 +#if defined(NDEBUG) || defined(LEMON_DISABLE_ASSERTS)
1.498 +
1.499 +# define LEMON_ASSERT(exp, msg) (static_cast<void> (0))
1.500 +
1.501 +#else
1.502 +
1.503 +/**
1.504 + * \brief Macro for assertions with customizable message
1.505 + *
1.506 + * Macro for assertions with customizable message.
1.507 + *
1.508 + * The behaviour can be customized with LEMON_ASSERT_HANDLER,
1.509 + * LEMON_ASSERT_EXCEPTION and LEMON_ASSERT_ABORT defines. Asserts can be
1.510 + * disabled by defining either NDEBUG or LEMON_DISABLE_ASSERTS macros.
1.511 + *
1.512 + * \todo We should provide some way to reset to the default behaviour,
1.513 + * shouldn't we?
1.514 + *
1.515 + * \todo This whole 'assert' business should be placed in a separate
1.516 + * include file.
1.517 + *
1.518 + * \todo __PRETTY_FUNCTION__ should be replaced by something
1.519 + * compiler-independent, like BOOST_CURRENT_FUNCTION
1.520 + */
1.521 +
1.522 +# define LEMON_ASSERT(exp, msg) \
1.523 + (static_cast<void> (!!(exp) ? 0 : ( \
1.524 + LEMON_ASSERT_HANDLER(__FILE__, __LINE__, \
1.525 + __PRETTY_FUNCTION__, \
1.526 + (msg), #exp, LEMON_ASSERT_ABORT), 0)))
1.527 +
1.528 +#endif // NDEBUG || LEMON_DISABLE_ASSERTS
1.529 +
1.530 +/**
1.531 + * \brief Macro for mark not yet implemented features.
1.532 + *
1.533 + * \todo Is this the right place for this? It should be used only in
1.534 + * modules under development.
1.535 + *
1.536 + * \todo __PRETTY_FUNCTION__ should be replaced by something
1.537 + * compiler-independent, like BOOST_CURRENT_FUNCTION
1.538 + */
1.539 +
1.540 +# define LEMON_FIXME(msg) \
1.541 + (LEMON_ASSERT_HANDLER(__FILE__, __LINE__, __PRETTY_FUNCTION__, \
1.542 + "FIXME: " msg))