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