src/lemon/error.h
author alpar
Tue, 15 Feb 2005 14:54:25 +0000
changeset 1146 ebab0e5ec8b2
parent 1122 3ce7fc516cca
child 1151 b217fc69f913
permissions -rw-r--r--
Doc improvements.
     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    * A typical example for this is \ref UninitializedParameter.
   130    */
   131   class LogicError : public Exception {
   132   public:
   133     virtual const char* exceptionName() const {
   134       return "lemon::LogicError";
   135     }
   136   };
   137 
   138   /**
   139    * \brief \ref Exception for uninitialized parameters.
   140    *
   141    * This error represents problems in the initialization
   142    * of the parameters of the algorithms.
   143    */
   144   class UninitializedParameter : public LogicError {
   145   public:
   146     virtual const char* exceptionName() const {
   147       return "lemon::UninitializedParameter";
   148     }
   149   };
   150 
   151   
   152   /**
   153    * \brief One of the two main subclasses of \ref Exception.
   154    *
   155    * Runtime errors represent problems outside the scope of a program;
   156    * they cannot be easily predicted and can generally only be caught as
   157    * the program executes.
   158    */
   159   class RuntimeError : public Exception {
   160   public:
   161     virtual const char* exceptionName() const {
   162       return "lemon::RuntimeError";
   163     }
   164   };
   165 
   166   ///\e
   167   class RangeError : public RuntimeError {
   168   public:
   169     virtual const char* exceptionName() const {
   170       return "lemon::RangeError";
   171     }
   172   };
   173 
   174   ///\e 
   175   class IOError : public RuntimeError {
   176   public:
   177     virtual const char* exceptionName() const {
   178       return "lemon::IOError";
   179     }
   180   };
   181 
   182   ///\e 
   183   class DataFormatError : public IOError {
   184   protected:
   185     const char *_message;
   186     int _line;
   187     boost::shared_ptr<std::string> _file;
   188 
   189   public:
   190     ///\e 
   191     explicit DataFormatError(const char *the_message)
   192       : _message(the_message), _line(0) {}
   193     ///\e 
   194     DataFormatError(const std::string &file_name, int line_num,
   195 		    const char *the_message)
   196       : _message(the_message), _line(line_num) { file(file_name); }
   197 
   198     ///\e 
   199     void line(int line_num) { _line=line_num; }
   200     ///\e 
   201     void message(char *the_message) { _message=the_message; }
   202     ///\e 
   203     void file(const std::string &file_name) {
   204       try {
   205 	_file.reset(new std::string);
   206 	*_file = file_name;
   207       }
   208       catch(...) {
   209 	_file.reset();
   210       }
   211     }
   212 
   213     ///\e
   214     int line() const { return _line; }
   215     ///\e
   216     const char* message() const { return _message; }
   217 
   218     /// \brief Returns the filename.
   219     ///
   220     /// Returns \e "(unknown)" if the filename was not specified.
   221     const char* file() const {
   222       if( _file )
   223 	return _file->c_str();
   224       else
   225 	return "(unknown)";
   226     }
   227 
   228     ///\e 
   229     virtual const char* what() const throw() {
   230       const char *mes = 0;
   231       try {
   232 	std::ostringstream ostr;
   233 	ostr << _message;
   234 	if( _file || _line ) {
   235 	  ostr << " (";
   236 	  if( _file ) ostr << "in file '" << *_file << "'";
   237 	  if( _file && _line ) ostr << " ";
   238 	  if( _line ) ostr << "at line " << _line;
   239 	  ostr << ")";
   240 	}
   241 	mes = ostr.str().c_str();
   242       }
   243       catch(...) {}
   244       if( mes ) return mes;
   245       return exceptionName();
   246     }
   247 
   248     virtual const char* exceptionName() const {
   249       return "lemon::DataFormatError";
   250     }
   251 
   252     virtual ~DataFormatError() throw() {}
   253   };
   254 
   255 
   256   ///\e
   257   class AssertionFailedError : public LogicError {
   258   protected:
   259     const char *assertion;
   260     const char *file;
   261     int line;
   262     const char *function;
   263     const char *message;
   264   public:
   265     ///\e
   266     AssertionFailedError(const char *_file, int _line, const char *func,
   267 			 const char *msg, const char *_assertion = 0) :
   268       assertion(_assertion), file(_file), line(_line), function(func),
   269       message(msg) {}
   270 
   271     ///\e
   272     const char* get_assertion() const { return assertion; }
   273     ///\e
   274     const char* get_message() const { return message; }
   275     ///\e
   276     const char* get_file() const { return file; }
   277     ///\e
   278     const char* get_function() const { return function; }
   279     ///\e
   280     int get_line() const { return line; }
   281 
   282 
   283     virtual const char* what() const throw() {
   284       const char *mes = 0;
   285       try {
   286 	std::ostringstream ostr;
   287 	ostr << file << ":" << line << ": ";
   288 	if( function )
   289 	  ostr << function << ": ";
   290 	ostr << message;
   291 	if( assertion )
   292 	  ostr << " (assertion '" << assertion << "' failed)";
   293 	mes = ostr.str().c_str();
   294       }
   295       catch(...) {}
   296       if( mes ) return mes;
   297       return exceptionName();
   298     }
   299 
   300     virtual const char* exceptionName() const {
   301       return "lemon::AssertionFailedError";
   302     }
   303 
   304     virtual ~AssertionFailedError() throw() {}
   305   };
   306 
   307 
   308   /****************  Macros  ****************/
   309 
   310 
   311   inline
   312   void assert_fail(const char *file, int line, const char *func,
   313 		   const char *message, const char *assertion = 0,
   314 		   bool do_abort=true)
   315   {
   316     using namespace std;
   317     cerr << file << ":" << line << ": ";
   318     if( func )
   319       cerr << func << ": ";
   320     cerr << message;
   321     if( assertion )
   322       cerr << " (assertion '" << assertion << "' failed)";
   323     cerr << endl;
   324     if(do_abort)
   325       abort();
   326   }
   327 
   328   inline
   329   void assert_fail_throw(const char *file, int line, const char *func,
   330 		   const char *message, const char *assertion = 0,
   331 		   bool = true)
   332   {
   333     throw AssertionFailedError(file, line, func, message, assertion);
   334   }
   335 
   336 
   337 }
   338 #endif // LEMON_ERROR_H
   339 
   340 #undef LEMON_ASSERT
   341 #undef LEMON_FIXME
   342 
   343 #ifndef LEMON_ASSERT_ABORT
   344 #  define LEMON_ASSERT_ABORT 1
   345 #endif
   346 
   347 #ifndef LEMON_ASSERT_HANDLER
   348 #  ifdef LEMON_ASSERT_EXCEPTION
   349 #    define LEMON_ASSERT_HANDLER ::lemon::assert_fail_throw
   350 #  else
   351 #    define LEMON_ASSERT_HANDLER ::lemon::assert_fail
   352 #  endif
   353 #endif
   354 
   355 #if defined(NDEBUG) || defined(LEMON_DISABLE_ASSERTS)
   356 
   357 #  define LEMON_ASSERT(exp, msg)  (static_cast<void> (0))
   358 
   359 #else
   360 
   361 /**
   362  * \brief Macro for assertions with customizable message
   363  *
   364  * Macro for assertions with customizable message.
   365  *
   366  * The behaviour can be customized with LEMON_ASSERT_HANDLER,
   367  * LEMON_ASSERT_EXCEPTION and LEMON_ASSERT_ABORT defines. Asserts can be
   368  * disabled by defining either NDEBUG or LEMON_DISABLE_ASSERTS macros.
   369  *
   370  * \todo We should provide some way to reset to the default behaviour,
   371  * shouldn't we?
   372  *
   373  * \todo This whole 'assert' business should be placed in a separate
   374  * include file.
   375  *
   376  * \todo __PRETTY_FUNCTION__ should be replaced by something
   377  * compiler-independant, like BOOST_CURRENT_FUNCTION
   378  */
   379 
   380 #  define LEMON_ASSERT(exp, msg)                 \
   381      (static_cast<void> (!!(exp) ? 0 : (         \
   382        LEMON_ASSERT_HANDLER(__FILE__, __LINE__,  \
   383                             __PRETTY_FUNCTION__, \
   384 			    (msg), #exp, LEMON_ASSERT_ABORT), 0)))
   385 
   386 #endif // NDEBUG || LEMON_DISABLE_ASSERTS
   387 
   388 /**
   389  * \brief Macro for mark not yet implemented features.
   390  *
   391  * \todo Is this the right place for this? It should be used only in
   392  * modules under development.
   393  *
   394  * \todo __PRETTY_FUNCTION__ should be replaced by something
   395  * compiler-independant, like BOOST_CURRENT_FUNCTION
   396  */
   397 
   398 # define LEMON_FIXME(msg) \
   399     (LEMON_ASSERT_HANDLER(__FILE__, __LINE__, __PRETTY_FUNCTION__, \
   400 			  "FIXME: " msg))