1.1 --- a/src/work/klao/error.h Sun Jan 09 23:21:52 2005 +0000
1.2 +++ b/src/work/klao/error.h Sun Jan 09 23:28:18 2005 +0000
1.3 @@ -19,23 +19,29 @@
1.4
1.5 //! \ingroup misc
1.6 //! \file
1.7 -//! \brief Basic error handling (signaling) routines.
1.8 +//! \brief Basic exception classes and error handling.
1.9
1.10 #include <exception>
1.11 #include <string>
1.12 #include <sstream>
1.13 +#include <iostream>
1.14 +#include <cstdlib>
1.15
1.16 #include <boost/shared_ptr.hpp>
1.17
1.18 namespace lemon {
1.19
1.20 /// Exception-safe convenient "error message" class.
1.21 +
1.22 + /// Helper class which provides a convenient ostream-like (operator <<
1.23 + /// based) interface to create a string message. Mostly useful in
1.24 + /// exception classes (therefore the name).
1.25 class ErrorMessage {
1.26 protected:
1.27 - ///\e
1.28 + ///\e
1.29 boost::shared_ptr<std::ostringstream> buf;
1.30
1.31 - ///\e
1.32 + ///\e
1.33 bool init() throw() {
1.34 try {
1.35 buf.reset(new std::ostringstream);
1.36 @@ -48,22 +54,22 @@
1.37
1.38 public:
1.39
1.40 - ///\e
1.41 + ///\e
1.42 ErrorMessage() throw() { init(); }
1.43
1.44 - ///\e
1.45 + ///\e
1.46 ErrorMessage(const char *message) throw() {
1.47 init();
1.48 *this << message;
1.49 }
1.50
1.51 - ///\e
1.52 + ///\e
1.53 ErrorMessage(const std::string &message) throw() {
1.54 init();
1.55 *this << message;
1.56 }
1.57
1.58 - ///\e
1.59 + ///\e
1.60 template <typename T>
1.61 ErrorMessage& operator<<(const T &t) throw() {
1.62 if( !buf ) return *this;
1.63 @@ -76,7 +82,7 @@
1.64 }
1.65 }
1.66
1.67 - ///\e
1.68 + ///\e
1.69 const char* message() throw() {
1.70 if( !buf ) return 0;
1.71
1.72 @@ -95,65 +101,81 @@
1.73 *
1.74 * Base class for exceptions used in LEMON.
1.75 */
1.76 - class Exception : public std::exception, public ErrorMessage {
1.77 + class Exception : public std::exception {
1.78 + protected:
1.79 + ///\e
1.80 + const char *message;
1.81 +
1.82 public:
1.83 - ///\e
1.84 - Exception() throw() {}
1.85 - ///\e
1.86 - explicit Exception(const std::string &s) throw()
1.87 - : ErrorMessage(s) {}
1.88 - ///\e
1.89 + ///\e
1.90 + Exception() throw() : message(0) {}
1.91 + ///\e
1.92 + explicit Exception(const char *msg) throw()
1.93 + : message(msg) {}
1.94 + ///\e
1.95 virtual ~Exception() throw() {}
1.96
1.97 - ///\e
1.98 + ///\e
1.99 virtual const char* what() const throw() {
1.100 - const char *mes = message();
1.101 - if( mes ) return mes;
1.102 + if( message ) return message;
1.103 return "lemon::Exception";
1.104 }
1.105 };
1.106
1.107 ///\e
1.108 class LogicError : public Exception {
1.109 - ///\e
1.110 - explicit LogicError(const std::string &s)
1.111 + public:
1.112 + ///\e
1.113 + explicit LogicError() {}
1.114 + ///\e
1.115 + explicit LogicError(const char *s)
1.116 : Exception(s) {}
1.117 };
1.118
1.119 ///\e
1.120 class RuntimeError : public Exception {
1.121 - ///\e
1.122 - explicit RuntimeError(const std::string &s)
1.123 + public:
1.124 + ///\e
1.125 + explicit RuntimeError() {}
1.126 + ///\e
1.127 + explicit RuntimeError(const char *s)
1.128 : Exception(s) {}
1.129 };
1.130
1.131 - ///\e
1.132 + ///\e
1.133 class RangeError : public RuntimeError {
1.134 - ///\e
1.135 - explicit RangeError(const std::string &s)
1.136 + public:
1.137 + ///\e
1.138 + explicit RangeError(const char *s)
1.139 : RuntimeError(s) {}
1.140 };
1.141
1.142 ///\e
1.143 class IOError : public RuntimeError {
1.144 - ///\e
1.145 - explicit IOError(const std::string &s)
1.146 + public:
1.147 + ///\e
1.148 + explicit IOError(const char *s)
1.149 : RuntimeError(s) {}
1.150 };
1.151
1.152 ///\e
1.153 class DataFormatError : public IOError {
1.154 - ///\e
1.155 - explicit DataFormatError(const std::string &message)
1.156 - : IOError(message) : line(0) {}
1.157 - ///\e
1.158 + protected:
1.159 + int line;
1.160 + boost::shared_ptr<std::string> file;
1.161 +
1.162 + public:
1.163 + ///\e
1.164 + explicit DataFormatError(const char *message)
1.165 + : IOError(message), line(0) {}
1.166 + ///\e
1.167 DataFormatError(const std::string &file_name, int line_num,
1.168 - const std::string &message)
1.169 + const char *message)
1.170 : IOError(message), line(line_num) { set_file(file_name); }
1.171
1.172 - ///\e
1.173 + ///\e
1.174 void set_line(int line_num) { line=line_num; }
1.175 - ///\e
1.176 + ///\e
1.177 void set_file(const std::string &file_name) {
1.178 try {
1.179 file.reset(new std::string);
1.180 @@ -164,16 +186,31 @@
1.181 }
1.182 }
1.183
1.184 - ///\e
1.185 - virtual const char* what() const {
1.186 + ///\e
1.187 + int get_line() const { return line; }
1.188 +
1.189 + /// \brief Returns the filename.
1.190 + ///
1.191 + /// Returns "(unknown)" if the filename was not specified.
1.192 + const char* get_file() const {
1.193 + if( file )
1.194 + return file->c_str();
1.195 + else
1.196 + return "(unknown)";
1.197 + }
1.198 +
1.199 + ///\e
1.200 + virtual const char* what() const throw() {
1.201 const char *mes = 0;
1.202 try {
1.203 std::ostringstream ostr;
1.204 ostr << IOError::what();
1.205 if( file || line ) {
1.206 ostr << " (";
1.207 - if( file ) ostr << "in file" << *file;
1.208 - if( line ) ostr << " at line" << line;
1.209 + if( file ) ostr << "in file '" << *file << "'";
1.210 + if( file && line ) ostr << " ";
1.211 + if( line ) ostr << "at line " << line;
1.212 + ostr << ")";
1.213 }
1.214 mes = ostr.str().c_str();
1.215 }
1.216 @@ -181,32 +218,132 @@
1.217 if( mes ) return mes;
1.218 return "lemon::DataFormatError";
1.219 }
1.220 +
1.221 + virtual ~DataFormatError() throw() {}
1.222 };
1.223
1.224
1.225 + class AssertionFailedError : public LogicError {
1.226 + protected:
1.227 + const char *assertion;
1.228 + const char *file;
1.229 + int line;
1.230 + const char *function;
1.231 + const char *message;
1.232 + public:
1.233 + ///\e
1.234 + AssertionFailedError(const char *_file, int _line, const char *func,
1.235 + const char *msg, const char *_assertion = 0) :
1.236 + assertion(_assertion), file(_file), line(_line), function(func),
1.237 + message(msg) {}
1.238 +
1.239 + ///\e
1.240 + const char* get_assertion() const { return assertion; }
1.241 + ///\e
1.242 + const char* get_message() const { return message; }
1.243 + ///\e
1.244 + const char* get_file() const { return file; }
1.245 + ///\e
1.246 + const char* get_function() const { return function; }
1.247 + ///\e
1.248 + int get_line() const { return line; }
1.249 +
1.250 +
1.251 + virtual const char* what() const throw() {
1.252 + const char *mes = 0;
1.253 + try {
1.254 + std::ostringstream ostr;
1.255 + ostr << file << ":" << line << ": ";
1.256 + if( function )
1.257 + ostr << function << ": ";
1.258 + ostr << message;
1.259 + if( assertion )
1.260 + ostr << " (assertion '" << assertion << "' failed)";
1.261 + mes = ostr.str().c_str();
1.262 + }
1.263 + catch(...) {}
1.264 + if( mes ) return mes;
1.265 + return "lemon::AssertionFailedError";
1.266 + }
1.267 +
1.268 + virtual ~AssertionFailedError() throw() {}
1.269 + };
1.270 +
1.271
1.272 /**************** Macros ****************/
1.273
1.274
1.275 - /**
1.276 - * \brief Macro for assertions with customizable message
1.277 - */
1.278 + inline
1.279 + void assert_fail(const char *file, int line, const char *func,
1.280 + const char *message, const char *assertion = 0,
1.281 + bool do_abort=true)
1.282 + {
1.283 + using namespace std;
1.284 + cerr << file << ":" << line << ": ";
1.285 + if( func )
1.286 + cerr << func << ": ";
1.287 + cerr << message;
1.288 + if( assertion )
1.289 + cerr << " (assertion '" << assertion << "' failed)";
1.290 + cerr << endl;
1.291 + if(do_abort)
1.292 + abort();
1.293 + }
1.294
1.295 -# define lemon_assert(exp, msg) \
1.296 - if(!(exp)) { \
1.297 - std::cerr << __FILE__ ":" << __LINE__ << ": " << (msg) << std::endl; \
1.298 - abort; \
1.299 - }
1.300 + inline
1.301 + void assert_fail_throw(const char *file, int line, const char *func,
1.302 + const char *message, const char *assertion = 0,
1.303 + bool = true)
1.304 + {
1.305 + throw AssertionFailedError(file, line, func, message, assertion);
1.306 + }
1.307
1.308
1.309 - /**
1.310 - * \brief Macro for mark not yet implemented features.
1.311 - *
1.312 - * \todo Is this the right place for this? It should be used only in
1.313 - * modules under development.
1.314 - */
1.315 -
1.316 -# define FIXME(msg) lemon_assert(0, "FIXME: " msg)
1.317 -
1.318 }
1.319 #endif // LEMON_ERROR_H
1.320 +
1.321 +#undef LEMON_ASSERT
1.322 +#undef LEMON_FIXME
1.323 +
1.324 +#ifndef LEMON_ASSERT_ABORT
1.325 +# define LEMON_ASSERT_ABORT 1
1.326 +#endif
1.327 +
1.328 +#ifndef LEMON_ASSERT_HANDLER
1.329 +# define LEMON_ASSERT_HANDLER ::lemon::assert_fail
1.330 +#endif
1.331 +
1.332 +#if defined(NDEBUG) || defined(LEMON_DISABLE_ASSERTS)
1.333 +
1.334 +# define LEMON_ASSERT(exp, msg) (static_cast<void> (0))
1.335 +
1.336 +#else
1.337 +
1.338 +/**
1.339 + * \brief Macro for assertions with customizable message
1.340 + *
1.341 + * \todo __PRETTY_FUNCTION__ should be replaced by something
1.342 + * compiler-independant, like BOOST_CURRENT_FUNCTION
1.343 + */
1.344 +
1.345 +# define LEMON_ASSERT(exp, msg) \
1.346 + (static_cast<void> (!!(exp) ? 0 : ( \
1.347 + LEMON_ASSERT_HANDLER(__FILE__, __LINE__, \
1.348 + __PRETTY_FUNCTION__, \
1.349 + (msg), #exp, LEMON_ASSERT_ABORT), 0)))
1.350 +
1.351 +# endif // NDEBUG
1.352 +
1.353 +/**
1.354 + * \brief Macro for mark not yet implemented features.
1.355 + *
1.356 + * \todo Is this the right place for this? It should be used only in
1.357 + * modules under development.
1.358 + *
1.359 + * \todo __PRETTY_FUNCTION__ should be replaced by something
1.360 + * compiler-independant, like BOOST_CURRENT_FUNCTION
1.361 + */
1.362 +
1.363 +# define LEMON_FIXME(msg) \
1.364 + (LEMON_ASSERT_HANDLER(__FILE__, __LINE__, __PRETTY_FUNCTION__, \
1.365 + "FIXME: " msg))