kpeter@66: /* -*- C++ -*- kpeter@66: * kpeter@66: * This file is a part of LEMON, a generic C++ optimization library kpeter@66: * kpeter@66: * Copyright (C) 2003-2008 kpeter@66: * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport kpeter@66: * (Egervary Research Group on Combinatorial Optimization, EGRES). kpeter@66: * kpeter@66: * Permission to use, modify and distribute this software is granted kpeter@66: * provided that this copyright notice appears in all copies. For kpeter@66: * precise terms see the accompanying LICENSE file. kpeter@66: * kpeter@66: * This software is provided "AS IS" with no warranty of any kind, kpeter@66: * express or implied, and with no claim as to its suitability for any kpeter@66: * purpose. kpeter@66: * kpeter@66: */ kpeter@66: kpeter@66: #ifndef LEMON_ERROR_H kpeter@66: #define LEMON_ERROR_H kpeter@66: kpeter@66: /// \ingroup exceptions kpeter@66: /// \file kpeter@66: /// \brief Basic exception classes and error handling. kpeter@66: kpeter@66: #include kpeter@66: #include kpeter@66: #include kpeter@66: #include kpeter@66: #include kpeter@66: #include kpeter@66: kpeter@66: namespace lemon { kpeter@66: kpeter@66: /// \addtogroup exceptions kpeter@66: /// @{ kpeter@66: kpeter@66: /// \brief Exception safe wrapper class. kpeter@66: /// kpeter@66: /// Exception safe wrapper class to implement the members of exceptions. kpeter@66: template kpeter@66: class ExceptionMember { kpeter@66: public: kpeter@66: typedef _Type Type; kpeter@66: kpeter@66: ExceptionMember() throw() { kpeter@66: try { kpeter@66: ptr.reset(new Type()); kpeter@66: } catch (...) {} kpeter@66: } kpeter@66: kpeter@66: ExceptionMember(const Type& type) throw() { kpeter@66: try { kpeter@66: ptr.reset(new Type()); kpeter@66: if (ptr.get() == 0) return; kpeter@66: *ptr = type; kpeter@66: } catch (...) {} kpeter@66: } kpeter@66: kpeter@66: ExceptionMember(const ExceptionMember& copy) throw() { kpeter@66: try { kpeter@66: if (!copy.valid()) return; kpeter@66: ptr.reset(new Type()); kpeter@66: if (ptr.get() == 0) return; kpeter@66: *ptr = copy.get(); kpeter@66: } catch (...) {} kpeter@66: } kpeter@66: kpeter@66: ExceptionMember& operator=(const ExceptionMember& copy) throw() { kpeter@66: if (ptr.get() == 0) return; kpeter@66: try { kpeter@66: if (!copy.valid()) return; kpeter@66: *ptr = copy.get(); kpeter@66: } catch (...) {} kpeter@66: } kpeter@66: kpeter@66: void set(const Type& type) throw() { kpeter@66: if (ptr.get() == 0) return; kpeter@66: try { kpeter@66: *ptr = type; kpeter@66: } catch (...) {} kpeter@66: } kpeter@66: kpeter@66: const Type& get() const { kpeter@66: return *ptr; kpeter@66: } kpeter@66: kpeter@66: bool valid() const throw() { kpeter@66: return ptr.get() != 0; kpeter@66: } kpeter@66: kpeter@66: private: kpeter@66: std::auto_ptr<_Type> ptr; kpeter@66: }; kpeter@66: deba@108: /// Exception-safe convenient error message builder class. kpeter@66: kpeter@66: /// Helper class which provides a convenient ostream-like (operator << kpeter@66: /// based) interface to create a string message. Mostly useful in kpeter@66: /// exception classes (therefore the name). kpeter@66: class ErrorMessage { kpeter@66: protected: kpeter@66: ///\e kpeter@66: kpeter@66: ///\todo The good solution is boost::shared_ptr... kpeter@66: /// kpeter@66: mutable std::auto_ptr buf; kpeter@66: kpeter@66: ///\e kpeter@66: bool init() throw() { kpeter@66: try { kpeter@66: buf.reset(new std::ostringstream); kpeter@66: } kpeter@66: catch(...) { kpeter@66: buf.reset(); kpeter@66: } kpeter@66: return buf.get(); kpeter@66: } kpeter@66: kpeter@66: public: kpeter@66: kpeter@66: ///\e kpeter@66: ErrorMessage() throw() { init(); } kpeter@66: kpeter@66: ErrorMessage(const ErrorMessage& em) throw() : buf(em.buf) { } kpeter@66: kpeter@66: ///\e kpeter@66: ErrorMessage(const char *msg) throw() { kpeter@66: init(); kpeter@66: *this << msg; kpeter@66: } kpeter@66: kpeter@66: ///\e kpeter@66: ErrorMessage(const std::string &msg) throw() { kpeter@66: init(); kpeter@66: *this << msg; kpeter@66: } kpeter@66: kpeter@66: ///\e kpeter@66: template kpeter@66: ErrorMessage& operator<<(const T &t) throw() { kpeter@66: if( ! buf.get() ) return *this; kpeter@66: kpeter@66: try { kpeter@66: *buf << t; kpeter@66: } kpeter@66: catch(...) { kpeter@66: buf.reset(); kpeter@66: } kpeter@66: return *this; kpeter@66: } kpeter@66: kpeter@66: ///\e kpeter@66: const char* message() throw() { kpeter@66: if( ! buf.get() ) return 0; kpeter@66: kpeter@66: const char* mes = 0; kpeter@66: try { kpeter@66: mes = buf->str().c_str(); kpeter@66: } kpeter@66: catch(...) {} kpeter@66: return mes; kpeter@66: } kpeter@66: kpeter@66: }; kpeter@66: kpeter@66: /// Generic exception class. kpeter@66: kpeter@66: /// Base class for exceptions used in LEMON. kpeter@66: /// kpeter@66: class Exception : public std::exception { kpeter@66: public: kpeter@66: ///\e kpeter@66: Exception() {} kpeter@66: ///\e kpeter@66: virtual ~Exception() throw() {} kpeter@66: ///\e kpeter@66: virtual const char* what() const throw() { kpeter@66: return "lemon::Exception"; kpeter@66: } kpeter@66: }; kpeter@66: kpeter@66: /// One of the two main subclasses of \ref Exception. kpeter@66: kpeter@66: /// Logic errors represent problems in the internal logic of a program; kpeter@66: /// in theory, these are preventable, and even detectable before the kpeter@66: /// program runs (e.g. violations of class invariants). kpeter@66: /// kpeter@66: /// A typical example for this is \ref UninitializedParameter. kpeter@66: class LogicError : public Exception { kpeter@66: public: kpeter@66: virtual const char* what() const throw() { kpeter@66: return "lemon::LogicError"; kpeter@66: } kpeter@66: }; kpeter@66: kpeter@66: /// \ref Exception for uninitialized parameters. kpeter@66: kpeter@66: /// This error represents problems in the initialization kpeter@66: /// of the parameters of the algorithms. kpeter@66: class UninitializedParameter : public LogicError { kpeter@66: public: kpeter@66: virtual const char* what() const throw() { kpeter@66: return "lemon::UninitializedParameter"; kpeter@66: } kpeter@66: }; kpeter@66: kpeter@66: kpeter@66: /// One of the two main subclasses of \ref Exception. kpeter@66: kpeter@66: /// Runtime errors represent problems outside the scope of a program; kpeter@66: /// they cannot be easily predicted and can generally only be caught kpeter@66: /// as the program executes. kpeter@66: class RuntimeError : public Exception { kpeter@66: public: kpeter@66: virtual const char* what() const throw() { kpeter@66: return "lemon::RuntimeError"; kpeter@66: } kpeter@66: }; kpeter@66: kpeter@66: ///\e kpeter@66: class RangeError : public RuntimeError { kpeter@66: public: kpeter@66: virtual const char* what() const throw() { kpeter@66: return "lemon::RangeError"; kpeter@66: } kpeter@66: }; kpeter@66: kpeter@66: ///\e kpeter@66: class IoError : public RuntimeError { kpeter@66: public: kpeter@66: virtual const char* what() const throw() { kpeter@66: return "lemon::IoError"; kpeter@66: } kpeter@66: }; kpeter@66: kpeter@66: ///\e kpeter@66: class DataFormatError : public IoError { kpeter@66: protected: kpeter@66: ExceptionMember _message; kpeter@66: ExceptionMember _file; kpeter@66: int _line; kpeter@66: kpeter@66: mutable ExceptionMember _message_holder; kpeter@66: public: kpeter@66: kpeter@66: DataFormatError(const DataFormatError &dfe) : kpeter@66: IoError(dfe), _message(dfe._message), _file(dfe._file), kpeter@66: _line(dfe._line) {} kpeter@66: kpeter@66: ///\e kpeter@66: explicit DataFormatError(const char *the_message) kpeter@66: : _message(the_message), _line(0) {} kpeter@66: kpeter@66: ///\e kpeter@66: DataFormatError(const std::string &file_name, int line_num, kpeter@66: const char *the_message) kpeter@66: : _message(the_message), _line(line_num) { file(file_name); } kpeter@66: kpeter@66: ///\e kpeter@66: void line(int ln) { _line = ln; } kpeter@66: ///\e kpeter@66: void message(const std::string& msg) { _message.set(msg); } kpeter@66: ///\e kpeter@66: void file(const std::string &fl) { _file.set(fl); } kpeter@66: kpeter@66: ///\e kpeter@66: int line() const { return _line; } kpeter@66: ///\e kpeter@66: const char* message() const { kpeter@66: if (_message.valid() && !_message.get().empty()) { kpeter@66: return _message.get().c_str(); kpeter@66: } else { kpeter@66: return 0; kpeter@66: } kpeter@66: } kpeter@66: kpeter@66: /// \brief Returns the filename. kpeter@66: /// kpeter@66: /// Returns \e null if the filename was not specified. kpeter@66: const char* file() const { kpeter@66: if (_file.valid() && !_file.get().empty()) { kpeter@66: return _file.get().c_str(); kpeter@66: } else { kpeter@66: return 0; kpeter@66: } kpeter@66: } kpeter@66: kpeter@66: ///\e kpeter@66: virtual const char* what() const throw() { kpeter@66: try { kpeter@66: std::ostringstream ostr; kpeter@66: ostr << "lemon:DataFormatError" << ": "; kpeter@66: if (message()) ostr << message(); kpeter@66: if( file() || line() != 0 ) { kpeter@66: ostr << " ("; kpeter@66: if( file() ) ostr << "in file '" << file() << "'"; kpeter@66: if( file() && line() != 0 ) ostr << " "; kpeter@66: if( line() != 0 ) ostr << "at line " << line(); kpeter@66: ostr << ")"; kpeter@66: } kpeter@66: _message_holder.set(ostr.str()); kpeter@66: } kpeter@66: catch (...) {} kpeter@66: if( _message_holder.valid()) return _message_holder.get().c_str(); kpeter@66: return "lemon:DataFormatError"; kpeter@66: } kpeter@66: kpeter@66: virtual ~DataFormatError() throw() {} kpeter@66: }; kpeter@66: kpeter@66: ///\e kpeter@66: class FileOpenError : public IoError { kpeter@66: protected: kpeter@66: ExceptionMember _file; kpeter@66: kpeter@66: mutable ExceptionMember _message_holder; kpeter@66: public: kpeter@66: kpeter@66: FileOpenError(const FileOpenError &foe) : kpeter@66: IoError(foe), _file(foe._file) {} kpeter@66: kpeter@66: ///\e kpeter@66: explicit FileOpenError(const std::string& fl) kpeter@66: : _file(fl) {} kpeter@66: kpeter@66: kpeter@66: ///\e kpeter@66: void file(const std::string &fl) { _file.set(fl); } kpeter@66: kpeter@66: /// \brief Returns the filename. kpeter@66: /// kpeter@66: /// Returns \e null if the filename was not specified. kpeter@66: const char* file() const { kpeter@66: if (_file.valid() && !_file.get().empty()) { kpeter@66: return _file.get().c_str(); kpeter@66: } else { kpeter@66: return 0; kpeter@66: } kpeter@66: } kpeter@66: kpeter@66: ///\e kpeter@66: virtual const char* what() const throw() { kpeter@66: try { kpeter@66: std::ostringstream ostr; kpeter@66: ostr << "lemon::FileOpenError" << ": "; kpeter@66: ostr << "Cannot open file - " << file(); kpeter@66: _message_holder.set(ostr.str()); kpeter@66: } kpeter@66: catch (...) {} kpeter@66: if( _message_holder.valid()) return _message_holder.get().c_str(); kpeter@66: return "lemon::FileOpenError"; kpeter@66: } kpeter@66: virtual ~FileOpenError() throw() {} kpeter@66: }; kpeter@66: kpeter@66: class IoParameterError : public IoError { kpeter@66: protected: kpeter@66: ExceptionMember _message; kpeter@66: ExceptionMember _file; kpeter@66: kpeter@66: mutable ExceptionMember _message_holder; kpeter@66: public: kpeter@66: kpeter@66: IoParameterError(const IoParameterError &ile) : kpeter@66: IoError(ile), _message(ile._message), _file(ile._file) {} kpeter@66: kpeter@66: ///\e kpeter@66: explicit IoParameterError(const char *the_message) kpeter@66: : _message(the_message) {} kpeter@66: kpeter@66: ///\e kpeter@66: IoParameterError(const char *file_name, const char *the_message) kpeter@66: : _message(the_message), _file(file_name) {} kpeter@66: kpeter@66: ///\e kpeter@66: void message(const std::string& msg) { _message.set(msg); } kpeter@66: ///\e kpeter@66: void file(const std::string &fl) { _file.set(fl); } kpeter@66: kpeter@66: ///\e kpeter@66: const char* message() const { kpeter@66: if (_message.valid()) { kpeter@66: return _message.get().c_str(); kpeter@66: } else { kpeter@66: return 0; kpeter@66: } kpeter@66: } kpeter@66: kpeter@66: /// \brief Returns the filename. kpeter@66: /// kpeter@66: /// Returns \c 0 if the filename was not specified. kpeter@66: const char* file() const { kpeter@66: if (_file.valid()) { kpeter@66: return _file.get().c_str(); kpeter@66: } else { kpeter@66: return 0; kpeter@66: } kpeter@66: } kpeter@66: kpeter@66: ///\e kpeter@66: virtual const char* what() const throw() { kpeter@66: try { kpeter@66: std::ostringstream ostr; kpeter@66: if (message()) ostr << message(); kpeter@66: if (file()) ostr << "(when reading file '" << file() << "')"; kpeter@66: _message_holder.set(ostr.str()); kpeter@66: } kpeter@66: catch (...) {} kpeter@66: if( _message_holder.valid() ) return _message_holder.get().c_str(); kpeter@66: return "lemon:IoParameterError"; kpeter@66: } kpeter@66: virtual ~IoParameterError() throw() {} kpeter@66: }; kpeter@66: deba@108: /// @} kpeter@66: kpeter@66: } deba@108: kpeter@66: #endif // LEMON_ERROR_H