lemon/error.h
changeset 108 889d0c289d19
parent 66 5f7a8570687d
child 209 765619b7cbb2
equal deleted inserted replaced
0:553a545829ef 1:02eefc7d01a5
    91 
    91 
    92   private:
    92   private:
    93     std::auto_ptr<_Type> ptr;
    93     std::auto_ptr<_Type> ptr;
    94   };
    94   };
    95 
    95 
    96   /// Exception-safe convenient "error message" class.
    96   /// Exception-safe convenient error message builder class.
    97 
    97 
    98   /// Helper class which provides a convenient ostream-like (operator <<
    98   /// Helper class which provides a convenient ostream-like (operator <<
    99   /// based) interface to create a string message. Mostly useful in
    99   /// based) interface to create a string message. Mostly useful in
   100   /// exception classes (therefore the name).
   100   /// exception classes (therefore the name).
   101   class ErrorMessage {
   101   class ErrorMessage {
   411       return "lemon:IoParameterError";
   411       return "lemon:IoParameterError";
   412     }
   412     }
   413     virtual ~IoParameterError() throw() {}
   413     virtual ~IoParameterError() throw() {}
   414   };
   414   };
   415 
   415 
   416 
   416   /// @}
   417   ///\e
       
   418   class AssertionFailedError : public LogicError {
       
   419   protected:
       
   420     const char *assertion;
       
   421     const char *file;
       
   422     int line;
       
   423     const char *function;
       
   424     const char *message;
       
   425 
       
   426     mutable ExceptionMember<std::string> _message_holder;
       
   427   public:
       
   428     ///\e
       
   429     AssertionFailedError(const char *_file, int _line, const char *func,
       
   430 			 const char *msg, const char *_assertion = 0) :
       
   431       assertion(_assertion), file(_file), line(_line), function(func),
       
   432       message(msg) {}
       
   433 
       
   434     ///\e
       
   435     const char* get_assertion() const { return assertion; }
       
   436     ///\e
       
   437     const char* get_message() const { return message; }
       
   438     ///\e
       
   439     const char* get_file() const { return file; }
       
   440     ///\e
       
   441     const char* get_function() const { return function; }
       
   442     ///\e
       
   443     int get_line() const { return line; }
       
   444 
       
   445 
       
   446     virtual const char* what() const throw() {
       
   447       try {
       
   448 	std::ostringstream ostr;
       
   449 	ostr << file << ":" << line << ": ";
       
   450 	if( function )
       
   451 	  ostr << function << ": ";
       
   452 	ostr << message;
       
   453 	if( assertion )
       
   454 	   ostr << " (assertion '" << assertion << "' failed)";
       
   455 	_message_holder.set(ostr.str());
       
   456 	return ostr.str().c_str();
       
   457       }
       
   458       catch(...) {}
       
   459       if( _message_holder.valid() ) return _message_holder.get().c_str();
       
   460       return "lemon::AssertionFailedError";
       
   461     }
       
   462    virtual ~AssertionFailedError() throw() {}
       
   463   };
       
   464 
       
   465 
       
   466   /****************  Macros  ****************/
       
   467 
       
   468 
       
   469   template <typename Exception>
       
   470   inline void assert_fail(const char *file, int line,
       
   471                           const char *func,
       
   472                           Exception exception,
       
   473                           const char *assertion = 0,
       
   474                           bool do_abort=true)
       
   475   {
       
   476     using namespace std;
       
   477     cerr << file << ":" << line << ": ";
       
   478     if (func)
       
   479       cerr << func << ": ";
       
   480     cerr << exception.what();
       
   481     if (assertion)
       
   482       cerr << " (assertion '" << assertion << "' failed)";
       
   483     cerr << endl;
       
   484     if (do_abort)
       
   485       abort();
       
   486   }
       
   487 
       
   488   template <>
       
   489   inline void assert_fail<const char *>(const char *file, int line,
       
   490                                         const char *func,
       
   491                                         const char *message,
       
   492                                         const char *assertion,
       
   493                                         bool do_abort)
       
   494   {
       
   495     using namespace std;
       
   496     cerr << file << ":" << line << ": ";
       
   497     if (func)
       
   498       cerr << func << ": ";
       
   499     cerr << message;
       
   500     if (assertion)
       
   501       cerr << " (assertion '" << assertion << "' failed)";
       
   502     cerr << endl;
       
   503     if (do_abort)
       
   504       abort();
       
   505   }
       
   506 
       
   507   template <>
       
   508   inline void assert_fail<std::string>(const char *file, int line,
       
   509                                        const char *func,
       
   510                                        std::string message,
       
   511                                        const char *assertion,
       
   512                                        bool do_abort)
       
   513   {
       
   514     assert_fail(file, line, func, message.c_str(), assertion, do_abort);
       
   515   }
       
   516 
       
   517   template <typename Exception>
       
   518   inline void assert_fail_failure(const char *file, int line, const char *func,
       
   519 			   Exception exception,
       
   520 			   const char *assertion = 0,
       
   521 			   bool = true)
       
   522   {
       
   523     throw AssertionFailedError(file, line, func, exception.what(), assertion);
       
   524   }
       
   525 
       
   526   template <>
       
   527   inline void assert_fail_failure<const char *>(const char *file, int line,
       
   528                                                 const char *func,
       
   529                                                 const char *message,
       
   530                                                 const char *assertion,
       
   531                                                 bool)
       
   532   {
       
   533     throw AssertionFailedError(file, line, func, message, assertion);
       
   534   }
       
   535 
       
   536   template <>
       
   537   inline void assert_fail_failure<std::string>(const char *file, int line,
       
   538                                                const char *func,
       
   539                                                std::string message,
       
   540                                                const char *assertion,
       
   541                                                bool)
       
   542   {
       
   543     assert_fail_failure(file, line, func, message.c_str(), assertion, true);
       
   544   }
       
   545 
       
   546   template <typename Exception>
       
   547   inline void assert_fail_exception(const char *file, int line, const char *func,
       
   548 			     Exception exception,
       
   549 			     const char *assertion = 0, bool = true)
       
   550   {
       
   551     throw exception;
       
   552   }
       
   553 
       
   554   template <>
       
   555   inline void assert_fail_exception<const char *>(const char *file, int line,
       
   556 					   const char *func,
       
   557 					   const char *message,
       
   558 					   const char *assertion,
       
   559 					   bool)
       
   560   {
       
   561     throw AssertionFailedError(file, line, func, message, assertion);
       
   562   }
       
   563 
       
   564   template <>
       
   565   inline void assert_fail_exception<std::string>(const char *file, int line,
       
   566                                                  const char *func,
       
   567                                                  std::string message,
       
   568                                                  const char *assertion,
       
   569                                                  bool)
       
   570   {
       
   571     assert_fail_exception(file, line, func, message.c_str(), assertion, true);
       
   572   }
       
   573 
       
   574 /// @}
       
   575 
   417 
   576 }
   418 }
       
   419 
   577 #endif // LEMON_ERROR_H
   420 #endif // LEMON_ERROR_H
   578 
       
   579 #undef LEMON_ASSERT
       
   580 #undef LEMON_FIXME
       
   581 
       
   582 #ifdef LEMON_ENABLE_ASSERTS
       
   583 #  define LEMON_ASSERT_ABORT
       
   584 #endif
       
   585 
       
   586 #ifndef LEMON_ASSERT_DO_ABORT
       
   587 #  define LEMON_ASSERT_DO_ABORT 1
       
   588 #endif
       
   589 
       
   590 #ifndef LEMON_ASSERT_HANDLER
       
   591 #  if defined LEMON_ASSERT_EXCEPTION
       
   592 #    define LEMON_ASSERT_HANDLER ::lemon::assert_fail_exception
       
   593 #  elif defined LEMON_ASSERT_FAILURE
       
   594 #    define LEMON_ASSERT_HANDLER ::lemon::assert_fail_failure
       
   595 #  elif defined LEMON_ASSERT_ABORT
       
   596 #    define LEMON_ASSERT_HANDLER ::lemon::assert_fail
       
   597 #  else
       
   598 #    define LEMON_DISABLE_ASSERTS
       
   599 #  endif
       
   600 #endif
       
   601 
       
   602 #ifdef DOXYGEN
       
   603 
       
   604 /// \brief Macro for assertions with customizable message
       
   605 ///
       
   606 /// Macro for assertions with customizable message.
       
   607 ///
       
   608 /// The assertions are disabled in the default behaviour. You can
       
   609 /// enable the assertions with the
       
   610 /// \code
       
   611 /// #define LEMON_ENABLE_ASSERTS
       
   612 /// \endcode
       
   613 /// Then an assert
       
   614 /// provides a log on the standard error about the assertion and aborts
       
   615 /// the program if LEMON_ASSERT_DO_ABORT is also defined (otherwise the
       
   616 /// program keeps on running).
       
   617 /// By defining LEMON_ASSERT_FAILURE or
       
   618 /// LEMON_ASSERT_EXCEPTION, you can set other behaviour to the
       
   619 /// assertions. In case LEMON_ASSERT_FAILURE is given, LEMON_ASSERT
       
   620 /// will always throw an \c AssertionFailedError exception with
       
   621 /// the \c msg error message. By using
       
   622 /// LEMON_ASSERT_EXCEPTION, one can define an arbitrary exception to be thrown.
       
   623 ///
       
   624 /// The LEMON_ASSERT macro should be called with the \c exp parameter
       
   625 /// which should be an expression convertible to bool. If the given
       
   626 /// parameter is false the assertion is raised and one of the assertion
       
   627 /// behaviour will be activated. The \c msg should be either a const
       
   628 /// char* message or an exception. When the \c msg is an exception the
       
   629 /// \ref lemon::Exception::what() "what()" function is called to retrieve and
       
   630 /// display the error message.
       
   631 ///
       
   632 /// \todo We should provide some way to reset to the default behaviour,
       
   633 /// shouldn't we?
       
   634 ///
       
   635 /// \todo This whole 'assert' business should be placed in a separate
       
   636 /// include file. The boost assert is not guarded by header sentries
       
   637 /// which may help to change the behaviour of the assertions in
       
   638 /// the files.
       
   639 ///
       
   640 /// \todo __PRETTY_FUNCTION__ should be replaced by something
       
   641 /// compiler-independent, like BOOST_CURRENT_FUNCTION
       
   642 
       
   643 #  define LEMON_ASSERT(exp, msg)                 \
       
   644      (static_cast<void> (!!(exp) ? 0 : (         \
       
   645        LEMON_ASSERT_HANDLER(__FILE__, __LINE__,  \
       
   646                             __PRETTY_FUNCTION__, \
       
   647                             msg, #exp, LEMON_ASSERT_DO_ABORT), 0)))
       
   648 
       
   649 #else
       
   650 #  if defined LEMON_DISABLE_ASSERTS
       
   651 
       
   652 #    define LEMON_ASSERT(exp, msg)  (static_cast<void> (0))
       
   653 
       
   654 #  else
       
   655 #    define LEMON_ASSERT(exp, msg)                 \
       
   656        (static_cast<void> (!!(exp) ? 0 : (         \
       
   657          LEMON_ASSERT_HANDLER(__FILE__, __LINE__,  \
       
   658                               __PRETTY_FUNCTION__, \
       
   659                               msg, #exp, LEMON_ASSERT_DO_ABORT), 0)))
       
   660 #  endif
       
   661 #endif
       
   662 
       
   663 /**
       
   664  * \brief Macro for mark not yet implemented features.
       
   665  *
       
   666  * \todo Is this the right place for this? It should be used only in
       
   667  * modules under development.
       
   668  *
       
   669  * \todo __PRETTY_FUNCTION__ should be replaced by something
       
   670  * compiler-independent, like BOOST_CURRENT_FUNCTION
       
   671  */
       
   672 
       
   673 #define LEMON_FIXME(msg) \
       
   674     (LEMON_ASSERT_HANDLER(__FILE__, __LINE__, __PRETTY_FUNCTION__, \
       
   675 			  "FIXME: " msg))