# HG changeset patch # User klao # Date 1105313298 0 # Node ID 47939f501c810971074b3cde06092f471ca6f42d # Parent 520769d825f277b8b56b2990a946b56c85263c1f Advances in error.h * More clear exception usage concept * sketch of LEMON_ASSERT interface * test file diff -r 520769d825f2 -r 47939f501c81 src/work/klao/Makefile --- a/src/work/klao/Makefile Sun Jan 09 23:21:52 2005 +0000 +++ b/src/work/klao/Makefile Sun Jan 09 23:28:18 2005 +0000 @@ -1,4 +1,5 @@ -BINARIES = tag_demo +BINARIES = error_test INCLUDEDIRS= -I. -I.. -I../.. -I../{marci,jacint,alpar,johanna,athos,akos} -I$(HOME)/boost include ../makefile +CXXFLAGS += $(C) diff -r 520769d825f2 -r 47939f501c81 src/work/klao/error.h --- a/src/work/klao/error.h Sun Jan 09 23:21:52 2005 +0000 +++ b/src/work/klao/error.h Sun Jan 09 23:28:18 2005 +0000 @@ -19,23 +19,29 @@ //! \ingroup misc //! \file -//! \brief Basic error handling (signaling) routines. +//! \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 + ///\e boost::shared_ptr buf; - ///\e + ///\e bool init() throw() { try { buf.reset(new std::ostringstream); @@ -48,22 +54,22 @@ public: - ///\e + ///\e ErrorMessage() throw() { init(); } - ///\e + ///\e ErrorMessage(const char *message) throw() { init(); *this << message; } - ///\e + ///\e ErrorMessage(const std::string &message) throw() { init(); *this << message; } - ///\e + ///\e template ErrorMessage& operator<<(const T &t) throw() { if( !buf ) return *this; @@ -76,7 +82,7 @@ } } - ///\e + ///\e const char* message() throw() { if( !buf ) return 0; @@ -95,65 +101,81 @@ * * Base class for exceptions used in LEMON. */ - class Exception : public std::exception, public ErrorMessage { + class Exception : public std::exception { + protected: + ///\e + const char *message; + public: - ///\e - Exception() throw() {} - ///\e - explicit Exception(const std::string &s) throw() - : ErrorMessage(s) {} - ///\e + ///\e + Exception() throw() : message(0) {} + ///\e + explicit Exception(const char *msg) throw() + : message(msg) {} + ///\e virtual ~Exception() throw() {} - ///\e + ///\e virtual const char* what() const throw() { - const char *mes = message(); - if( mes ) return mes; + if( message ) return message; return "lemon::Exception"; } }; ///\e class LogicError : public Exception { - ///\e - explicit LogicError(const std::string &s) + public: + ///\e + explicit LogicError() {} + ///\e + explicit LogicError(const char *s) : Exception(s) {} }; ///\e class RuntimeError : public Exception { - ///\e - explicit RuntimeError(const std::string &s) + public: + ///\e + explicit RuntimeError() {} + ///\e + explicit RuntimeError(const char *s) : Exception(s) {} }; - ///\e + ///\e class RangeError : public RuntimeError { - ///\e - explicit RangeError(const std::string &s) + public: + ///\e + explicit RangeError(const char *s) : RuntimeError(s) {} }; ///\e class IOError : public RuntimeError { - ///\e - explicit IOError(const std::string &s) + public: + ///\e + explicit IOError(const char *s) : RuntimeError(s) {} }; ///\e class DataFormatError : public IOError { - ///\e - explicit DataFormatError(const std::string &message) - : IOError(message) : line(0) {} - ///\e + 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 std::string &message) + const char *message) : IOError(message), line(line_num) { set_file(file_name); } - ///\e + ///\e void set_line(int line_num) { line=line_num; } - ///\e + ///\e void set_file(const std::string &file_name) { try { file.reset(new std::string); @@ -164,16 +186,31 @@ } } - ///\e - virtual const char* what() const { + ///\e + int get_line() const { return line; } + + /// \brief Returns the filename. + /// + /// Returns "(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( line ) ostr << " at line" << line; + if( file ) ostr << "in file '" << *file << "'"; + if( file && line ) ostr << " "; + if( line ) ostr << "at line " << line; + ostr << ")"; } mes = ostr.str().c_str(); } @@ -181,32 +218,132 @@ if( mes ) return mes; return "lemon::DataFormatError"; } + + virtual ~DataFormatError() throw() {} }; + 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 ****************/ - /** - * \brief Macro for assertions with customizable message - */ + 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(); + } -# define lemon_assert(exp, msg) \ - if(!(exp)) { \ - std::cerr << __FILE__ ":" << __LINE__ << ": " << (msg) << std::endl; \ - 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); + } - /** - * \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. - */ - -# define FIXME(msg) lemon_assert(0, "FIXME: " msg) - } #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)) diff -r 520769d825f2 -r 47939f501c81 src/work/klao/error_test.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/work/klao/error_test.cc Sun Jan 09 23:28:18 2005 +0000 @@ -0,0 +1,57 @@ +#include +#include + +#define LEMON_ASSERT_ABORT 0 +#include + +using namespace std; + +void parse_line() { + throw lemon::DataFormatError("Syntax error"); +} + +void parse_file(string fn) { + try { + parse_line(); + } + catch(lemon::DataFormatError &e) { + e.set_file(fn); + e.set_line(5); + throw; + } +} + +void fail_assert(); + +int main() { + try { + parse_file("input.txt"); + } + catch(exception &e) { + cerr << "Exception caught: " << endl; + cerr << e.what() << endl; + } + + try { + fail_assert(); + } + catch(exception &e) { + cerr << "Exception caught: " << endl; + cerr << e.what() << endl; + } + + // assert(1==0); + LEMON_ASSERT(1==0, "Ellentmondas"); + LEMON_FIXME("Nincs kesz"); +} + +#undef LEMON_ASSERT_HANDLER +#define LEMON_ASSERT_HANDLER ::lemon::assert_fail_throw + +#include + +void fail_assert() { + LEMON_ASSERT(2*2==5, "Marson vagyunk"); +} + + diff -r 520769d825f2 -r 47939f501c81 src/work/makefile --- a/src/work/makefile Sun Jan 09 23:21:52 2005 +0000 +++ b/src/work/makefile Sun Jan 09 23:28:18 2005 +0000 @@ -1,5 +1,5 @@ INCLUDEDIRS ?= -I.. -I. -I./{marci,jacint,alpar,klao,akos} -CXXFLAGS = -g -O3 -W -Wall $(INCLUDEDIRS) -ansi -pedantic +CXXFLAGS += -g -O2 -W -Wall $(INCLUDEDIRS) -ansi -pedantic BINARIES ?= bin_heap_demo