src/work/klao/error.h
changeset 1067 47939f501c81
parent 1061 e3433c024123
child 1068 e0b0dcee5e17
     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))