lemon/error.h
author convert-repo
Thu, 04 Mar 2010 19:34:55 +0000
changeset 2659 611ced85018b
parent 2476 059dcdda37c5
permissions -rw-r--r--
update tags
     1 /* -*- C++ -*-
     2  *
     3  * This file is a part of LEMON, a generic C++ optimization library
     4  *
     5  * Copyright (C) 2003-2008
     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 *msg) throw() {
   130       init();
   131       *this << msg;
   132     }
   133 
   134     ///\e 
   135     ErrorMessage(const std::string &msg) throw() {
   136       init();
   137       *this << msg;
   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 ln) { _line = ln; }
   270     ///\e 
   271     void message(const std::string& msg) { _message.set(msg); }
   272     ///\e 
   273     void file(const std::string &fl) { _file.set(fl); }
   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& fl)
   333       : _file(fl) {}
   334 
   335 
   336     ///\e 
   337     void file(const std::string &fl) { _file.set(fl); }
   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& msg) { _message.set(msg); }
   386     ///\e 
   387     void file(const std::string &fl) { _file.set(fl); }
   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, 
   479                           const char *func,
   480                           Exception exception, 
   481                           const char *assertion = 0,
   482                           bool do_abort=true)
   483   {
   484     using namespace std;
   485     cerr << file << ":" << line << ": ";
   486     if( func )
   487       cerr << func << ": ";
   488     cerr << exception.what();
   489     if( assertion )
   490       cerr << " (assertion '" << assertion << "' failed)";
   491     cerr << endl;
   492     if(do_abort)
   493       abort();
   494   }
   495 
   496   template <>
   497   inline void assert_fail<const char *>(const char *file, int line, 
   498                                         const char *func,
   499                                         const char *message, 
   500                                         const char *assertion,
   501                                         bool do_abort)
   502   {
   503     using namespace std;
   504     cerr << file << ":" << line << ": ";
   505     if( func )
   506       cerr << func << ": ";
   507     cerr << message;
   508     if( assertion )
   509       cerr << " (assertion '" << assertion << "' failed)";
   510     cerr << endl;
   511     if(do_abort)
   512       abort();
   513   }
   514 
   515   template <>
   516   inline void assert_fail<std::string>(const char *file, int line, 
   517                                        const char *func,
   518                                        std::string message, 
   519                                        const char *assertion,
   520                                        bool do_abort)
   521   {
   522     assert_fail(file, line, func, message.c_str(), assertion, do_abort);
   523   }
   524 
   525   template <typename Exception>
   526   inline void assert_fail_failure(const char *file, int line, const char *func,
   527 			   Exception exception, 
   528 			   const char *assertion = 0,
   529 			   bool = true)
   530   {
   531     throw AssertionFailedError(file, line, func, exception.what(), assertion);
   532   }
   533 
   534   template <>
   535   inline void assert_fail_failure<const char *>(const char *file, int line, 
   536                                                 const char *func,
   537                                                 const char *message, 
   538                                                 const char *assertion,
   539                                                 bool)
   540   {
   541     throw AssertionFailedError(file, line, func, message, assertion);
   542   }
   543 
   544   template <>
   545   inline void assert_fail_failure<std::string>(const char *file, int line, 
   546                                                const char *func,
   547                                                std::string message, 
   548                                                const char *assertion,
   549                                                bool)
   550   {
   551     assert_fail_failure(file, line, func, message.c_str(), assertion, true);
   552   }
   553 
   554   template <typename Exception> 
   555   inline void assert_fail_exception(const char *file, int line, const char *func,
   556 			     Exception exception, 
   557 			     const char *assertion = 0, bool = true)
   558   {
   559     throw exception;
   560   }
   561 
   562   template <> 
   563   inline void assert_fail_exception<const char *>(const char *file, int line, 
   564 					   const char *func,
   565 					   const char *message, 
   566 					   const char *assertion,
   567 					   bool)
   568   {
   569     throw AssertionFailedError(file, line, func, message, assertion);
   570   }
   571 
   572   template <>
   573   inline void assert_fail_exception<std::string>(const char *file, int line, 
   574                                                  const char *func,
   575                                                  std::string message, 
   576                                                  const char *assertion,
   577                                                  bool)
   578   {
   579     assert_fail_exception(file, line, func, message.c_str(), assertion, true);    
   580   }
   581 
   582 /// @}
   583 
   584 }
   585 #endif // LEMON_ERROR_H
   586 
   587 #undef LEMON_ASSERT
   588 #undef LEMON_FIXME
   589 
   590 #ifdef LEMON_ENABLE_ASSERTS
   591 #  define LEMON_ASSERT_ABORT
   592 #endif
   593 
   594 #ifndef LEMON_ASSERT_DO_ABORT
   595 #  define LEMON_ASSERT_DO_ABORT 1
   596 #endif
   597 
   598 #ifndef LEMON_ASSERT_HANDLER
   599 #  if defined LEMON_ASSERT_EXCEPTION
   600 #    define LEMON_ASSERT_HANDLER ::lemon::assert_fail_exception
   601 #  elif defined LEMON_ASSERT_FAILURE
   602 #    define LEMON_ASSERT_HANDLER ::lemon::assert_fail_failure
   603 #  elif defined LEMON_ASSERT_ABORT
   604 #    define LEMON_ASSERT_HANDLER ::lemon::assert_fail
   605 #  else
   606 #    define LEMON_DISABLE_ASSERTS
   607 #  endif
   608 #endif
   609 
   610 #ifdef DOXYGEN
   611 
   612 /// \brief Macro for assertions with customizable message
   613 ///
   614 /// Macro for assertions with customizable message.
   615 ///
   616 /// The assertions are disabled in the default behaviour. You can
   617 /// enable the assertions with the
   618 /// \code
   619 /// #define LEMON_ENABLE_ASSERTS
   620 /// \endcode
   621 /// Then an assert
   622 /// provides a log on the standard error about the assertion and aborts
   623 /// the program if LEMON_ASSERT_DO_ABORT is also defined (otherwise the
   624 /// program keeps on running).
   625 /// By defining LEMON_ASSERT_FAILURE or
   626 /// LEMON_ASSERT_EXCEPTION, you can set other behaviour to the
   627 /// assertions. In case LEMON_ASSERT_FAILURE is given, LEMON_ASSERT
   628 /// will always throw an \c AssertionFailedError exception with
   629 /// the \c msg error message. By using
   630 /// LEMON_ASSERT_EXCEPTION, one can define an arbitrary exception to be thrown.
   631 ///
   632 /// The LEMON_ASSERT macro should be called with the \c exp parameter
   633 /// which should be an expression convertible to bool. If the given
   634 /// parameter is false the assertion is raised and one of the assertion
   635 /// behaviour will be activated. The \c msg should be either a const
   636 /// char* message or an exception. When the \c msg is an exception the
   637 /// \ref lemon::Exception::what() "what()" function is called to retrieve and
   638 /// display the error message.
   639 ///
   640 /// \todo We should provide some way to reset to the default behaviour,
   641 /// shouldn't we?
   642 ///
   643 /// \todo This whole 'assert' business should be placed in a separate
   644 /// include file. The boost assert is not guarded by header sentries
   645 /// which may help to change the behaviour of the assertions in 
   646 /// the files.
   647 ///
   648 /// \todo __PRETTY_FUNCTION__ should be replaced by something
   649 /// compiler-independent, like BOOST_CURRENT_FUNCTION
   650 
   651 #  define LEMON_ASSERT(exp, msg)                 \
   652      (static_cast<void> (!!(exp) ? 0 : (         \
   653        LEMON_ASSERT_HANDLER(__FILE__, __LINE__,  \
   654                             __PRETTY_FUNCTION__, \
   655                             msg, #exp, LEMON_ASSERT_DO_ABORT), 0)))
   656 
   657 #else 
   658 #  if defined LEMON_DISABLE_ASSERTS
   659 
   660 #    define LEMON_ASSERT(exp, msg)  (static_cast<void> (0))
   661 
   662 #  else
   663 #    define LEMON_ASSERT(exp, msg)                 \
   664        (static_cast<void> (!!(exp) ? 0 : (         \
   665          LEMON_ASSERT_HANDLER(__FILE__, __LINE__,  \
   666                               __PRETTY_FUNCTION__, \
   667                               msg, #exp, LEMON_ASSERT_DO_ABORT), 0)))
   668 #  endif
   669 #endif
   670 
   671 /**
   672  * \brief Macro for mark not yet implemented features.
   673  *
   674  * \todo Is this the right place for this? It should be used only in
   675  * modules under development.
   676  *
   677  * \todo __PRETTY_FUNCTION__ should be replaced by something
   678  * compiler-independent, like BOOST_CURRENT_FUNCTION
   679  */
   680 
   681 # define LEMON_FIXME(msg) \
   682     (LEMON_ASSERT_HANDLER(__FILE__, __LINE__, __PRETTY_FUNCTION__, \
   683 			  "FIXME: " msg))