alpar@906: /* -*- C++ -*- alpar@921: * src/lemon/error.h - Part of LEMON, a generic C++ optimization library alpar@906: * alpar@906: * Copyright (C) 2004 Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport alpar@906: * (Egervary Combinatorial Optimization Research Group, EGRES). alpar@906: * alpar@906: * Permission to use, modify and distribute this software is granted alpar@906: * provided that this copyright notice appears in all copies. For alpar@906: * precise terms see the accompanying LICENSE file. alpar@906: * alpar@906: * This software is provided "AS IS" with no warranty of any kind, alpar@906: * express or implied, and with no claim as to its suitability for any alpar@906: * purpose. alpar@906: * alpar@906: */ alpar@883: alpar@921: #ifndef LEMON_ERROR_H alpar@921: #define LEMON_ERROR_H alpar@883: alpar@883: //! \ingroup misc alpar@883: //! \file klao@1067: //! \brief Basic exception classes and error handling. alpar@883: alpar@883: #include alpar@883: #include alpar@883: #include klao@1067: #include klao@1067: #include alpar@883: klao@1056: #include alpar@883: alpar@921: namespace lemon { alpar@883: klao@1056: /// Exception-safe convenient "error message" class. klao@1067: klao@1067: /// Helper class which provides a convenient ostream-like (operator << klao@1067: /// based) interface to create a string message. Mostly useful in klao@1067: /// exception classes (therefore the name). klao@1056: class ErrorMessage { klao@1056: protected: klao@1067: ///\e klao@1056: boost::shared_ptr buf; klao@1056: klao@1067: ///\e klao@1056: bool init() throw() { klao@1056: try { klao@1056: buf.reset(new std::ostringstream); klao@1056: } klao@1056: catch(...) { klao@1056: buf.reset(); klao@1056: } klao@1056: return buf; klao@1056: } klao@1056: klao@1056: public: klao@1056: klao@1067: ///\e klao@1056: ErrorMessage() throw() { init(); } klao@1056: klao@1067: ///\e klao@1056: ErrorMessage(const char *message) throw() { klao@1056: init(); klao@1056: *this << message; klao@1056: } klao@1056: klao@1067: ///\e klao@1056: ErrorMessage(const std::string &message) throw() { klao@1056: init(); klao@1056: *this << message; klao@1056: } klao@1056: klao@1067: ///\e klao@1056: template klao@1056: ErrorMessage& operator<<(const T &t) throw() { klao@1056: if( !buf ) return *this; klao@1056: klao@1056: try { klao@1056: *buf << t; klao@1056: } klao@1056: catch(...) { klao@1056: buf.reset(); klao@1056: } klao@1056: } klao@1056: klao@1067: ///\e klao@1056: const char* message() throw() { klao@1056: if( !buf ) return 0; klao@1056: klao@1056: const char* mes = 0; klao@1056: try { klao@1056: mes = buf->str().c_str(); klao@1056: } klao@1056: catch(...) {} klao@1056: return mes; klao@1056: } klao@1056: klao@1056: }; klao@1056: alpar@883: /** alpar@883: * \brief Generic exception class. alpar@883: * klao@1056: * Base class for exceptions used in LEMON. alpar@883: */ klao@1067: class Exception : public std::exception { alpar@883: public: klao@1067: ///\e klao@1120: Exception() {} klao@1067: ///\e alpar@883: virtual ~Exception() throw() {} klao@1120: klao@1120: ///\e klao@1120: virtual const char* exceptionName() const { klao@1120: return "lemon::Exception"; klao@1120: } alpar@883: klao@1067: ///\e alpar@883: virtual const char* what() const throw() { klao@1120: return exceptionName(); klao@1056: } klao@1056: }; klao@1056: klao@1120: /** klao@1120: * \brief One of the two main subclasses of \ref Exception. klao@1120: * klao@1120: * Logic errors represent problems in the internal logic of a program; klao@1120: * in theory, these are preventable, and even detectable before the klao@1120: * program runs (e.g., violations of class invariants). klao@1120: * alpar@1125: * A typical example for this is \ref UninitializedParameter. klao@1120: */ klao@1056: class LogicError : public Exception { klao@1067: public: klao@1120: virtual const char* exceptionName() const { klao@1120: return "lemon::LogicError"; klao@1120: } klao@1056: }; klao@1056: alpar@1125: /** alpar@1125: * \brief \ref Exception for uninitialized parameters. alpar@1125: * alpar@1125: * This error represents problems in the initialization alpar@1125: * of the parameters of the algorithms. alpar@1125: */ alpar@1125: class UninitializedParameter : public LogicError { alpar@1125: public: alpar@1125: virtual const char* exceptionName() const { alpar@1125: return "lemon::UninitializedParameter"; alpar@1125: } alpar@1125: }; alpar@1125: klao@1120: klao@1120: /** klao@1120: * \brief One of the two main subclasses of \ref Exception. klao@1120: * klao@1120: * Runtime errors represent problems outside the scope of a program; klao@1120: * they cannot be easily predicted and can generally only be caught as klao@1120: * the program executes. klao@1120: */ klao@1056: class RuntimeError : public Exception { klao@1067: public: klao@1120: virtual const char* exceptionName() const { klao@1120: return "lemon::RuntimeError"; klao@1120: } klao@1056: }; klao@1056: klao@1067: ///\e klao@1056: class RangeError : public RuntimeError { klao@1067: public: klao@1120: virtual const char* exceptionName() const { klao@1120: return "lemon::RangeError"; klao@1120: } klao@1056: }; klao@1056: alpar@1061: ///\e klao@1056: class IOError : public RuntimeError { klao@1067: public: klao@1120: virtual const char* exceptionName() const { klao@1120: return "lemon::IOError"; klao@1120: } klao@1056: }; klao@1056: alpar@1061: ///\e klao@1056: class DataFormatError : public IOError { klao@1067: protected: klao@1120: const char *_message; klao@1120: int _line; klao@1120: boost::shared_ptr _file; klao@1067: klao@1067: public: klao@1067: ///\e klao@1120: explicit DataFormatError(const char *the_message) klao@1120: : _message(the_message), _line(0) {} klao@1067: ///\e klao@1056: DataFormatError(const std::string &file_name, int line_num, klao@1120: const char *the_message) klao@1120: : _message(the_message), _line(line_num) { file(file_name); } klao@1056: klao@1067: ///\e klao@1120: void line(int line_num) { _line=line_num; } klao@1067: ///\e klao@1120: void message(char *the_message) { _message=the_message; } klao@1120: ///\e klao@1120: void file(const std::string &file_name) { klao@1056: try { klao@1120: _file.reset(new std::string); klao@1120: *_file = file_name; klao@1056: } klao@1056: catch(...) { klao@1120: _file.reset(); klao@1056: } alpar@883: } alpar@883: klao@1067: ///\e klao@1120: int line() const { return _line; } klao@1120: ///\e klao@1120: const char* message() const { return _message; } klao@1067: klao@1067: /// \brief Returns the filename. klao@1067: /// klao@1068: /// Returns \e "(unknown)" if the filename was not specified. klao@1120: const char* file() const { klao@1120: if( _file ) klao@1120: return _file->c_str(); klao@1067: else klao@1067: return "(unknown)"; klao@1067: } klao@1067: klao@1067: ///\e klao@1067: virtual const char* what() const throw() { klao@1056: const char *mes = 0; klao@1056: try { klao@1056: std::ostringstream ostr; klao@1120: ostr << _message; klao@1120: if( _file || _line ) { klao@1056: ostr << " ("; klao@1120: if( _file ) ostr << "in file '" << *_file << "'"; klao@1120: if( _file && _line ) ostr << " "; klao@1120: if( _line ) ostr << "at line " << _line; klao@1067: ostr << ")"; klao@1056: } klao@1056: mes = ostr.str().c_str(); klao@1056: } klao@1056: catch(...) {} klao@1056: if( mes ) return mes; klao@1120: return exceptionName(); klao@1120: } klao@1120: klao@1120: virtual const char* exceptionName() const { klao@1056: return "lemon::DataFormatError"; klao@1056: } klao@1067: klao@1067: virtual ~DataFormatError() throw() {} alpar@883: }; alpar@883: klao@1056: klao@1068: ///\e klao@1067: class AssertionFailedError : public LogicError { klao@1067: protected: klao@1067: const char *assertion; klao@1067: const char *file; klao@1067: int line; klao@1067: const char *function; klao@1067: const char *message; klao@1067: public: klao@1067: ///\e klao@1067: AssertionFailedError(const char *_file, int _line, const char *func, klao@1067: const char *msg, const char *_assertion = 0) : klao@1067: assertion(_assertion), file(_file), line(_line), function(func), klao@1067: message(msg) {} klao@1067: klao@1067: ///\e klao@1067: const char* get_assertion() const { return assertion; } klao@1067: ///\e klao@1067: const char* get_message() const { return message; } klao@1067: ///\e klao@1067: const char* get_file() const { return file; } klao@1067: ///\e klao@1067: const char* get_function() const { return function; } klao@1067: ///\e klao@1067: int get_line() const { return line; } klao@1067: klao@1067: klao@1067: virtual const char* what() const throw() { klao@1067: const char *mes = 0; klao@1067: try { klao@1067: std::ostringstream ostr; klao@1067: ostr << file << ":" << line << ": "; klao@1067: if( function ) klao@1067: ostr << function << ": "; klao@1067: ostr << message; klao@1067: if( assertion ) klao@1067: ostr << " (assertion '" << assertion << "' failed)"; klao@1067: mes = ostr.str().c_str(); klao@1067: } klao@1067: catch(...) {} klao@1067: if( mes ) return mes; klao@1120: return exceptionName(); klao@1120: } klao@1120: klao@1120: virtual const char* exceptionName() const { klao@1067: return "lemon::AssertionFailedError"; klao@1067: } klao@1067: klao@1067: virtual ~AssertionFailedError() throw() {} klao@1067: }; klao@1067: klao@1056: klao@1056: /**************** Macros ****************/ klao@1056: klao@1056: klao@1067: inline klao@1067: void assert_fail(const char *file, int line, const char *func, klao@1067: const char *message, const char *assertion = 0, klao@1067: bool do_abort=true) klao@1067: { klao@1067: using namespace std; klao@1067: cerr << file << ":" << line << ": "; klao@1067: if( func ) klao@1067: cerr << func << ": "; klao@1067: cerr << message; klao@1067: if( assertion ) klao@1067: cerr << " (assertion '" << assertion << "' failed)"; klao@1067: cerr << endl; klao@1067: if(do_abort) klao@1067: abort(); klao@1067: } klao@1056: klao@1067: inline klao@1067: void assert_fail_throw(const char *file, int line, const char *func, klao@1067: const char *message, const char *assertion = 0, klao@1067: bool = true) klao@1067: { klao@1067: throw AssertionFailedError(file, line, func, message, assertion); klao@1067: } klao@1056: alpar@883: alpar@883: } alpar@921: #endif // LEMON_ERROR_H klao@1067: klao@1067: #undef LEMON_ASSERT klao@1067: #undef LEMON_FIXME klao@1067: klao@1067: #ifndef LEMON_ASSERT_ABORT klao@1067: # define LEMON_ASSERT_ABORT 1 klao@1067: #endif klao@1067: klao@1067: #ifndef LEMON_ASSERT_HANDLER klao@1120: # ifdef LEMON_ASSERT_EXCEPTION klao@1120: # define LEMON_ASSERT_HANDLER ::lemon::assert_fail_throw klao@1120: # else klao@1120: # define LEMON_ASSERT_HANDLER ::lemon::assert_fail klao@1120: # endif klao@1067: #endif klao@1067: klao@1067: #if defined(NDEBUG) || defined(LEMON_DISABLE_ASSERTS) klao@1067: klao@1067: # define LEMON_ASSERT(exp, msg) (static_cast (0)) klao@1067: klao@1067: #else klao@1067: klao@1067: /** klao@1067: * \brief Macro for assertions with customizable message klao@1067: * klao@1120: * Macro for assertions with customizable message. klao@1120: * klao@1120: * The behaviour can be customized with LEMON_ASSERT_HANDLER, klao@1120: * LEMON_ASSERT_EXCEPTION and LEMON_ASSERT_ABORT defines. Asserts can be klao@1120: * disabled by defining either NDEBUG or LEMON_DISABLE_ASSERTS macros. klao@1120: * klao@1120: * \todo We should provide some way to reset to the default behaviour, klao@1120: * shouldn't we? klao@1120: * klao@1120: * \todo This whole 'assert' business should be placed in a separate klao@1120: * include file. klao@1120: * klao@1067: * \todo __PRETTY_FUNCTION__ should be replaced by something klao@1067: * compiler-independant, like BOOST_CURRENT_FUNCTION klao@1067: */ klao@1067: klao@1067: # define LEMON_ASSERT(exp, msg) \ klao@1067: (static_cast (!!(exp) ? 0 : ( \ klao@1067: LEMON_ASSERT_HANDLER(__FILE__, __LINE__, \ klao@1067: __PRETTY_FUNCTION__, \ klao@1067: (msg), #exp, LEMON_ASSERT_ABORT), 0))) klao@1067: klao@1120: #endif // NDEBUG || LEMON_DISABLE_ASSERTS klao@1067: klao@1067: /** klao@1067: * \brief Macro for mark not yet implemented features. klao@1067: * klao@1067: * \todo Is this the right place for this? It should be used only in klao@1067: * modules under development. klao@1067: * klao@1067: * \todo __PRETTY_FUNCTION__ should be replaced by something klao@1067: * compiler-independant, like BOOST_CURRENT_FUNCTION klao@1067: */ klao@1067: klao@1067: # define LEMON_FIXME(msg) \ klao@1067: (LEMON_ASSERT_HANDLER(__FILE__, __LINE__, __PRETTY_FUNCTION__, \ klao@1067: "FIXME: " msg))