/* -*- C++ -*- * src/lemon/error.h - Part of LEMON, a generic C++ optimization library * * Copyright (C) 2004 Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Combinatorial Optimization Research Group, EGRES). * * Permission to use, modify and distribute this software is granted * provided that this copyright notice appears in all copies. For * precise terms see the accompanying LICENSE file. * * This software is provided "AS IS" with no warranty of any kind, * express or implied, and with no claim as to its suitability for any * purpose. * */ #ifndef LEMON_ERROR_H #define LEMON_ERROR_H //! \ingroup misc //! \file //! \brief Basic exception classes and error handling. #include #include #include #include #include #include namespace lemon { /// Exception-safe convenient "error message" class. /// Helper class which provides a convenient ostream-like (operator << /// based) interface to create a string message. Mostly useful in /// exception classes (therefore the name). class ErrorMessage { protected: ///\e boost::shared_ptr buf; ///\e bool init() throw() { try { buf.reset(new std::ostringstream); } catch(...) { buf.reset(); } return buf; } public: ///\e ErrorMessage() throw() { init(); } ///\e ErrorMessage(const char *message) throw() { init(); *this << message; } ///\e ErrorMessage(const std::string &message) throw() { init(); *this << message; } ///\e template ErrorMessage& operator<<(const T &t) throw() { if( !buf ) return *this; try { *buf << t; } catch(...) { buf.reset(); } } ///\e const char* message() throw() { if( !buf ) return 0; const char* mes = 0; try { mes = buf->str().c_str(); } catch(...) {} return mes; } }; /** * \brief Generic exception class. * * Base class for exceptions used in LEMON. */ class Exception : public std::exception { protected: ///\e const char *message; public: ///\e Exception() throw() : message(0) {} ///\e explicit Exception(const char *msg) throw() : message(msg) {} ///\e virtual ~Exception() throw() {} ///\e virtual const char* what() const throw() { if( message ) return message; return "lemon::Exception"; } }; ///\e class LogicError : public Exception { public: ///\e explicit LogicError() {} ///\e explicit LogicError(const char *s) : Exception(s) {} }; ///\e class RuntimeError : public Exception { public: ///\e explicit RuntimeError() {} ///\e explicit RuntimeError(const char *s) : Exception(s) {} }; ///\e class RangeError : public RuntimeError { public: ///\e explicit RangeError(const char *s) : RuntimeError(s) {} }; ///\e class IOError : public RuntimeError { public: ///\e explicit IOError(const char *s) : RuntimeError(s) {} }; ///\e class DataFormatError : public IOError { protected: int line; boost::shared_ptr file; public: ///\e explicit DataFormatError(const char *message) : IOError(message), line(0) {} ///\e DataFormatError(const std::string &file_name, int line_num, const char *message) : IOError(message), line(line_num) { set_file(file_name); } ///\e void set_line(int line_num) { line=line_num; } ///\e void set_file(const std::string &file_name) { try { file.reset(new std::string); *file = file_name; } catch(...) { file.reset(); } } ///\e int get_line() const { return line; } /// \brief Returns the filename. /// /// Returns \e "(unknown)" if the filename was not specified. const char* get_file() const { if( file ) return file->c_str(); else return "(unknown)"; } ///\e virtual const char* what() const throw() { const char *mes = 0; try { std::ostringstream ostr; ostr << IOError::what(); if( file || line ) { ostr << " ("; if( file ) ostr << "in file '" << *file << "'"; if( file && line ) ostr << " "; if( line ) ostr << "at line " << line; ostr << ")"; } mes = ostr.str().c_str(); } catch(...) {} if( mes ) return mes; return "lemon::DataFormatError"; } virtual ~DataFormatError() throw() {} }; ///\e class AssertionFailedError : public LogicError { protected: const char *assertion; const char *file; int line; const char *function; const char *message; public: ///\e AssertionFailedError(const char *_file, int _line, const char *func, const char *msg, const char *_assertion = 0) : assertion(_assertion), file(_file), line(_line), function(func), message(msg) {} ///\e const char* get_assertion() const { return assertion; } ///\e const char* get_message() const { return message; } ///\e const char* get_file() const { return file; } ///\e const char* get_function() const { return function; } ///\e int get_line() const { return line; } virtual const char* what() const throw() { const char *mes = 0; try { std::ostringstream ostr; ostr << file << ":" << line << ": "; if( function ) ostr << function << ": "; ostr << message; if( assertion ) ostr << " (assertion '" << assertion << "' failed)"; mes = ostr.str().c_str(); } catch(...) {} if( mes ) return mes; return "lemon::AssertionFailedError"; } virtual ~AssertionFailedError() throw() {} }; /**************** Macros ****************/ inline void assert_fail(const char *file, int line, const char *func, const char *message, const char *assertion = 0, bool do_abort=true) { using namespace std; cerr << file << ":" << line << ": "; if( func ) cerr << func << ": "; cerr << message; if( assertion ) cerr << " (assertion '" << assertion << "' failed)"; cerr << endl; if(do_abort) abort(); } inline void assert_fail_throw(const char *file, int line, const char *func, const char *message, const char *assertion = 0, bool = true) { throw AssertionFailedError(file, line, func, message, assertion); } } #endif // LEMON_ERROR_H #undef LEMON_ASSERT #undef LEMON_FIXME #ifndef LEMON_ASSERT_ABORT # define LEMON_ASSERT_ABORT 1 #endif #ifndef LEMON_ASSERT_HANDLER # define LEMON_ASSERT_HANDLER ::lemon::assert_fail #endif #if defined(NDEBUG) || defined(LEMON_DISABLE_ASSERTS) # define LEMON_ASSERT(exp, msg) (static_cast (0)) #else /** * \brief Macro for assertions with customizable message * * \todo __PRETTY_FUNCTION__ should be replaced by something * compiler-independant, like BOOST_CURRENT_FUNCTION */ # define LEMON_ASSERT(exp, msg) \ (static_cast (!!(exp) ? 0 : ( \ LEMON_ASSERT_HANDLER(__FILE__, __LINE__, \ __PRETTY_FUNCTION__, \ (msg), #exp, LEMON_ASSERT_ABORT), 0))) # endif // NDEBUG /** * \brief Macro for mark not yet implemented features. * * \todo Is this the right place for this? It should be used only in * modules under development. * * \todo __PRETTY_FUNCTION__ should be replaced by something * compiler-independant, like BOOST_CURRENT_FUNCTION */ # define LEMON_FIXME(msg) \ (LEMON_ASSERT_HANDLER(__FILE__, __LINE__, __PRETTY_FUNCTION__, \ "FIXME: " msg))