src/work/klao/error.h
author klao
Thu, 03 Feb 2005 19:24:42 +0000
changeset 1120 5d8d64bde9c5
parent 1068 e0b0dcee5e17
permissions -rw-r--r--
Latest LEMON exception and assert concepts
     1 /* -*- C++ -*-
     2  * src/lemon/error.h - Part of LEMON, a generic C++ optimization library
     3  *
     4  * Copyright (C) 2004 Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
     5  * (Egervary Combinatorial Optimization Research Group, EGRES).
     6  *
     7  * Permission to use, modify and distribute this software is granted
     8  * provided that this copyright notice appears in all copies. For
     9  * precise terms see the accompanying LICENSE file.
    10  *
    11  * This software is provided "AS IS" with no warranty of any kind,
    12  * express or implied, and with no claim as to its suitability for any
    13  * purpose.
    14  *
    15  */
    16 
    17 #ifndef LEMON_ERROR_H
    18 #define LEMON_ERROR_H
    19 
    20 //! \ingroup misc
    21 //! \file
    22 //! \brief Basic exception classes and error handling.
    23 
    24 #include <exception>
    25 #include <string>
    26 #include <sstream>
    27 #include <iostream>
    28 #include <cstdlib>
    29 
    30 #include <boost/shared_ptr.hpp>
    31 
    32 namespace lemon {
    33 
    34   /// Exception-safe convenient "error message" class.
    35 
    36   /// Helper class which provides a convenient ostream-like (operator <<
    37   /// based) interface to create a string message. Mostly useful in
    38   /// exception classes (therefore the name).
    39   class ErrorMessage {
    40   protected:
    41     ///\e 
    42     boost::shared_ptr<std::ostringstream> buf;
    43     
    44     ///\e 
    45     bool init() throw() {
    46       try {
    47 	buf.reset(new std::ostringstream);
    48       }
    49       catch(...) {
    50 	buf.reset();
    51       }
    52       return buf;
    53     }
    54 
    55   public:
    56 
    57     ///\e 
    58     ErrorMessage() throw() { init(); }
    59 
    60     ///\e 
    61     ErrorMessage(const char *message) throw() {
    62       init();
    63       *this << message;
    64     }
    65 
    66     ///\e 
    67     ErrorMessage(const std::string &message) throw() {
    68       init();
    69       *this << message;
    70     }
    71 
    72     ///\e 
    73     template <typename T>
    74     ErrorMessage& operator<<(const T &t) throw() {
    75       if( !buf ) return *this;
    76 
    77       try {
    78 	*buf << t;
    79       }
    80       catch(...) {
    81 	buf.reset();
    82       }
    83     }
    84 
    85     ///\e 
    86     const char* message() throw() {
    87       if( !buf ) return 0;
    88 
    89       const char* mes = 0;
    90       try {
    91 	mes = buf->str().c_str();
    92       }
    93       catch(...) {}
    94       return mes;
    95     }
    96     
    97   };
    98 
    99   /**
   100    * \brief Generic exception class.
   101    *
   102    * Base class for exceptions used in LEMON.
   103    */
   104   class Exception : public std::exception {
   105   public:
   106     ///\e 
   107     Exception() {}
   108     ///\e 
   109     virtual ~Exception() throw() {}
   110 
   111     ///\e
   112     virtual const char* exceptionName() const {
   113       return "lemon::Exception";
   114     }
   115     
   116     ///\e 
   117     virtual const char* what() const throw() {
   118       return exceptionName();
   119     }
   120   };
   121 
   122   /**
   123    * \brief One of the two main subclasses of \ref Exception.
   124    *
   125    * Logic errors represent problems in the internal logic of a program;
   126    * in theory, these are preventable, and even detectable before the
   127    * program runs (e.g., violations of class invariants).
   128    *
   129    * For a typical example \see UninitializedParameterError.
   130    */
   131   class LogicError : public Exception {
   132   public:
   133     virtual const char* exceptionName() const {
   134       return "lemon::LogicError";
   135     }
   136   };
   137 
   138   
   139   /**
   140    * \brief One of the two main subclasses of \ref Exception.
   141    *
   142    * Runtime errors represent problems outside the scope of a program;
   143    * they cannot be easily predicted and can generally only be caught as
   144    * the program executes.
   145    */
   146   class RuntimeError : public Exception {
   147   public:
   148     virtual const char* exceptionName() const {
   149       return "lemon::RuntimeError";
   150     }
   151   };
   152 
   153   ///\e
   154   class RangeError : public RuntimeError {
   155   public:
   156     virtual const char* exceptionName() const {
   157       return "lemon::RangeError";
   158     }
   159   };
   160 
   161   ///\e 
   162   class IOError : public RuntimeError {
   163   public:
   164     virtual const char* exceptionName() const {
   165       return "lemon::IOError";
   166     }
   167   };
   168 
   169   ///\e 
   170   class DataFormatError : public IOError {
   171   protected:
   172     const char *_message;
   173     int _line;
   174     boost::shared_ptr<std::string> _file;
   175 
   176   public:
   177     ///\e 
   178     explicit DataFormatError(const char *the_message)
   179       : _message(the_message), _line(0) {}
   180     ///\e 
   181     DataFormatError(const std::string &file_name, int line_num,
   182 		    const char *the_message)
   183       : _message(the_message), _line(line_num) { file(file_name); }
   184 
   185     ///\e 
   186     void line(int line_num) { _line=line_num; }
   187     ///\e 
   188     void message(char *the_message) { _message=the_message; }
   189     ///\e 
   190     void file(const std::string &file_name) {
   191       try {
   192 	_file.reset(new std::string);
   193 	*_file = file_name;
   194       }
   195       catch(...) {
   196 	_file.reset();
   197       }
   198     }
   199 
   200     ///\e
   201     int line() const { return _line; }
   202     ///\e
   203     const char* message() const { return _message; }
   204 
   205     /// \brief Returns the filename.
   206     ///
   207     /// Returns \e "(unknown)" if the filename was not specified.
   208     const char* file() const {
   209       if( _file )
   210 	return _file->c_str();
   211       else
   212 	return "(unknown)";
   213     }
   214 
   215     ///\e 
   216     virtual const char* what() const throw() {
   217       const char *mes = 0;
   218       try {
   219 	std::ostringstream ostr;
   220 	ostr << _message;
   221 	if( _file || _line ) {
   222 	  ostr << " (";
   223 	  if( _file ) ostr << "in file '" << *_file << "'";
   224 	  if( _file && _line ) ostr << " ";
   225 	  if( _line ) ostr << "at line " << _line;
   226 	  ostr << ")";
   227 	}
   228 	mes = ostr.str().c_str();
   229       }
   230       catch(...) {}
   231       if( mes ) return mes;
   232       return exceptionName();
   233     }
   234 
   235     virtual const char* exceptionName() const {
   236       return "lemon::DataFormatError";
   237     }
   238 
   239     virtual ~DataFormatError() throw() {}
   240   };
   241 
   242 
   243   ///\e
   244   class AssertionFailedError : public LogicError {
   245   protected:
   246     const char *assertion;
   247     const char *file;
   248     int line;
   249     const char *function;
   250     const char *message;
   251   public:
   252     ///\e
   253     AssertionFailedError(const char *_file, int _line, const char *func,
   254 			 const char *msg, const char *_assertion = 0) :
   255       assertion(_assertion), file(_file), line(_line), function(func),
   256       message(msg) {}
   257 
   258     ///\e
   259     const char* get_assertion() const { return assertion; }
   260     ///\e
   261     const char* get_message() const { return message; }
   262     ///\e
   263     const char* get_file() const { return file; }
   264     ///\e
   265     const char* get_function() const { return function; }
   266     ///\e
   267     int get_line() const { return line; }
   268 
   269 
   270     virtual const char* what() const throw() {
   271       const char *mes = 0;
   272       try {
   273 	std::ostringstream ostr;
   274 	ostr << file << ":" << line << ": ";
   275 	if( function )
   276 	  ostr << function << ": ";
   277 	ostr << message;
   278 	if( assertion )
   279 	  ostr << " (assertion '" << assertion << "' failed)";
   280 	mes = ostr.str().c_str();
   281       }
   282       catch(...) {}
   283       if( mes ) return mes;
   284       return exceptionName();
   285     }
   286 
   287     virtual const char* exceptionName() const {
   288       return "lemon::AssertionFailedError";
   289     }
   290 
   291     virtual ~AssertionFailedError() throw() {}
   292   };
   293 
   294 
   295   /****************  Macros  ****************/
   296 
   297 
   298   inline
   299   void assert_fail(const char *file, int line, const char *func,
   300 		   const char *message, const char *assertion = 0,
   301 		   bool do_abort=true)
   302   {
   303     using namespace std;
   304     cerr << file << ":" << line << ": ";
   305     if( func )
   306       cerr << func << ": ";
   307     cerr << message;
   308     if( assertion )
   309       cerr << " (assertion '" << assertion << "' failed)";
   310     cerr << endl;
   311     if(do_abort)
   312       abort();
   313   }
   314 
   315   inline
   316   void assert_fail_throw(const char *file, int line, const char *func,
   317 		   const char *message, const char *assertion = 0,
   318 		   bool = true)
   319   {
   320     throw AssertionFailedError(file, line, func, message, assertion);
   321   }
   322 
   323 
   324 }
   325 #endif // LEMON_ERROR_H
   326 
   327 #undef LEMON_ASSERT
   328 #undef LEMON_FIXME
   329 
   330 #ifndef LEMON_ASSERT_ABORT
   331 #  define LEMON_ASSERT_ABORT 1
   332 #endif
   333 
   334 #ifndef LEMON_ASSERT_HANDLER
   335 #  ifdef LEMON_ASSERT_EXCEPTION
   336 #    define LEMON_ASSERT_HANDLER ::lemon::assert_fail_throw
   337 #  else
   338 #    define LEMON_ASSERT_HANDLER ::lemon::assert_fail
   339 #  endif
   340 #endif
   341 
   342 #if defined(NDEBUG) || defined(LEMON_DISABLE_ASSERTS)
   343 
   344 #  define LEMON_ASSERT(exp, msg)  (static_cast<void> (0))
   345 
   346 #else
   347 
   348 /**
   349  * \brief Macro for assertions with customizable message
   350  *
   351  * Macro for assertions with customizable message.
   352  *
   353  * The behaviour can be customized with LEMON_ASSERT_HANDLER,
   354  * LEMON_ASSERT_EXCEPTION and LEMON_ASSERT_ABORT defines. Asserts can be
   355  * disabled by defining either NDEBUG or LEMON_DISABLE_ASSERTS macros.
   356  *
   357  * \todo We should provide some way to reset to the default behaviour,
   358  * shouldn't we?
   359  *
   360  * \todo This whole 'assert' business should be placed in a separate
   361  * include file.
   362  *
   363  * \todo __PRETTY_FUNCTION__ should be replaced by something
   364  * compiler-independant, like BOOST_CURRENT_FUNCTION
   365  */
   366 
   367 #  define LEMON_ASSERT(exp, msg)                 \
   368      (static_cast<void> (!!(exp) ? 0 : (         \
   369        LEMON_ASSERT_HANDLER(__FILE__, __LINE__,  \
   370                             __PRETTY_FUNCTION__, \
   371 			    (msg), #exp, LEMON_ASSERT_ABORT), 0)))
   372 
   373 #endif // NDEBUG || LEMON_DISABLE_ASSERTS
   374 
   375 /**
   376  * \brief Macro for mark not yet implemented features.
   377  *
   378  * \todo Is this the right place for this? It should be used only in
   379  * modules under development.
   380  *
   381  * \todo __PRETTY_FUNCTION__ should be replaced by something
   382  * compiler-independant, like BOOST_CURRENT_FUNCTION
   383  */
   384 
   385 # define LEMON_FIXME(msg) \
   386     (LEMON_ASSERT_HANDLER(__FILE__, __LINE__, __PRETTY_FUNCTION__, \
   387 			  "FIXME: " msg))