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