diff -r d8475431bbbb -r 8e85e6bbefdf lemon/error.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lemon/error.h Mon May 23 04:48:14 2005 +0000 @@ -0,0 +1,539 @@ +/* -*- C++ -*- + * lemon/error.h - Part of LEMON, a generic C++ optimization library + * + * Copyright (C) 2005 Egervary Jeno Kombinatorikus Optimalizalasi + * Kutatocsoport (Egervary Research Group on Combinatorial Optimization, + * 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 exceptions +//! \file +//! \brief Basic exception classes and error handling. + +#include +#include +#include +#include +#include +#include + +namespace lemon { + + /// \addtogroup exceptions + /// @{ + + /// \brief Exception safe wrapper class. + /// + /// Exception safe wrapper class to implement the members of exceptions. + template + class ExceptionMember { + public: + typedef _Type Type; + + ExceptionMember() throw () { + try { + ptr.reset(new Type()); + } catch (...) {} + } + + ExceptionMember(const Type& type) throw () { + try { + ptr.reset(new Type()); + if (ptr.get() == 0) return; + *ptr = type; + } catch (...) {} + } + + ExceptionMember(const ExceptionMember& copy) throw() { + try { + if (!copy.valid()) return; + ptr.reset(new Type()); + if (ptr.get() == 0) return; + *ptr = copy.get(); + } catch (...) {} + } + + ExceptionMember& operator=(const ExceptionMember& copy) { + if (ptr.get() == 0) return; + try { + if (!copy.valid()) return; + *ptr = copy.get(); + } catch (...) {} + } + + void set(const Type& type) { + if (ptr.get() == 0) return; + try { + *ptr = type; + } catch (...) {} + } + + const Type& get() const { + return *ptr; + } + + bool valid() const { + return ptr.get() != 0; + } + + private: + std::auto_ptr<_Type> ptr; + }; + + /// 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 + ///\todo The good solution is boost:shared_ptr... + mutable + std::auto_ptr buf; + + ///\e + bool init() throw() { + try { + buf.reset(new std::ostringstream); + } + catch(...) { + buf.reset(); + } + return buf.get(); + } + + public: + + ///\e + ErrorMessage() throw() { init(); } + + ErrorMessage(const ErrorMessage& em) throw() : buf(em.buf) { } + + ///\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.get() ) return *this; + + try { + *buf << t; + } + catch(...) { + buf.reset(); + } + return *this; + } + + ///\e + const char* message() throw() { + if( ! buf.get() ) 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 { + public: + ///\e + Exception() {} + ///\e + virtual ~Exception() throw() {} + + ///\e + virtual const char* exceptionName() const { + return "lemon::Exception"; + } + + ///\e + virtual const char* what() const throw() { + return exceptionName(); + } + }; + + /** + * \brief One of the two main subclasses of \ref Exception. + * + * Logic errors represent problems in the internal logic of a program; + * in theory, these are preventable, and even detectable before the + * program runs (e.g., violations of class invariants). + * + * A typical example for this is \ref UninitializedParameter. + */ + class LogicError : public Exception { + public: + virtual const char* exceptionName() const { + return "lemon::LogicError"; + } + }; + + /** + * \brief \ref Exception for uninitialized parameters. + * + * This error represents problems in the initialization + * of the parameters of the algorithms. + */ + class UninitializedParameter : public LogicError { + public: + virtual const char* exceptionName() const { + return "lemon::UninitializedParameter"; + } + }; + + + /** + * \brief One of the two main subclasses of \ref Exception. + * + * Runtime errors represent problems outside the scope of a program; + * they cannot be easily predicted and can generally only be caught as + * the program executes. + */ + class RuntimeError : public Exception { + public: + virtual const char* exceptionName() const { + return "lemon::RuntimeError"; + } + }; + + ///\e + class RangeError : public RuntimeError { + public: + virtual const char* exceptionName() const { + return "lemon::RangeError"; + } + }; + + ///\e + class IOError : public RuntimeError { + public: + virtual const char* exceptionName() const { + return "lemon::IOError"; + } + }; + + ///\e + class DataFormatError : public IOError { + protected: + ExceptionMember _message; + ExceptionMember _file; + int _line; + + mutable ExceptionMember _message_holder; + public: + + DataFormatError(const DataFormatError &dfe) : + IOError(dfe), _message(dfe._message), _file(dfe._file), + _line(dfe._line) {} + + ///\e + explicit DataFormatError(const char *the_message) + : _message(the_message), _line(0) {} + + ///\e + DataFormatError(const std::string &file_name, int line_num, + const char *the_message) + : _message(the_message), _line(line_num) { file(file_name); } + + ///\e + void line(int line) { _line = line; } + ///\e + void message(const std::string& message) { _message.set(message); } + ///\e + void file(const std::string &file) { _file.set(file); } + + ///\e + int line() const { return _line; } + ///\e + const char* message() const { + if (_message.valid() && !_message.get().empty()) { + return _message.get().c_str(); + } else { + return 0; + } + } + + /// \brief Returns the filename. + /// + /// Returns \e null if the filename was not specified. + const char* file() const { + if (_file.valid() && !_file.get().empty()) { + return _file.get().c_str(); + } else { + return 0; + } + } + + ///\e + virtual const char* what() const throw() { + try { + std::ostringstream ostr; + ostr << exceptionName() << ": "; + if (message()) ostr << message(); + if( file() || line() != 0 ) { + ostr << " ("; + if( file() ) ostr << "in file '" << file() << "'"; + if( file() && line() != 0 ) ostr << " "; + if( line() != 0 ) ostr << "at line " << line(); + ostr << ")"; + } + _message_holder.set(ostr.str()); + } + catch (...) {} + if( _message_holder.valid()) return _message_holder.get().c_str(); + return exceptionName(); + } + + virtual const char* exceptionName() const { + return "lemon::DataFormatError"; + } + + virtual ~DataFormatError() throw() {} + }; + + class IOParameterError : public LogicError { + protected: + ExceptionMember _message; + ExceptionMember _file; + + mutable ExceptionMember _message_holder; + public: + + IOParameterError(const IOParameterError &ile) : + LogicError(ile), _message(ile._message), _file(ile._file) {} + + ///\e + explicit IOParameterError(const char *the_message) + : _message(the_message) {} + + ///\e + IOParameterError(const char *file_name, const char *the_message) + : _message(the_message), _file(file_name) {} + + ///\e + void message(const std::string& message) { _message.set(message); } + ///\e + void file(const std::string &file) { _file.set(file); } + + ///\e + const char* message() const { + if (_message.valid()) { + return _message.get().c_str(); + } else { + return 0; + } + } + + /// \brief Returns the filename. + /// + /// Returns \e null if the filename was not specified. + const char* file() const { + if (_file.valid()) { + return _file.get().c_str(); + } else { + return 0; + } + } + + ///\e + virtual const char* what() const throw() { + try { + std::ostringstream ostr; + if (message()) ostr << message(); + if (file()) ostr << "(when reading file '" << file() << "')"; + _message_holder.set(ostr.str()); + } + catch (...) {} + if( _message_holder.valid() ) return _message_holder.get().c_str(); + return exceptionName(); + } + + virtual const char* exceptionName() const { + return "lemon::IOParameterError"; + } + + virtual ~IOParameterError() throw() {} + }; + + + ///\e + class AssertionFailedError : public LogicError { + protected: + const char *assertion; + const char *file; + int line; + const char *function; + const char *message; + + mutable ExceptionMember _message_holder; + 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() { + try { + std::ostringstream ostr; + ostr << file << ":" << line << ": "; + if( function ) + ostr << function << ": "; + ostr << message; + if( assertion ) + ostr << " (assertion '" << assertion << "' failed)"; + _message_holder.set(ostr.str()); + return ostr.str().c_str(); + } + catch(...) {} + if( _message_holder.valid() ) return _message_holder.get().c_str(); + return exceptionName(); + } + + virtual const char* exceptionName() const { + 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 +# ifdef LEMON_ASSERT_EXCEPTION +# define LEMON_ASSERT_HANDLER ::lemon::assert_fail_throw +# else +# define LEMON_ASSERT_HANDLER ::lemon::assert_fail +# endif +#endif + +#if defined(NDEBUG) || defined(LEMON_DISABLE_ASSERTS) + +# define LEMON_ASSERT(exp, msg) (static_cast (0)) + +#else + +/** + * \brief Macro for assertions with customizable message + * + * Macro for assertions with customizable message. + * + * The behaviour can be customized with LEMON_ASSERT_HANDLER, + * LEMON_ASSERT_EXCEPTION and LEMON_ASSERT_ABORT defines. Asserts can be + * disabled by defining either NDEBUG or LEMON_DISABLE_ASSERTS macros. + * + * \todo We should provide some way to reset to the default behaviour, + * shouldn't we? + * + * \todo This whole 'assert' business should be placed in a separate + * include file. + * + * \todo __PRETTY_FUNCTION__ should be replaced by something + * compiler-independent, 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 || LEMON_DISABLE_ASSERTS + +/** + * \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-independent, like BOOST_CURRENT_FUNCTION + */ + +# define LEMON_FIXME(msg) \ + (LEMON_ASSERT_HANDLER(__FILE__, __LINE__, __PRETTY_FUNCTION__, \ + "FIXME: " msg))