lemon/error.h
author alpar
Mon, 13 Nov 2006 18:46:19 +0000
changeset 2301 eb378706bd3d
parent 2153 b1fb96088350
child 2386 81b47fc5c444
permissions -rw-r--r--
Test the automatic compilation checker 1/2: make a bug
     1 /* -*- C++ -*-
     2  *
     3  * This file is a part of LEMON, a generic C++ optimization library
     4  *
     5  * Copyright (C) 2003-2006
     6  * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
     7  * (Egervary Research Group on Combinatorial Optimization, 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   /// \brief Exception safe wrapper class.
    39   ///
    40   /// Exception safe wrapper class to implement the members of exceptions.
    41   template <typename _Type>
    42   class ExceptionMember {
    43   public:
    44     typedef _Type Type;
    45 
    46     ExceptionMember() throw () {
    47       try {
    48 	ptr.reset(new Type());
    49       } catch (...) {}
    50     }
    51 
    52     ExceptionMember(const Type& type) throw () {
    53       try {
    54 	ptr.reset(new Type());
    55 	if (ptr.get() == 0) return;
    56 	*ptr = type;
    57       } catch (...) {}
    58     }
    59 
    60     ExceptionMember(const ExceptionMember& copy) throw() {
    61       try {
    62 	if (!copy.valid()) return;
    63 	ptr.reset(new Type());
    64 	if (ptr.get() == 0) return;
    65 	*ptr = copy.get();
    66       } catch (...) {}
    67     }
    68 
    69     ExceptionMember& operator=(const ExceptionMember& copy) {
    70       if (ptr.get() == 0) return;
    71       try {
    72 	if (!copy.valid()) return;
    73  	*ptr = copy.get();
    74       } catch (...) {}
    75     }
    76 
    77     void set(const Type& type) {
    78       if (ptr.get() == 0) return;
    79       try {
    80 	*ptr = type;
    81       } catch (...) {}
    82     }
    83 
    84     const Type& get() const {
    85       return *ptr;
    86     }
    87 
    88     bool valid() const {
    89       return ptr.get() != 0;
    90     }
    91     
    92   private:
    93     std::auto_ptr<_Type> ptr;
    94   };
    95 
    96   /// Exception-safe convenient "error message" class.
    97 
    98   /// Helper class which provides a convenient ostream-like (operator <<
    99   /// based) interface to create a string message. Mostly useful in
   100   /// exception classes (therefore the name).
   101   class ErrorMessage {
   102   protected:
   103     ///\e 
   104 
   105     ///\todo The good solution is boost::shared_ptr...
   106     ///
   107     mutable
   108     std::auto_ptr<std::ostringstream> buf;
   109     
   110     ///\e 
   111     bool init() throw() {
   112       try {
   113 	buf.reset(new std::ostringstream);
   114       }
   115       catch(...) {
   116 	buf.reset();
   117       }
   118       return buf.get();
   119     }
   120 
   121   public:
   122 
   123     ///\e 
   124     ErrorMessage() throw() { init(); }
   125 
   126     ErrorMessage(const ErrorMessage& em) throw() : buf(em.buf) { }
   127 
   128     ///\e 
   129     ErrorMessage(const char *message) throw() {
   130       init();
   131       *this << message;
   132     }
   133 
   134     ///\e 
   135     ErrorMessage(const std::string &message) throw() {
   136       init();
   137       *this << message;
   138     }
   139 
   140     ///\e 
   141     template <typename T>
   142     ErrorMessage& operator<<(const T &t) throw() {
   143       if( ! buf.get() ) return *this;
   144 
   145       try {
   146 	*buf << t;
   147       }
   148       catch(...) {
   149 	buf.reset();
   150       }
   151       return *this;
   152     }
   153 
   154     ///\e 
   155     const char* message() throw() {
   156       if( ! buf.get() ) return 0;
   157 
   158       const char* mes = 0;
   159       try {
   160 	mes = buf->str().c_str();
   161       }
   162       catch(...) {}
   163       return mes;
   164     }
   165     
   166   };
   167 
   168   /**
   169    * \brief Generic exception class.
   170    *
   171    * Base class for exceptions used in LEMON.
   172    */
   173   class Exception : public std::exception {
   174   public:
   175     ///\e 
   176     Exception() {}
   177     ///\e 
   178     virtual ~Exception() throw() {}
   179     ///\e 
   180     virtual const char* what() const throw() {
   181       return "lemon::Exception";
   182     }
   183   };
   184 
   185   /**
   186    * \brief One of the two main subclasses of \ref Exception.
   187    *
   188    * Logic errors represent problems in the internal logic of a program;
   189    * in theory, these are preventable, and even detectable before the
   190    * program runs (e.g., violations of class invariants).
   191    *
   192    * A typical example for this is \ref UninitializedParameter.
   193    */
   194   class LogicError : public Exception {
   195   public:
   196     virtual const char* what() const throw() {
   197       return "lemon::LogicError";
   198     }
   199   };
   200 
   201   /**
   202    * \brief \ref Exception for uninitialized parameters.
   203    *
   204    * This error represents problems in the initialization
   205    * of the parameters of the algorithms.
   206    */
   207   class UninitializedParameter : public LogicError {
   208   public:
   209     virtual const char* what() const throw() {
   210       return "lemon::UninitializedParameter";
   211     }
   212   };
   213 
   214   
   215   /**
   216    * \brief One of the two main subclasses of \ref Exception.
   217    *
   218    * Runtime errors represent problems outside the scope of a program;
   219    * they cannot be easily predicted and can generally only be caught as
   220    * the program executes.
   221    */
   222   class RuntimeError : public Exception {
   223   public:
   224     virtual const char* what() const throw() {
   225       return "lemon::RuntimeError";
   226     }
   227   };
   228 
   229   ///\e
   230   class RangeError : public RuntimeError {
   231   public:
   232     virtual const char* what() const throw() {
   233       return "lemon::RangeError";
   234     }
   235   };
   236 
   237   ///\e 
   238   class IoError : public RuntimeError {
   239   public:
   240     virtual const char* what() const throw() {
   241       return "lemon::IoError";
   242     }
   243   };
   244 
   245   ///\e 
   246   class DataFormatError : public IoError {
   247   protected:
   248     ExceptionMember<std::string> _message;
   249     ExceptionMember<std::string> _file;
   250     int _line;
   251 
   252     mutable ExceptionMember<std::string> _message_holder;
   253   public:
   254 
   255     DataFormatError(const DataFormatError &dfe) : 
   256       IoError(dfe), _message(dfe._message), _file(dfe._file),
   257       _line(dfe._line) {}
   258 
   259     ///\e 
   260     explicit DataFormatError(const char *the_message)
   261       : _message(the_message), _line(0) {}
   262 
   263     ///\e 
   264     DataFormatError(const std::string &file_name, int line_num,
   265 		    const char *the_message)
   266       : _message(the_message), _line(line_num) { file(file_name); }
   267 
   268     ///\e 
   269     void line(int line) { _line = line; }
   270     ///\e 
   271     void message(const std::string& message) { _message.set(message); }
   272     ///\e 
   273     void file(const std::string &file) { _file.set(file); }
   274  
   275     ///\e
   276     int line() const { return _line; }
   277     ///\e
   278     const char* message() const { 
   279       if (_message.valid() && !_message.get().empty()) {
   280 	return _message.get().c_str();
   281       } else {
   282 	return 0;
   283       }
   284     }
   285 
   286     /// \brief Returns the filename.
   287     ///
   288     /// Returns \e null if the filename was not specified.
   289     const char* file() const {
   290       if (_file.valid() && !_file.get().empty()) {
   291 	return _file.get().c_str();
   292       } else {
   293 	return 0;
   294       }
   295     }
   296 
   297     ///\e 
   298     virtual const char* what() const throw() {
   299       try {
   300 	std::ostringstream ostr;
   301 	ostr << "lemon:DataFormatError" << ": ";
   302 	if (message()) ostr << message();
   303 	if( file() || line() != 0 ) {
   304 	  ostr << " (";
   305 	  if( file() ) ostr << "in file '" << file() << "'";
   306 	  if( file() && line() != 0 ) ostr << " ";
   307 	  if( line() != 0 ) ostr << "at line " << line();
   308 	  ostr << ")";
   309 	}
   310 	_message_holder.set(ostr.str());
   311       }
   312       catch (...) {}
   313       if( _message_holder.valid()) return _message_holder.get().c_str();
   314       return "lemon:DataFormatError";
   315     }
   316 
   317     virtual ~DataFormatError() throw() {}
   318   };
   319 
   320   ///\e 
   321   class FileOpenError : public IoError {
   322   protected:
   323     ExceptionMember<std::string> _file;
   324 
   325     mutable ExceptionMember<std::string> _message_holder;
   326   public:
   327 
   328     FileOpenError(const FileOpenError &foe) : 
   329       IoError(foe), _file(foe._file) {}
   330 
   331     ///\e 
   332     explicit FileOpenError(const std::string& file)
   333       : _file(file) {}
   334 
   335 
   336     ///\e 
   337     void file(const std::string &file) { _file.set(file); }
   338  
   339     /// \brief Returns the filename.
   340     ///
   341     /// Returns \e null if the filename was not specified.
   342     const char* file() const {
   343       if (_file.valid() && !_file.get().empty()) {
   344 	return _file.get().c_str();
   345       } else {
   346 	return 0;
   347       }
   348     }
   349 
   350     ///\e 
   351     virtual const char* what() const throw() {
   352       try {
   353 	std::ostringstream ostr;
   354 	ostr << "lemon::FileOpenError" << ": ";
   355 	ostr << "Cannot open file - " << file();
   356 	_message_holder.set(ostr.str());
   357       }
   358       catch (...) {}
   359       if( _message_holder.valid()) return _message_holder.get().c_str();
   360       return "lemon::FileOpenError";
   361     }
   362     virtual ~FileOpenError() throw() {}
   363   };
   364 
   365   class IoParameterError : public IoError {
   366   protected:
   367     ExceptionMember<std::string> _message;
   368     ExceptionMember<std::string> _file;
   369 
   370     mutable ExceptionMember<std::string> _message_holder;
   371   public:
   372 
   373     IoParameterError(const IoParameterError &ile) : 
   374       IoError(ile), _message(ile._message), _file(ile._file) {}
   375 
   376     ///\e 
   377     explicit IoParameterError(const char *the_message)
   378       : _message(the_message) {}
   379 
   380     ///\e 
   381     IoParameterError(const char *file_name, const char *the_message)
   382       : _message(the_message), _file(file_name) {}
   383 
   384      ///\e 
   385     void message(const std::string& message) { _message.set(message); }
   386     ///\e 
   387     void file(const std::string &file) { _file.set(file); }
   388  
   389      ///\e
   390     const char* message() const { 
   391       if (_message.valid()) {
   392 	return _message.get().c_str();
   393       } else {
   394 	return 0;
   395       }
   396     }
   397 
   398     /// \brief Returns the filename.
   399     ///
   400     /// Returns \e null if the filename was not specified.
   401     const char* file() const {
   402       if (_file.valid()) {
   403 	return _file.get().c_str();
   404       } else {
   405 	return 0;
   406       }
   407     }
   408 
   409     ///\e 
   410     virtual const char* what() const throw() {
   411       try {
   412 	std::ostringstream ostr;
   413 	if (message()) ostr << message();
   414 	if (file()) ostr << "(when reading file '" << file() << "')";
   415 	_message_holder.set(ostr.str());
   416       }
   417       catch (...) {}
   418       if( _message_holder.valid() ) return _message_holder.get().c_str();
   419       return "lemon:IoParameterError";
   420     }
   421     virtual ~IoParameterError() throw() {}
   422   };
   423 
   424 
   425   ///\e
   426   class AssertionFailedError : public LogicError {
   427   protected:
   428     const char *assertion;
   429     const char *file;
   430     int line;
   431     const char *function;
   432     const char *message;
   433 
   434     mutable ExceptionMember<std::string> _message_holder;
   435   public:
   436     ///\e
   437     AssertionFailedError(const char *_file, int _line, const char *func,
   438 			 const char *msg, const char *_assertion = 0) :
   439       assertion(_assertion), file(_file), line(_line), function(func),
   440       message(msg) {}
   441 
   442     ///\e
   443     const char* get_assertion() const { return assertion; }
   444     ///\e
   445     const char* get_message() const { return message; }
   446     ///\e
   447     const char* get_file() const { return file; }
   448     ///\e
   449     const char* get_function() const { return function; }
   450     ///\e
   451     int get_line() const { return line; }
   452 
   453 
   454     virtual const char* what() const throw() {
   455       try {
   456 	std::ostringstream ostr;
   457 	ostr << file << ":" << line << ": ";
   458 	if( function )
   459 	  ostr << function << ": ";
   460 	ostr << message;
   461 	if( assertion )
   462 	   ostr << " (assertion '" << assertion << "' failed)";
   463 	_message_holder.set(ostr.str());
   464 	return ostr.str().c_str();
   465       }
   466       catch(...) {}
   467       if( _message_holder.valid() ) return _message_holder.get().c_str();
   468       return "lemon::AssertionFailedError";
   469     }
   470    virtual ~AssertionFailedError() throw() {}
   471   };
   472 
   473 
   474   /****************  Macros  ****************/
   475 
   476 
   477   template <typename Exception>
   478   inline void assert_fail(const char *file, int line, const char *func,
   479 		   Exception exception, const char *assertion = 0,
   480 		   bool do_abort=true)
   481   {
   482     using namespace std;
   483     cerr << file << ":" << line << ": ";
   484     if( func )
   485       cerr << func << ": ";
   486     cerr << exception.what();
   487     if( assertion )
   488       cerr << " (assertion '" << assertion << "' failed)";
   489     cerr << endl;
   490     if(do_abort)
   491       abort();
   492   }
   493 
   494   template <>
   495   inline void assert_fail<const char *>(const char *file, int line, 
   496                                         const char *func,
   497                                         const char *message, 
   498                                         const char *assertion,
   499                                         bool do_abort)
   500   {
   501     using namespace std;
   502     cerr << file << ":" << line << ": ";
   503     if( func )
   504       cerr << func << ": ";
   505     cerr << message;
   506     if( assertion )
   507       cerr << " (assertion '" << assertion << "' failed)";
   508     cerr << endl;
   509     if(do_abort)
   510       abort();
   511   }
   512 
   513   template <typename Exception>
   514   inline void assert_fail_failure(const char *file, int line, const char *func,
   515 			   Exception exception, 
   516 			   const char *assertion = 0,
   517 			   bool = true)
   518   {
   519     throw AssertionFailedError(file, line, func, exception.what(), assertion);
   520   }
   521 
   522   template <>
   523   inline void assert_fail_failure<const char *>(const char *file, int line, 
   524 					 const char *func,
   525 					 const char *message, 
   526 					 const char *assertion,
   527 					 bool)
   528   {
   529     throw AssertionFailedError(file, line, func, message, assertion);
   530   }
   531 
   532   template <typename Exception> 
   533   inline void assert_fail_exception(const char *file, int line, const char *func,
   534 			     Exception exception, 
   535 			     const char *assertion = 0, bool = true)
   536   {
   537     throw exception;
   538   }
   539 
   540   template <> 
   541   inline void assert_fail_exception<const char *>(const char *file, int line, 
   542 					   const char *func,
   543 					   const char *message, 
   544 					   const char *assertion,
   545 					   bool)
   546   {
   547     throw AssertionFailedError(file, line, func, message, assertion);
   548   }
   549 
   550 /// @}
   551 
   552 }
   553 #endif // LEMON_ERROR_H
   554 
   555 #undef LEMON_ASSERT
   556 #undef LEMON_FIXME
   557 
   558 #ifdef LEMON_ENABLE_ASSERTS
   559 #  define LEMON_ASSERT_ABORT
   560 #endif
   561 
   562 #ifndef LEMON_ASSERT_DO_ABORT
   563 #  define LEMON_ASSERT_DO_ABORT 1
   564 #endif
   565 
   566 #ifndef LEMON_ASSERT_HANDLER
   567 #  if defined LEMON_ASSERT_EXCEPTION
   568 #    define LEMON_ASSERT_HANDLER ::lemon::assert_fail_exception
   569 #  elif defined LEMON_ASSERT_FAILURE
   570 #    define LEMON_ASSERT_HANDLER ::lemon::assert_fail_failure
   571 #  elif defined LEMON_ASSERT_ABORT
   572 #    define LEMON_ASSERT_HANDLER ::lemon::assert_fail
   573 #  else
   574 #    define LEMON_DISABLE_ASSERTS
   575 #  endif
   576 #endif
   577 
   578 #ifdef DOXYGEN
   579 
   580 /// \brief Macro for assertions with customizable message
   581 ///
   582 /// Macro for assertions with customizable message.
   583 ///
   584 /// The assertions are disabled in the default behaviour. You can
   585 /// enable the assertions with the
   586 /// \code
   587 /// #define LEMON_ENABLE_ASSERTS
   588 /// \endcode
   589 /// Then an assert
   590 /// provides a log on the standard error about the assertion and aborts
   591 /// the program if LEMON_ASSERT_DO_ABORT is also defined (otherwise the
   592 /// program keeps on running).
   593 /// By defining LEMON_ASSERT_FAILURE or
   594 /// LEMON_ASSERT_EXCEPTION, you can set other behaviour to the
   595 /// assertions. In case LEMON_ASSERT_FAILURE is given, LEMON_ASSERT
   596 /// will always throw an \c AssertionFailedError exception with
   597 /// the \c msg error message. By using
   598 /// LEMON_ASSERT_EXCEPTION, one can define an arbitrary exception to be thrown.
   599 ///
   600 /// The LEMON_ASSERT macro should be called with the \c exp parameter
   601 /// which should be an expression convertible to bool. If the given
   602 /// parameter is false the assertion is raised and one of the assertion
   603 /// behaviour will be activated. The \c msg should be either a const
   604 /// char* message or an exception. When the \c msg is an exception the
   605 /// \ref "Exception::what" what() function is called to retrieve and
   606 /// display the error message.
   607 ///
   608 /// \todo We should provide some way to reset to the default behaviour,
   609 /// shouldn't we?
   610 ///
   611 /// \todo This whole 'assert' business should be placed in a separate
   612 /// include file. The boost assert is not guarded by header sentries
   613 /// which may help to change the behaviour of the assertions in 
   614 /// the files.
   615 ///
   616 /// \todo __PRETTY_FUNCTION__ should be replaced by something
   617 /// compiler-independent, like BOOST_CURRENT_FUNCTION
   618 
   619 #  define LEMON_ASSERT(exp, msg)                 \
   620      (static_cast<void> (!!(exp) ? 0 : (         \
   621        LEMON_ASSERT_HANDLER(__FILE__, __LINE__,  \
   622                             __PRETTY_FUNCTION__, \
   623                             msg, #exp, LEMON_ASSERT_DO_ABORT), 0)))
   624 
   625 #else 
   626 #  if defined LEMON_DISABLE_ASSERTS
   627 
   628 #    define LEMON_ASSERT(exp, msg)  (static_cast<void> (0))
   629 
   630 #  else
   631 #    define LEMON_ASSERT(exp, msg)                 \
   632        (static_cast<void> (!!(exp) ? 0 : (         \
   633          LEMON_ASSERT_HANDLER(__FILE__, __LINE__,  \
   634                               __PRETTY_FUNCTION__, \
   635                               msg, #exp, LEMON_ASSERT_DO_ABORT), 0)))
   636 #  endif
   637 #endif
   638 
   639 /**
   640  * \brief Macro for mark not yet implemented features.
   641  *
   642  * \todo Is this the right place for this? It should be used only in
   643  * modules under development.
   644  *
   645  * \todo __PRETTY_FUNCTION__ should be replaced by something
   646  * compiler-independent, like BOOST_CURRENT_FUNCTION
   647  */
   648 
   649 # define LEMON_FIXME(msg) \
   650     (LEMON_ASSERT_HANDLER(__FILE__, __LINE__, __PRETTY_FUNCTION__, \
   651 			  "FIXME: " msg))