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: kpeter@66: /// Exception-safe convenient "error message" 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: kpeter@66: kpeter@66: ///\e kpeter@66: class AssertionFailedError : public LogicError { kpeter@66: protected: kpeter@66: const char *assertion; kpeter@66: const char *file; kpeter@66: int line; kpeter@66: const char *function; kpeter@66: const char *message; kpeter@66: kpeter@66: mutable ExceptionMember _message_holder; kpeter@66: public: kpeter@66: ///\e kpeter@66: AssertionFailedError(const char *_file, int _line, const char *func, kpeter@66: const char *msg, const char *_assertion = 0) : kpeter@66: assertion(_assertion), file(_file), line(_line), function(func), kpeter@66: message(msg) {} kpeter@66: kpeter@66: ///\e kpeter@66: const char* get_assertion() const { return assertion; } kpeter@66: ///\e kpeter@66: const char* get_message() const { return message; } kpeter@66: ///\e kpeter@66: const char* get_file() const { return file; } kpeter@66: ///\e kpeter@66: const char* get_function() const { return function; } kpeter@66: ///\e kpeter@66: int get_line() const { return line; } kpeter@66: kpeter@66: kpeter@66: virtual const char* what() const throw() { kpeter@66: try { kpeter@66: std::ostringstream ostr; kpeter@66: ostr << file << ":" << line << ": "; kpeter@66: if( function ) kpeter@66: ostr << function << ": "; kpeter@66: ostr << message; kpeter@66: if( assertion ) kpeter@66: ostr << " (assertion '" << assertion << "' failed)"; kpeter@66: _message_holder.set(ostr.str()); kpeter@66: return ostr.str().c_str(); kpeter@66: } kpeter@66: catch(...) {} kpeter@66: if( _message_holder.valid() ) return _message_holder.get().c_str(); kpeter@66: return "lemon::AssertionFailedError"; kpeter@66: } kpeter@66: virtual ~AssertionFailedError() throw() {} kpeter@66: }; kpeter@66: kpeter@66: kpeter@66: /**************** Macros ****************/ kpeter@66: kpeter@66: kpeter@66: template kpeter@66: inline void assert_fail(const char *file, int line, kpeter@66: const char *func, kpeter@66: Exception exception, kpeter@66: const char *assertion = 0, kpeter@66: bool do_abort=true) kpeter@66: { kpeter@66: using namespace std; kpeter@66: cerr << file << ":" << line << ": "; kpeter@66: if (func) kpeter@66: cerr << func << ": "; kpeter@66: cerr << exception.what(); kpeter@66: if (assertion) kpeter@66: cerr << " (assertion '" << assertion << "' failed)"; kpeter@66: cerr << endl; kpeter@66: if (do_abort) kpeter@66: abort(); kpeter@66: } kpeter@66: kpeter@66: template <> kpeter@66: inline void assert_fail(const char *file, int line, kpeter@66: const char *func, kpeter@66: const char *message, kpeter@66: const char *assertion, kpeter@66: bool do_abort) kpeter@66: { kpeter@66: using namespace std; kpeter@66: cerr << file << ":" << line << ": "; kpeter@66: if (func) kpeter@66: cerr << func << ": "; kpeter@66: cerr << message; kpeter@66: if (assertion) kpeter@66: cerr << " (assertion '" << assertion << "' failed)"; kpeter@66: cerr << endl; kpeter@66: if (do_abort) kpeter@66: abort(); kpeter@66: } kpeter@66: kpeter@66: template <> kpeter@66: inline void assert_fail(const char *file, int line, kpeter@66: const char *func, kpeter@66: std::string message, kpeter@66: const char *assertion, kpeter@66: bool do_abort) kpeter@66: { kpeter@66: assert_fail(file, line, func, message.c_str(), assertion, do_abort); kpeter@66: } kpeter@66: kpeter@66: template kpeter@66: inline void assert_fail_failure(const char *file, int line, const char *func, kpeter@66: Exception exception, kpeter@66: const char *assertion = 0, kpeter@66: bool = true) kpeter@66: { kpeter@66: throw AssertionFailedError(file, line, func, exception.what(), assertion); kpeter@66: } kpeter@66: kpeter@66: template <> kpeter@66: inline void assert_fail_failure(const char *file, int line, kpeter@66: const char *func, kpeter@66: const char *message, kpeter@66: const char *assertion, kpeter@66: bool) kpeter@66: { kpeter@66: throw AssertionFailedError(file, line, func, message, assertion); kpeter@66: } kpeter@66: kpeter@66: template <> kpeter@66: inline void assert_fail_failure(const char *file, int line, kpeter@66: const char *func, kpeter@66: std::string message, kpeter@66: const char *assertion, kpeter@66: bool) kpeter@66: { kpeter@66: assert_fail_failure(file, line, func, message.c_str(), assertion, true); kpeter@66: } kpeter@66: kpeter@66: template kpeter@66: inline void assert_fail_exception(const char *file, int line, const char *func, kpeter@66: Exception exception, kpeter@66: const char *assertion = 0, bool = true) kpeter@66: { kpeter@66: throw exception; kpeter@66: } kpeter@66: kpeter@66: template <> kpeter@66: inline void assert_fail_exception(const char *file, int line, kpeter@66: const char *func, kpeter@66: const char *message, kpeter@66: const char *assertion, kpeter@66: bool) kpeter@66: { kpeter@66: throw AssertionFailedError(file, line, func, message, assertion); kpeter@66: } kpeter@66: kpeter@66: template <> kpeter@66: inline void assert_fail_exception(const char *file, int line, kpeter@66: const char *func, kpeter@66: std::string message, kpeter@66: const char *assertion, kpeter@66: bool) kpeter@66: { kpeter@66: assert_fail_exception(file, line, func, message.c_str(), assertion, true); kpeter@66: } kpeter@66: kpeter@66: /// @} kpeter@66: kpeter@66: } kpeter@66: #endif // LEMON_ERROR_H kpeter@66: kpeter@66: #undef LEMON_ASSERT kpeter@66: #undef LEMON_FIXME kpeter@66: kpeter@66: #ifdef LEMON_ENABLE_ASSERTS kpeter@66: # define LEMON_ASSERT_ABORT kpeter@66: #endif kpeter@66: kpeter@66: #ifndef LEMON_ASSERT_DO_ABORT kpeter@66: # define LEMON_ASSERT_DO_ABORT 1 kpeter@66: #endif kpeter@66: kpeter@66: #ifndef LEMON_ASSERT_HANDLER kpeter@66: # if defined LEMON_ASSERT_EXCEPTION kpeter@66: # define LEMON_ASSERT_HANDLER ::lemon::assert_fail_exception kpeter@66: # elif defined LEMON_ASSERT_FAILURE kpeter@66: # define LEMON_ASSERT_HANDLER ::lemon::assert_fail_failure kpeter@66: # elif defined LEMON_ASSERT_ABORT kpeter@66: # define LEMON_ASSERT_HANDLER ::lemon::assert_fail kpeter@66: # else kpeter@66: # define LEMON_DISABLE_ASSERTS kpeter@66: # endif kpeter@66: #endif kpeter@66: kpeter@66: #ifdef DOXYGEN kpeter@66: kpeter@66: /// \brief Macro for assertions with customizable message kpeter@66: /// kpeter@66: /// Macro for assertions with customizable message. kpeter@66: /// kpeter@66: /// The assertions are disabled in the default behaviour. You can kpeter@66: /// enable the assertions with the kpeter@66: /// \code kpeter@66: /// #define LEMON_ENABLE_ASSERTS kpeter@66: /// \endcode kpeter@66: /// Then an assert kpeter@66: /// provides a log on the standard error about the assertion and aborts kpeter@66: /// the program if LEMON_ASSERT_DO_ABORT is also defined (otherwise the kpeter@66: /// program keeps on running). kpeter@66: /// By defining LEMON_ASSERT_FAILURE or kpeter@66: /// LEMON_ASSERT_EXCEPTION, you can set other behaviour to the kpeter@66: /// assertions. In case LEMON_ASSERT_FAILURE is given, LEMON_ASSERT kpeter@66: /// will always throw an \c AssertionFailedError exception with kpeter@66: /// the \c msg error message. By using kpeter@66: /// LEMON_ASSERT_EXCEPTION, one can define an arbitrary exception to be thrown. kpeter@66: /// kpeter@66: /// The LEMON_ASSERT macro should be called with the \c exp parameter kpeter@66: /// which should be an expression convertible to bool. If the given kpeter@66: /// parameter is false the assertion is raised and one of the assertion kpeter@66: /// behaviour will be activated. The \c msg should be either a const kpeter@66: /// char* message or an exception. When the \c msg is an exception the kpeter@66: /// \ref lemon::Exception::what() "what()" function is called to retrieve and kpeter@66: /// display the error message. kpeter@66: /// kpeter@66: /// \todo We should provide some way to reset to the default behaviour, kpeter@66: /// shouldn't we? kpeter@66: /// kpeter@66: /// \todo This whole 'assert' business should be placed in a separate kpeter@66: /// include file. The boost assert is not guarded by header sentries kpeter@66: /// which may help to change the behaviour of the assertions in kpeter@66: /// the files. kpeter@66: /// kpeter@66: /// \todo __PRETTY_FUNCTION__ should be replaced by something kpeter@66: /// compiler-independent, like BOOST_CURRENT_FUNCTION kpeter@66: kpeter@66: # define LEMON_ASSERT(exp, msg) \ kpeter@66: (static_cast (!!(exp) ? 0 : ( \ kpeter@66: LEMON_ASSERT_HANDLER(__FILE__, __LINE__, \ kpeter@66: __PRETTY_FUNCTION__, \ kpeter@66: msg, #exp, LEMON_ASSERT_DO_ABORT), 0))) kpeter@66: kpeter@66: #else kpeter@66: # if defined LEMON_DISABLE_ASSERTS kpeter@66: kpeter@66: # define LEMON_ASSERT(exp, msg) (static_cast (0)) kpeter@66: kpeter@66: # else kpeter@66: # define LEMON_ASSERT(exp, msg) \ kpeter@66: (static_cast (!!(exp) ? 0 : ( \ kpeter@66: LEMON_ASSERT_HANDLER(__FILE__, __LINE__, \ kpeter@66: __PRETTY_FUNCTION__, \ kpeter@66: msg, #exp, LEMON_ASSERT_DO_ABORT), 0))) kpeter@66: # endif kpeter@66: #endif kpeter@66: kpeter@66: /** kpeter@66: * \brief Macro for mark not yet implemented features. kpeter@66: * kpeter@66: * \todo Is this the right place for this? It should be used only in kpeter@66: * modules under development. kpeter@66: * kpeter@66: * \todo __PRETTY_FUNCTION__ should be replaced by something kpeter@66: * compiler-independent, like BOOST_CURRENT_FUNCTION kpeter@66: */ kpeter@66: kpeter@66: #define LEMON_FIXME(msg) \ kpeter@66: (LEMON_ASSERT_HANDLER(__FILE__, __LINE__, __PRETTY_FUNCTION__, \ kpeter@66: "FIXME: " msg))