1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/src/lemon/error.h Thu Feb 03 19:31:37 2005 +0000
1.3 @@ -0,0 +1,387 @@
1.4 +/* -*- C++ -*-
1.5 + * src/lemon/error.h - Part of LEMON, a generic C++ optimization library
1.6 + *
1.7 + * Copyright (C) 2004 Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
1.8 + * (Egervary Combinatorial Optimization Research Group, EGRES).
1.9 + *
1.10 + * Permission to use, modify and distribute this software is granted
1.11 + * provided that this copyright notice appears in all copies. For
1.12 + * precise terms see the accompanying LICENSE file.
1.13 + *
1.14 + * This software is provided "AS IS" with no warranty of any kind,
1.15 + * express or implied, and with no claim as to its suitability for any
1.16 + * purpose.
1.17 + *
1.18 + */
1.19 +
1.20 +#ifndef LEMON_ERROR_H
1.21 +#define LEMON_ERROR_H
1.22 +
1.23 +//! \ingroup misc
1.24 +//! \file
1.25 +//! \brief Basic exception classes and error handling.
1.26 +
1.27 +#include <exception>
1.28 +#include <string>
1.29 +#include <sstream>
1.30 +#include <iostream>
1.31 +#include <cstdlib>
1.32 +
1.33 +#include <boost/shared_ptr.hpp>
1.34 +
1.35 +namespace lemon {
1.36 +
1.37 + /// Exception-safe convenient "error message" class.
1.38 +
1.39 + /// Helper class which provides a convenient ostream-like (operator <<
1.40 + /// based) interface to create a string message. Mostly useful in
1.41 + /// exception classes (therefore the name).
1.42 + class ErrorMessage {
1.43 + protected:
1.44 + ///\e
1.45 + boost::shared_ptr<std::ostringstream> buf;
1.46 +
1.47 + ///\e
1.48 + bool init() throw() {
1.49 + try {
1.50 + buf.reset(new std::ostringstream);
1.51 + }
1.52 + catch(...) {
1.53 + buf.reset();
1.54 + }
1.55 + return buf;
1.56 + }
1.57 +
1.58 + public:
1.59 +
1.60 + ///\e
1.61 + ErrorMessage() throw() { init(); }
1.62 +
1.63 + ///\e
1.64 + ErrorMessage(const char *message) throw() {
1.65 + init();
1.66 + *this << message;
1.67 + }
1.68 +
1.69 + ///\e
1.70 + ErrorMessage(const std::string &message) throw() {
1.71 + init();
1.72 + *this << message;
1.73 + }
1.74 +
1.75 + ///\e
1.76 + template <typename T>
1.77 + ErrorMessage& operator<<(const T &t) throw() {
1.78 + if( !buf ) return *this;
1.79 +
1.80 + try {
1.81 + *buf << t;
1.82 + }
1.83 + catch(...) {
1.84 + buf.reset();
1.85 + }
1.86 + }
1.87 +
1.88 + ///\e
1.89 + const char* message() throw() {
1.90 + if( !buf ) return 0;
1.91 +
1.92 + const char* mes = 0;
1.93 + try {
1.94 + mes = buf->str().c_str();
1.95 + }
1.96 + catch(...) {}
1.97 + return mes;
1.98 + }
1.99 +
1.100 + };
1.101 +
1.102 + /**
1.103 + * \brief Generic exception class.
1.104 + *
1.105 + * Base class for exceptions used in LEMON.
1.106 + */
1.107 + class Exception : public std::exception {
1.108 + public:
1.109 + ///\e
1.110 + Exception() {}
1.111 + ///\e
1.112 + virtual ~Exception() throw() {}
1.113 +
1.114 + ///\e
1.115 + virtual const char* exceptionName() const {
1.116 + return "lemon::Exception";
1.117 + }
1.118 +
1.119 + ///\e
1.120 + virtual const char* what() const throw() {
1.121 + return exceptionName();
1.122 + }
1.123 + };
1.124 +
1.125 + /**
1.126 + * \brief One of the two main subclasses of \ref Exception.
1.127 + *
1.128 + * Logic errors represent problems in the internal logic of a program;
1.129 + * in theory, these are preventable, and even detectable before the
1.130 + * program runs (e.g., violations of class invariants).
1.131 + *
1.132 + * For a typical example \see UninitializedParameterError.
1.133 + */
1.134 + class LogicError : public Exception {
1.135 + public:
1.136 + virtual const char* exceptionName() const {
1.137 + return "lemon::LogicError";
1.138 + }
1.139 + };
1.140 +
1.141 +
1.142 + /**
1.143 + * \brief One of the two main subclasses of \ref Exception.
1.144 + *
1.145 + * Runtime errors represent problems outside the scope of a program;
1.146 + * they cannot be easily predicted and can generally only be caught as
1.147 + * the program executes.
1.148 + */
1.149 + class RuntimeError : public Exception {
1.150 + public:
1.151 + virtual const char* exceptionName() const {
1.152 + return "lemon::RuntimeError";
1.153 + }
1.154 + };
1.155 +
1.156 + ///\e
1.157 + class RangeError : public RuntimeError {
1.158 + public:
1.159 + virtual const char* exceptionName() const {
1.160 + return "lemon::RangeError";
1.161 + }
1.162 + };
1.163 +
1.164 + ///\e
1.165 + class IOError : public RuntimeError {
1.166 + public:
1.167 + virtual const char* exceptionName() const {
1.168 + return "lemon::IOError";
1.169 + }
1.170 + };
1.171 +
1.172 + ///\e
1.173 + class DataFormatError : public IOError {
1.174 + protected:
1.175 + const char *_message;
1.176 + int _line;
1.177 + boost::shared_ptr<std::string> _file;
1.178 +
1.179 + public:
1.180 + ///\e
1.181 + explicit DataFormatError(const char *the_message)
1.182 + : _message(the_message), _line(0) {}
1.183 + ///\e
1.184 + DataFormatError(const std::string &file_name, int line_num,
1.185 + const char *the_message)
1.186 + : _message(the_message), _line(line_num) { file(file_name); }
1.187 +
1.188 + ///\e
1.189 + void line(int line_num) { _line=line_num; }
1.190 + ///\e
1.191 + void message(char *the_message) { _message=the_message; }
1.192 + ///\e
1.193 + void file(const std::string &file_name) {
1.194 + try {
1.195 + _file.reset(new std::string);
1.196 + *_file = file_name;
1.197 + }
1.198 + catch(...) {
1.199 + _file.reset();
1.200 + }
1.201 + }
1.202 +
1.203 + ///\e
1.204 + int line() const { return _line; }
1.205 + ///\e
1.206 + const char* message() const { return _message; }
1.207 +
1.208 + /// \brief Returns the filename.
1.209 + ///
1.210 + /// Returns \e "(unknown)" if the filename was not specified.
1.211 + const char* file() const {
1.212 + if( _file )
1.213 + return _file->c_str();
1.214 + else
1.215 + return "(unknown)";
1.216 + }
1.217 +
1.218 + ///\e
1.219 + virtual const char* what() const throw() {
1.220 + const char *mes = 0;
1.221 + try {
1.222 + std::ostringstream ostr;
1.223 + ostr << _message;
1.224 + if( _file || _line ) {
1.225 + ostr << " (";
1.226 + if( _file ) ostr << "in file '" << *_file << "'";
1.227 + if( _file && _line ) ostr << " ";
1.228 + if( _line ) ostr << "at line " << _line;
1.229 + ostr << ")";
1.230 + }
1.231 + mes = ostr.str().c_str();
1.232 + }
1.233 + catch(...) {}
1.234 + if( mes ) return mes;
1.235 + return exceptionName();
1.236 + }
1.237 +
1.238 + virtual const char* exceptionName() const {
1.239 + return "lemon::DataFormatError";
1.240 + }
1.241 +
1.242 + virtual ~DataFormatError() throw() {}
1.243 + };
1.244 +
1.245 +
1.246 + ///\e
1.247 + class AssertionFailedError : public LogicError {
1.248 + protected:
1.249 + const char *assertion;
1.250 + const char *file;
1.251 + int line;
1.252 + const char *function;
1.253 + const char *message;
1.254 + public:
1.255 + ///\e
1.256 + AssertionFailedError(const char *_file, int _line, const char *func,
1.257 + const char *msg, const char *_assertion = 0) :
1.258 + assertion(_assertion), file(_file), line(_line), function(func),
1.259 + message(msg) {}
1.260 +
1.261 + ///\e
1.262 + const char* get_assertion() const { return assertion; }
1.263 + ///\e
1.264 + const char* get_message() const { return message; }
1.265 + ///\e
1.266 + const char* get_file() const { return file; }
1.267 + ///\e
1.268 + const char* get_function() const { return function; }
1.269 + ///\e
1.270 + int get_line() const { return line; }
1.271 +
1.272 +
1.273 + virtual const char* what() const throw() {
1.274 + const char *mes = 0;
1.275 + try {
1.276 + std::ostringstream ostr;
1.277 + ostr << file << ":" << line << ": ";
1.278 + if( function )
1.279 + ostr << function << ": ";
1.280 + ostr << message;
1.281 + if( assertion )
1.282 + ostr << " (assertion '" << assertion << "' failed)";
1.283 + mes = ostr.str().c_str();
1.284 + }
1.285 + catch(...) {}
1.286 + if( mes ) return mes;
1.287 + return exceptionName();
1.288 + }
1.289 +
1.290 + virtual const char* exceptionName() const {
1.291 + return "lemon::AssertionFailedError";
1.292 + }
1.293 +
1.294 + virtual ~AssertionFailedError() throw() {}
1.295 + };
1.296 +
1.297 +
1.298 + /**************** Macros ****************/
1.299 +
1.300 +
1.301 + inline
1.302 + void assert_fail(const char *file, int line, const char *func,
1.303 + const char *message, const char *assertion = 0,
1.304 + bool do_abort=true)
1.305 + {
1.306 + using namespace std;
1.307 + cerr << file << ":" << line << ": ";
1.308 + if( func )
1.309 + cerr << func << ": ";
1.310 + cerr << message;
1.311 + if( assertion )
1.312 + cerr << " (assertion '" << assertion << "' failed)";
1.313 + cerr << endl;
1.314 + if(do_abort)
1.315 + abort();
1.316 + }
1.317 +
1.318 + inline
1.319 + void assert_fail_throw(const char *file, int line, const char *func,
1.320 + const char *message, const char *assertion = 0,
1.321 + bool = true)
1.322 + {
1.323 + throw AssertionFailedError(file, line, func, message, assertion);
1.324 + }
1.325 +
1.326 +
1.327 +}
1.328 +#endif // LEMON_ERROR_H
1.329 +
1.330 +#undef LEMON_ASSERT
1.331 +#undef LEMON_FIXME
1.332 +
1.333 +#ifndef LEMON_ASSERT_ABORT
1.334 +# define LEMON_ASSERT_ABORT 1
1.335 +#endif
1.336 +
1.337 +#ifndef LEMON_ASSERT_HANDLER
1.338 +# ifdef LEMON_ASSERT_EXCEPTION
1.339 +# define LEMON_ASSERT_HANDLER ::lemon::assert_fail_throw
1.340 +# else
1.341 +# define LEMON_ASSERT_HANDLER ::lemon::assert_fail
1.342 +# endif
1.343 +#endif
1.344 +
1.345 +#if defined(NDEBUG) || defined(LEMON_DISABLE_ASSERTS)
1.346 +
1.347 +# define LEMON_ASSERT(exp, msg) (static_cast<void> (0))
1.348 +
1.349 +#else
1.350 +
1.351 +/**
1.352 + * \brief Macro for assertions with customizable message
1.353 + *
1.354 + * Macro for assertions with customizable message.
1.355 + *
1.356 + * The behaviour can be customized with LEMON_ASSERT_HANDLER,
1.357 + * LEMON_ASSERT_EXCEPTION and LEMON_ASSERT_ABORT defines. Asserts can be
1.358 + * disabled by defining either NDEBUG or LEMON_DISABLE_ASSERTS macros.
1.359 + *
1.360 + * \todo We should provide some way to reset to the default behaviour,
1.361 + * shouldn't we?
1.362 + *
1.363 + * \todo This whole 'assert' business should be placed in a separate
1.364 + * include file.
1.365 + *
1.366 + * \todo __PRETTY_FUNCTION__ should be replaced by something
1.367 + * compiler-independant, like BOOST_CURRENT_FUNCTION
1.368 + */
1.369 +
1.370 +# define LEMON_ASSERT(exp, msg) \
1.371 + (static_cast<void> (!!(exp) ? 0 : ( \
1.372 + LEMON_ASSERT_HANDLER(__FILE__, __LINE__, \
1.373 + __PRETTY_FUNCTION__, \
1.374 + (msg), #exp, LEMON_ASSERT_ABORT), 0)))
1.375 +
1.376 +#endif // NDEBUG || LEMON_DISABLE_ASSERTS
1.377 +
1.378 +/**
1.379 + * \brief Macro for mark not yet implemented features.
1.380 + *
1.381 + * \todo Is this the right place for this? It should be used only in
1.382 + * modules under development.
1.383 + *
1.384 + * \todo __PRETTY_FUNCTION__ should be replaced by something
1.385 + * compiler-independant, like BOOST_CURRENT_FUNCTION
1.386 + */
1.387 +
1.388 +# define LEMON_FIXME(msg) \
1.389 + (LEMON_ASSERT_HANDLER(__FILE__, __LINE__, __PRETTY_FUNCTION__, \
1.390 + "FIXME: " msg))