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 { klao@1067: protected: klao@1067: ///\e klao@1067: const char *message; klao@1067: alpar@883: public: klao@1067: ///\e klao@1067: Exception() throw() : message(0) {} klao@1067: ///\e klao@1067: explicit Exception(const char *msg) throw() klao@1067: : message(msg) {} klao@1067: ///\e alpar@883: virtual ~Exception() throw() {} alpar@883: klao@1067: ///\e alpar@883: virtual const char* what() const throw() { klao@1067: if( message ) return message; klao@1056: return "lemon::Exception"; klao@1056: } klao@1056: }; klao@1056: alpar@1061: ///\e klao@1056: class LogicError : public Exception { klao@1067: public: klao@1067: ///\e klao@1067: explicit LogicError() {} klao@1067: ///\e klao@1067: explicit LogicError(const char *s) klao@1056: : Exception(s) {} klao@1056: }; klao@1056: alpar@1061: ///\e klao@1056: class RuntimeError : public Exception { klao@1067: public: klao@1067: ///\e klao@1067: explicit RuntimeError() {} klao@1067: ///\e klao@1067: explicit RuntimeError(const char *s) klao@1056: : Exception(s) {} klao@1056: }; klao@1056: klao@1067: ///\e klao@1056: class RangeError : public RuntimeError { klao@1067: public: klao@1067: ///\e klao@1067: explicit RangeError(const char *s) klao@1056: : RuntimeError(s) {} klao@1056: }; klao@1056: alpar@1061: ///\e klao@1056: class IOError : public RuntimeError { klao@1067: public: klao@1067: ///\e klao@1067: explicit IOError(const char *s) klao@1056: : RuntimeError(s) {} klao@1056: }; klao@1056: alpar@1061: ///\e klao@1056: class DataFormatError : public IOError { klao@1067: protected: klao@1067: int line; klao@1067: boost::shared_ptr file; klao@1067: klao@1067: public: klao@1067: ///\e klao@1067: explicit DataFormatError(const char *message) klao@1067: : IOError(message), line(0) {} klao@1067: ///\e klao@1056: DataFormatError(const std::string &file_name, int line_num, klao@1067: const char *message) klao@1056: : IOError(message), line(line_num) { set_file(file_name); } klao@1056: klao@1067: ///\e klao@1056: void set_line(int line_num) { line=line_num; } klao@1067: ///\e klao@1056: void set_file(const std::string &file_name) { klao@1056: try { klao@1056: file.reset(new std::string); klao@1056: *file = file_name; klao@1056: } klao@1056: catch(...) { klao@1056: file.reset(); klao@1056: } alpar@883: } alpar@883: klao@1067: ///\e klao@1067: int get_line() const { return line; } klao@1067: klao@1067: /// \brief Returns the filename. klao@1067: /// klao@1068: /// Returns \e "(unknown)" if the filename was not specified. klao@1067: const char* get_file() const { klao@1067: if( file ) klao@1067: 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@1056: ostr << IOError::what(); klao@1056: if( file || line ) { klao@1056: ostr << " ("; klao@1067: if( file ) ostr << "in file '" << *file << "'"; klao@1067: if( file && line ) ostr << " "; klao@1067: 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@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@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@1067: # define LEMON_ASSERT_HANDLER ::lemon::assert_fail 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@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@1067: # endif // NDEBUG 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))