lemon/error.h
author deba
Tue, 17 Oct 2006 10:50:57 +0000
changeset 2247 269a0dcee70b
parent 2153 b1fb96088350
child 2386 81b47fc5c444
permissions -rw-r--r--
Update the Path concept
Concept check for paths

DirPath renamed to Path
The interface updated to the new lemon interface
Make difference between the empty path and the path from one node
Builder interface have not been changed
// I wanted but there was not accordance about it

UPath is removed
It was a buggy implementation, it could not iterate on the
nodes in the right order
Right way to use undirected paths => path of edges in undirected graphs

The tests have been modified to the current implementation
     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))