src/work/klao/error.h
author alpar
Wed, 02 Feb 2005 13:11:54 +0000
changeset 1117 5767cc417f62
parent 1067 47939f501c81
child 1120 5d8d64bde9c5
permissions -rw-r--r--
Bugfix
     1 /* -*- C++ -*-
     2  * src/lemon/error.h - Part of LEMON, a generic C++ optimization library
     3  *
     4  * Copyright (C) 2004 Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
     5  * (Egervary Combinatorial Optimization Research Group, EGRES).
     6  *
     7  * Permission to use, modify and distribute this software is granted
     8  * provided that this copyright notice appears in all copies. For
     9  * precise terms see the accompanying LICENSE file.
    10  *
    11  * This software is provided "AS IS" with no warranty of any kind,
    12  * express or implied, and with no claim as to its suitability for any
    13  * purpose.
    14  *
    15  */
    16 
    17 #ifndef LEMON_ERROR_H
    18 #define LEMON_ERROR_H
    19 
    20 //! \ingroup misc
    21 //! \file
    22 //! \brief Basic exception classes and error handling.
    23 
    24 #include <exception>
    25 #include <string>
    26 #include <sstream>
    27 #include <iostream>
    28 #include <cstdlib>
    29 
    30 #include <boost/shared_ptr.hpp>
    31 
    32 namespace lemon {
    33 
    34   /// Exception-safe convenient "error message" class.
    35 
    36   /// Helper class which provides a convenient ostream-like (operator <<
    37   /// based) interface to create a string message. Mostly useful in
    38   /// exception classes (therefore the name).
    39   class ErrorMessage {
    40   protected:
    41     ///\e 
    42     boost::shared_ptr<std::ostringstream> buf;
    43     
    44     ///\e 
    45     bool init() throw() {
    46       try {
    47 	buf.reset(new std::ostringstream);
    48       }
    49       catch(...) {
    50 	buf.reset();
    51       }
    52       return buf;
    53     }
    54 
    55   public:
    56 
    57     ///\e 
    58     ErrorMessage() throw() { init(); }
    59 
    60     ///\e 
    61     ErrorMessage(const char *message) throw() {
    62       init();
    63       *this << message;
    64     }
    65 
    66     ///\e 
    67     ErrorMessage(const std::string &message) throw() {
    68       init();
    69       *this << message;
    70     }
    71 
    72     ///\e 
    73     template <typename T>
    74     ErrorMessage& operator<<(const T &t) throw() {
    75       if( !buf ) return *this;
    76 
    77       try {
    78 	*buf << t;
    79       }
    80       catch(...) {
    81 	buf.reset();
    82       }
    83     }
    84 
    85     ///\e 
    86     const char* message() throw() {
    87       if( !buf ) return 0;
    88 
    89       const char* mes = 0;
    90       try {
    91 	mes = buf->str().c_str();
    92       }
    93       catch(...) {}
    94       return mes;
    95     }
    96     
    97   };
    98 
    99   /**
   100    * \brief Generic exception class.
   101    *
   102    * Base class for exceptions used in LEMON.
   103    */
   104   class Exception : public std::exception {
   105   protected:
   106     ///\e
   107     const char *message;
   108 
   109   public:
   110     ///\e 
   111     Exception() throw() : message(0) {}
   112     ///\e 
   113     explicit Exception(const char *msg) throw()
   114       : message(msg) {}
   115     ///\e 
   116     virtual ~Exception() throw() {}
   117     
   118     ///\e 
   119     virtual const char* what() const throw() {
   120       if( message ) return message;
   121       return "lemon::Exception";
   122     }
   123   };
   124 
   125   ///\e 
   126   class LogicError : public Exception {
   127   public:
   128     ///\e 
   129     explicit LogicError() {}
   130     ///\e 
   131     explicit LogicError(const char *s)
   132       : Exception(s) {}
   133   };
   134 
   135   ///\e 
   136   class RuntimeError : public Exception {
   137   public:
   138     ///\e
   139     explicit RuntimeError() {}
   140     ///\e
   141     explicit RuntimeError(const char *s)
   142       : Exception(s) {}
   143   };
   144 
   145   ///\e
   146   class RangeError : public RuntimeError {
   147   public:
   148     ///\e 
   149     explicit RangeError(const char *s)
   150       : RuntimeError(s) {}
   151   };
   152 
   153   ///\e 
   154   class IOError : public RuntimeError {
   155   public:
   156     ///\e 
   157     explicit IOError(const char *s)
   158       : RuntimeError(s) {}
   159   };
   160 
   161   ///\e 
   162   class DataFormatError : public IOError {
   163   protected:
   164     int line;
   165     boost::shared_ptr<std::string> file;
   166 
   167   public:
   168     ///\e 
   169     explicit DataFormatError(const char *message)
   170       : IOError(message), line(0) {}
   171     ///\e 
   172     DataFormatError(const std::string &file_name, int line_num,
   173 		    const char *message)
   174       : IOError(message), line(line_num) { set_file(file_name); }
   175 
   176     ///\e 
   177     void set_line(int line_num) { line=line_num; }
   178     ///\e 
   179     void set_file(const std::string &file_name) {
   180       try {
   181 	file.reset(new std::string);
   182 	*file = file_name;
   183       }
   184       catch(...) {
   185 	file.reset();
   186       }
   187     }
   188 
   189     ///\e
   190     int get_line() const { return line; }
   191 
   192     /// \brief Returns the filename.
   193     ///
   194     /// Returns \e "(unknown)" if the filename was not specified.
   195     const char* get_file() const {
   196       if( file )
   197 	return file->c_str();
   198       else
   199 	return "(unknown)";
   200     }
   201 
   202     ///\e 
   203     virtual const char* what() const throw() {
   204       const char *mes = 0;
   205       try {
   206 	std::ostringstream ostr;
   207 	ostr << IOError::what();
   208 	if( file || line ) {
   209 	  ostr << " (";
   210 	  if( file ) ostr << "in file '" << *file << "'";
   211 	  if( file && line ) ostr << " ";
   212 	  if( line ) ostr << "at line " << line;
   213 	  ostr << ")";
   214 	}
   215 	mes = ostr.str().c_str();
   216       }
   217       catch(...) {}
   218       if( mes ) return mes;
   219       return "lemon::DataFormatError";
   220     }
   221 
   222     virtual ~DataFormatError() throw() {}
   223   };
   224 
   225 
   226   ///\e
   227   class AssertionFailedError : public LogicError {
   228   protected:
   229     const char *assertion;
   230     const char *file;
   231     int line;
   232     const char *function;
   233     const char *message;
   234   public:
   235     ///\e
   236     AssertionFailedError(const char *_file, int _line, const char *func,
   237 			 const char *msg, const char *_assertion = 0) :
   238       assertion(_assertion), file(_file), line(_line), function(func),
   239       message(msg) {}
   240 
   241     ///\e
   242     const char* get_assertion() const { return assertion; }
   243     ///\e
   244     const char* get_message() const { return message; }
   245     ///\e
   246     const char* get_file() const { return file; }
   247     ///\e
   248     const char* get_function() const { return function; }
   249     ///\e
   250     int get_line() const { return line; }
   251 
   252 
   253     virtual const char* what() const throw() {
   254       const char *mes = 0;
   255       try {
   256 	std::ostringstream ostr;
   257 	ostr << file << ":" << line << ": ";
   258 	if( function )
   259 	  ostr << function << ": ";
   260 	ostr << message;
   261 	if( assertion )
   262 	  ostr << " (assertion '" << assertion << "' failed)";
   263 	mes = ostr.str().c_str();
   264       }
   265       catch(...) {}
   266       if( mes ) return mes;
   267       return "lemon::AssertionFailedError";
   268     }
   269 
   270     virtual ~AssertionFailedError() throw() {}
   271   };
   272 
   273 
   274   /****************  Macros  ****************/
   275 
   276 
   277   inline
   278   void assert_fail(const char *file, int line, const char *func,
   279 		   const char *message, const char *assertion = 0,
   280 		   bool do_abort=true)
   281   {
   282     using namespace std;
   283     cerr << file << ":" << line << ": ";
   284     if( func )
   285       cerr << func << ": ";
   286     cerr << message;
   287     if( assertion )
   288       cerr << " (assertion '" << assertion << "' failed)";
   289     cerr << endl;
   290     if(do_abort)
   291       abort();
   292   }
   293 
   294   inline
   295   void assert_fail_throw(const char *file, int line, const char *func,
   296 		   const char *message, const char *assertion = 0,
   297 		   bool = true)
   298   {
   299     throw AssertionFailedError(file, line, func, message, assertion);
   300   }
   301 
   302 
   303 }
   304 #endif // LEMON_ERROR_H
   305 
   306 #undef LEMON_ASSERT
   307 #undef LEMON_FIXME
   308 
   309 #ifndef LEMON_ASSERT_ABORT
   310 #  define LEMON_ASSERT_ABORT 1
   311 #endif
   312 
   313 #ifndef LEMON_ASSERT_HANDLER
   314 #  define LEMON_ASSERT_HANDLER ::lemon::assert_fail
   315 #endif
   316 
   317 #if defined(NDEBUG) || defined(LEMON_DISABLE_ASSERTS)
   318 
   319 #  define LEMON_ASSERT(exp, msg)  (static_cast<void> (0))
   320 
   321 #else
   322 
   323 /**
   324  * \brief Macro for assertions with customizable message
   325  *
   326  * \todo __PRETTY_FUNCTION__ should be replaced by something
   327  * compiler-independant, like BOOST_CURRENT_FUNCTION
   328  */
   329 
   330 #  define LEMON_ASSERT(exp, msg)                 \
   331      (static_cast<void> (!!(exp) ? 0 : (         \
   332        LEMON_ASSERT_HANDLER(__FILE__, __LINE__,  \
   333                             __PRETTY_FUNCTION__, \
   334 			    (msg), #exp, LEMON_ASSERT_ABORT), 0)))
   335 
   336 # endif // NDEBUG
   337 
   338 /**
   339  * \brief Macro for mark not yet implemented features.
   340  *
   341  * \todo Is this the right place for this? It should be used only in
   342  * modules under development.
   343  *
   344  * \todo __PRETTY_FUNCTION__ should be replaced by something
   345  * compiler-independant, like BOOST_CURRENT_FUNCTION
   346  */
   347 
   348 # define LEMON_FIXME(msg) \
   349     (LEMON_ASSERT_HANDLER(__FILE__, __LINE__, __PRETTY_FUNCTION__, \
   350 			  "FIXME: " msg))