Advances in error.h
authorklao
Sun, 09 Jan 2005 23:28:18 +0000
changeset 106747939f501c81
parent 1066 520769d825f2
child 1068 e0b0dcee5e17
Advances in error.h

* More clear exception usage concept
* sketch of LEMON_ASSERT interface
* test file
src/work/klao/Makefile
src/work/klao/error.h
src/work/klao/error_test.cc
src/work/makefile
     1.1 --- a/src/work/klao/Makefile	Sun Jan 09 23:21:52 2005 +0000
     1.2 +++ b/src/work/klao/Makefile	Sun Jan 09 23:28:18 2005 +0000
     1.3 @@ -1,4 +1,5 @@
     1.4 -BINARIES = tag_demo
     1.5 +BINARIES = error_test
     1.6  INCLUDEDIRS= -I. -I.. -I../.. -I../{marci,jacint,alpar,johanna,athos,akos} -I$(HOME)/boost
     1.7  include ../makefile
     1.8  
     1.9 +CXXFLAGS += $(C)
     2.1 --- a/src/work/klao/error.h	Sun Jan 09 23:21:52 2005 +0000
     2.2 +++ b/src/work/klao/error.h	Sun Jan 09 23:28:18 2005 +0000
     2.3 @@ -19,23 +19,29 @@
     2.4  
     2.5  //! \ingroup misc
     2.6  //! \file
     2.7 -//! \brief Basic error handling (signaling) routines.
     2.8 +//! \brief Basic exception classes and error handling.
     2.9  
    2.10  #include <exception>
    2.11  #include <string>
    2.12  #include <sstream>
    2.13 +#include <iostream>
    2.14 +#include <cstdlib>
    2.15  
    2.16  #include <boost/shared_ptr.hpp>
    2.17  
    2.18  namespace lemon {
    2.19  
    2.20    /// Exception-safe convenient "error message" class.
    2.21 +
    2.22 +  /// Helper class which provides a convenient ostream-like (operator <<
    2.23 +  /// based) interface to create a string message. Mostly useful in
    2.24 +  /// exception classes (therefore the name).
    2.25    class ErrorMessage {
    2.26    protected:
    2.27 -  ///\e 
    2.28 +    ///\e 
    2.29      boost::shared_ptr<std::ostringstream> buf;
    2.30      
    2.31 -  ///\e 
    2.32 +    ///\e 
    2.33      bool init() throw() {
    2.34        try {
    2.35  	buf.reset(new std::ostringstream);
    2.36 @@ -48,22 +54,22 @@
    2.37  
    2.38    public:
    2.39  
    2.40 -  ///\e 
    2.41 +    ///\e 
    2.42      ErrorMessage() throw() { init(); }
    2.43  
    2.44 -  ///\e 
    2.45 +    ///\e 
    2.46      ErrorMessage(const char *message) throw() {
    2.47        init();
    2.48        *this << message;
    2.49      }
    2.50  
    2.51 -  ///\e 
    2.52 +    ///\e 
    2.53      ErrorMessage(const std::string &message) throw() {
    2.54        init();
    2.55        *this << message;
    2.56      }
    2.57  
    2.58 -  ///\e 
    2.59 +    ///\e 
    2.60      template <typename T>
    2.61      ErrorMessage& operator<<(const T &t) throw() {
    2.62        if( !buf ) return *this;
    2.63 @@ -76,7 +82,7 @@
    2.64        }
    2.65      }
    2.66  
    2.67 -  ///\e 
    2.68 +    ///\e 
    2.69      const char* message() throw() {
    2.70        if( !buf ) return 0;
    2.71  
    2.72 @@ -95,65 +101,81 @@
    2.73     *
    2.74     * Base class for exceptions used in LEMON.
    2.75     */
    2.76 -  class Exception : public std::exception, public ErrorMessage {
    2.77 +  class Exception : public std::exception {
    2.78 +  protected:
    2.79 +    ///\e
    2.80 +    const char *message;
    2.81 +
    2.82    public:
    2.83 -  ///\e 
    2.84 -    Exception() throw() {}
    2.85 -  ///\e 
    2.86 -    explicit Exception(const std::string &s) throw()
    2.87 -      : ErrorMessage(s) {}
    2.88 -  ///\e 
    2.89 +    ///\e 
    2.90 +    Exception() throw() : message(0) {}
    2.91 +    ///\e 
    2.92 +    explicit Exception(const char *msg) throw()
    2.93 +      : message(msg) {}
    2.94 +    ///\e 
    2.95      virtual ~Exception() throw() {}
    2.96      
    2.97 -  ///\e 
    2.98 +    ///\e 
    2.99      virtual const char* what() const throw() {
   2.100 -      const char *mes = message();
   2.101 -      if( mes ) return mes;
   2.102 +      if( message ) return message;
   2.103        return "lemon::Exception";
   2.104      }
   2.105    };
   2.106  
   2.107    ///\e 
   2.108    class LogicError : public Exception {
   2.109 -  ///\e 
   2.110 -    explicit LogicError(const std::string &s)
   2.111 +  public:
   2.112 +    ///\e 
   2.113 +    explicit LogicError() {}
   2.114 +    ///\e 
   2.115 +    explicit LogicError(const char *s)
   2.116        : Exception(s) {}
   2.117    };
   2.118  
   2.119    ///\e 
   2.120    class RuntimeError : public Exception {
   2.121 -  ///\e 
   2.122 -    explicit RuntimeError(const std::string &s)
   2.123 +  public:
   2.124 +    ///\e
   2.125 +    explicit RuntimeError() {}
   2.126 +    ///\e
   2.127 +    explicit RuntimeError(const char *s)
   2.128        : Exception(s) {}
   2.129    };
   2.130  
   2.131 -  ///\e 
   2.132 +  ///\e
   2.133    class RangeError : public RuntimeError {
   2.134 -  ///\e 
   2.135 -    explicit RangeError(const std::string &s)
   2.136 +  public:
   2.137 +    ///\e 
   2.138 +    explicit RangeError(const char *s)
   2.139        : RuntimeError(s) {}
   2.140    };
   2.141  
   2.142    ///\e 
   2.143    class IOError : public RuntimeError {
   2.144 -  ///\e 
   2.145 -    explicit IOError(const std::string &s)
   2.146 +  public:
   2.147 +    ///\e 
   2.148 +    explicit IOError(const char *s)
   2.149        : RuntimeError(s) {}
   2.150    };
   2.151  
   2.152    ///\e 
   2.153    class DataFormatError : public IOError {
   2.154 -  ///\e 
   2.155 -    explicit DataFormatError(const std::string &message)
   2.156 -      : IOError(message) : line(0) {}
   2.157 -  ///\e 
   2.158 +  protected:
   2.159 +    int line;
   2.160 +    boost::shared_ptr<std::string> file;
   2.161 +
   2.162 +  public:
   2.163 +    ///\e 
   2.164 +    explicit DataFormatError(const char *message)
   2.165 +      : IOError(message), line(0) {}
   2.166 +    ///\e 
   2.167      DataFormatError(const std::string &file_name, int line_num,
   2.168 -		    const std::string &message)
   2.169 +		    const char *message)
   2.170        : IOError(message), line(line_num) { set_file(file_name); }
   2.171  
   2.172 -  ///\e 
   2.173 +    ///\e 
   2.174      void set_line(int line_num) { line=line_num; }
   2.175 -  ///\e 
   2.176 +    ///\e 
   2.177      void set_file(const std::string &file_name) {
   2.178        try {
   2.179  	file.reset(new std::string);
   2.180 @@ -164,16 +186,31 @@
   2.181        }
   2.182      }
   2.183  
   2.184 -  ///\e 
   2.185 -    virtual const char* what() const {
   2.186 +    ///\e
   2.187 +    int get_line() const { return line; }
   2.188 +
   2.189 +    /// \brief Returns the filename.
   2.190 +    ///
   2.191 +    /// Returns "(unknown)" if the filename was not specified.
   2.192 +    const char* get_file() const {
   2.193 +      if( file )
   2.194 +	return file->c_str();
   2.195 +      else
   2.196 +	return "(unknown)";
   2.197 +    }
   2.198 +
   2.199 +    ///\e 
   2.200 +    virtual const char* what() const throw() {
   2.201        const char *mes = 0;
   2.202        try {
   2.203  	std::ostringstream ostr;
   2.204  	ostr << IOError::what();
   2.205  	if( file || line ) {
   2.206  	  ostr << " (";
   2.207 -	  if( file ) ostr << "in file" << *file;
   2.208 -	  if( line ) ostr << " at line" << line;
   2.209 +	  if( file ) ostr << "in file '" << *file << "'";
   2.210 +	  if( file && line ) ostr << " ";
   2.211 +	  if( line ) ostr << "at line " << line;
   2.212 +	  ostr << ")";
   2.213  	}
   2.214  	mes = ostr.str().c_str();
   2.215        }
   2.216 @@ -181,32 +218,132 @@
   2.217        if( mes ) return mes;
   2.218        return "lemon::DataFormatError";
   2.219      }
   2.220 +
   2.221 +    virtual ~DataFormatError() throw() {}
   2.222    };
   2.223  
   2.224  
   2.225 +  class AssertionFailedError : public LogicError {
   2.226 +  protected:
   2.227 +    const char *assertion;
   2.228 +    const char *file;
   2.229 +    int line;
   2.230 +    const char *function;
   2.231 +    const char *message;
   2.232 +  public:
   2.233 +    ///\e
   2.234 +    AssertionFailedError(const char *_file, int _line, const char *func,
   2.235 +			 const char *msg, const char *_assertion = 0) :
   2.236 +      assertion(_assertion), file(_file), line(_line), function(func),
   2.237 +      message(msg) {}
   2.238 +
   2.239 +    ///\e
   2.240 +    const char* get_assertion() const { return assertion; }
   2.241 +    ///\e
   2.242 +    const char* get_message() const { return message; }
   2.243 +    ///\e
   2.244 +    const char* get_file() const { return file; }
   2.245 +    ///\e
   2.246 +    const char* get_function() const { return function; }
   2.247 +    ///\e
   2.248 +    int get_line() const { return line; }
   2.249 +
   2.250 +
   2.251 +    virtual const char* what() const throw() {
   2.252 +      const char *mes = 0;
   2.253 +      try {
   2.254 +	std::ostringstream ostr;
   2.255 +	ostr << file << ":" << line << ": ";
   2.256 +	if( function )
   2.257 +	  ostr << function << ": ";
   2.258 +	ostr << message;
   2.259 +	if( assertion )
   2.260 +	  ostr << " (assertion '" << assertion << "' failed)";
   2.261 +	mes = ostr.str().c_str();
   2.262 +      }
   2.263 +      catch(...) {}
   2.264 +      if( mes ) return mes;
   2.265 +      return "lemon::AssertionFailedError";
   2.266 +    }
   2.267 +
   2.268 +    virtual ~AssertionFailedError() throw() {}
   2.269 +  };
   2.270 +
   2.271  
   2.272    /****************  Macros  ****************/
   2.273  
   2.274  
   2.275 -  /**
   2.276 -   * \brief Macro for assertions with customizable message
   2.277 -   */
   2.278 +  inline
   2.279 +  void assert_fail(const char *file, int line, const char *func,
   2.280 +		   const char *message, const char *assertion = 0,
   2.281 +		   bool do_abort=true)
   2.282 +  {
   2.283 +    using namespace std;
   2.284 +    cerr << file << ":" << line << ": ";
   2.285 +    if( func )
   2.286 +      cerr << func << ": ";
   2.287 +    cerr << message;
   2.288 +    if( assertion )
   2.289 +      cerr << " (assertion '" << assertion << "' failed)";
   2.290 +    cerr << endl;
   2.291 +    if(do_abort)
   2.292 +      abort();
   2.293 +  }
   2.294  
   2.295 -# define lemon_assert(exp, msg) \
   2.296 -    if(!(exp)) { \
   2.297 -      std::cerr << __FILE__ ":" << __LINE__ << ": " << (msg) << std::endl; \
   2.298 -      abort; \
   2.299 -    }
   2.300 +  inline
   2.301 +  void assert_fail_throw(const char *file, int line, const char *func,
   2.302 +		   const char *message, const char *assertion = 0,
   2.303 +		   bool = true)
   2.304 +  {
   2.305 +    throw AssertionFailedError(file, line, func, message, assertion);
   2.306 +  }
   2.307  
   2.308  
   2.309 -  /**
   2.310 -   * \brief Macro for mark not yet implemented features.
   2.311 -   *
   2.312 -   * \todo Is this the right place for this? It should be used only in
   2.313 -   * modules under development.
   2.314 -   */
   2.315 -
   2.316 -# define FIXME(msg) lemon_assert(0, "FIXME: " msg)
   2.317 -
   2.318  }
   2.319  #endif // LEMON_ERROR_H
   2.320 +
   2.321 +#undef LEMON_ASSERT
   2.322 +#undef LEMON_FIXME
   2.323 +
   2.324 +#ifndef LEMON_ASSERT_ABORT
   2.325 +#  define LEMON_ASSERT_ABORT 1
   2.326 +#endif
   2.327 +
   2.328 +#ifndef LEMON_ASSERT_HANDLER
   2.329 +#  define LEMON_ASSERT_HANDLER ::lemon::assert_fail
   2.330 +#endif
   2.331 +
   2.332 +#if defined(NDEBUG) || defined(LEMON_DISABLE_ASSERTS)
   2.333 +
   2.334 +#  define LEMON_ASSERT(exp, msg)  (static_cast<void> (0))
   2.335 +
   2.336 +#else
   2.337 +
   2.338 +/**
   2.339 + * \brief Macro for assertions with customizable message
   2.340 + *
   2.341 + * \todo __PRETTY_FUNCTION__ should be replaced by something
   2.342 + * compiler-independant, like BOOST_CURRENT_FUNCTION
   2.343 + */
   2.344 +
   2.345 +#  define LEMON_ASSERT(exp, msg)                 \
   2.346 +     (static_cast<void> (!!(exp) ? 0 : (         \
   2.347 +       LEMON_ASSERT_HANDLER(__FILE__, __LINE__,  \
   2.348 +                            __PRETTY_FUNCTION__, \
   2.349 +			    (msg), #exp, LEMON_ASSERT_ABORT), 0)))
   2.350 +
   2.351 +# endif // NDEBUG
   2.352 +
   2.353 +/**
   2.354 + * \brief Macro for mark not yet implemented features.
   2.355 + *
   2.356 + * \todo Is this the right place for this? It should be used only in
   2.357 + * modules under development.
   2.358 + *
   2.359 + * \todo __PRETTY_FUNCTION__ should be replaced by something
   2.360 + * compiler-independant, like BOOST_CURRENT_FUNCTION
   2.361 + */
   2.362 +
   2.363 +# define LEMON_FIXME(msg) \
   2.364 +    (LEMON_ASSERT_HANDLER(__FILE__, __LINE__, __PRETTY_FUNCTION__, \
   2.365 +			  "FIXME: " msg))
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/src/work/klao/error_test.cc	Sun Jan 09 23:28:18 2005 +0000
     3.3 @@ -0,0 +1,57 @@
     3.4 +#include <iostream>
     3.5 +#include <string>
     3.6 +
     3.7 +#define LEMON_ASSERT_ABORT 0
     3.8 +#include <error.h>
     3.9 +
    3.10 +using namespace std;
    3.11 +
    3.12 +void parse_line() {
    3.13 +  throw lemon::DataFormatError("Syntax error");
    3.14 +}
    3.15 +
    3.16 +void parse_file(string fn) {
    3.17 +  try {
    3.18 +    parse_line();
    3.19 +  }
    3.20 +  catch(lemon::DataFormatError &e) {
    3.21 +    e.set_file(fn);
    3.22 +    e.set_line(5);
    3.23 +    throw;
    3.24 +  }
    3.25 +}
    3.26 +
    3.27 +void fail_assert();
    3.28 +
    3.29 +int main() {
    3.30 +  try {
    3.31 +    parse_file("input.txt");
    3.32 +  }
    3.33 +  catch(exception &e) {
    3.34 +    cerr << "Exception caught: " << endl;
    3.35 +    cerr << e.what() << endl;
    3.36 +  }
    3.37 +
    3.38 +  try {
    3.39 +    fail_assert();
    3.40 +  }
    3.41 +  catch(exception &e) {
    3.42 +    cerr << "Exception caught: " << endl;
    3.43 +    cerr << e.what() << endl;
    3.44 +  }
    3.45 +
    3.46 +  // assert(1==0);
    3.47 +  LEMON_ASSERT(1==0, "Ellentmondas");
    3.48 +  LEMON_FIXME("Nincs kesz");
    3.49 +}
    3.50 +
    3.51 +#undef LEMON_ASSERT_HANDLER
    3.52 +#define LEMON_ASSERT_HANDLER ::lemon::assert_fail_throw
    3.53 +
    3.54 +#include <error.h>
    3.55 +
    3.56 +void fail_assert() {
    3.57 +  LEMON_ASSERT(2*2==5, "Marson vagyunk");
    3.58 +}
    3.59 +
    3.60 +
     4.1 --- a/src/work/makefile	Sun Jan 09 23:21:52 2005 +0000
     4.2 +++ b/src/work/makefile	Sun Jan 09 23:28:18 2005 +0000
     4.3 @@ -1,5 +1,5 @@
     4.4  INCLUDEDIRS ?= -I.. -I. -I./{marci,jacint,alpar,klao,akos}
     4.5 -CXXFLAGS = -g -O3 -W -Wall $(INCLUDEDIRS) -ansi -pedantic
     4.6 +CXXFLAGS += -g -O2 -W -Wall $(INCLUDEDIRS) -ansi -pedantic
     4.7  
     4.8  BINARIES ?= bin_heap_demo
     4.9