src/lemon/error.h
author marci
Thu, 17 Feb 2005 15:14:13 +0000
changeset 1153 4b0468de3a31
parent 1125 377e240b050f
child 1157 3996d2098090
permissions -rw-r--r--
if you have a nuclear power plant and wanna compute small magic squares, then let's do it
     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 exceptions
    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 /// \addtogroup exceptions
    35 /// @{
    36 
    37   /// Exception-safe convenient "error message" class.
    38 
    39   /// Helper class which provides a convenient ostream-like (operator <<
    40   /// based) interface to create a string message. Mostly useful in
    41   /// exception classes (therefore the name).
    42   class ErrorMessage {
    43   protected:
    44     ///\e 
    45     boost::shared_ptr<std::ostringstream> buf;
    46     
    47     ///\e 
    48     bool init() throw() {
    49       try {
    50 	buf.reset(new std::ostringstream);
    51       }
    52       catch(...) {
    53 	buf.reset();
    54       }
    55       return buf;
    56     }
    57 
    58   public:
    59 
    60     ///\e 
    61     ErrorMessage() throw() { init(); }
    62 
    63     ///\e 
    64     ErrorMessage(const char *message) throw() {
    65       init();
    66       *this << message;
    67     }
    68 
    69     ///\e 
    70     ErrorMessage(const std::string &message) throw() {
    71       init();
    72       *this << message;
    73     }
    74 
    75     ///\e 
    76     template <typename T>
    77     ErrorMessage& operator<<(const T &t) throw() {
    78       if( !buf ) return *this;
    79 
    80       try {
    81 	*buf << t;
    82       }
    83       catch(...) {
    84 	buf.reset();
    85       }
    86     }
    87 
    88     ///\e 
    89     const char* message() throw() {
    90       if( !buf ) return 0;
    91 
    92       const char* mes = 0;
    93       try {
    94 	mes = buf->str().c_str();
    95       }
    96       catch(...) {}
    97       return mes;
    98     }
    99     
   100   };
   101 
   102   /**
   103    * \brief Generic exception class.
   104    *
   105    * Base class for exceptions used in LEMON.
   106    */
   107   class Exception : public std::exception {
   108   public:
   109     ///\e 
   110     Exception() {}
   111     ///\e 
   112     virtual ~Exception() throw() {}
   113 
   114     ///\e
   115     virtual const char* exceptionName() const {
   116       return "lemon::Exception";
   117     }
   118     
   119     ///\e 
   120     virtual const char* what() const throw() {
   121       return exceptionName();
   122     }
   123   };
   124 
   125   /**
   126    * \brief One of the two main subclasses of \ref Exception.
   127    *
   128    * Logic errors represent problems in the internal logic of a program;
   129    * in theory, these are preventable, and even detectable before the
   130    * program runs (e.g., violations of class invariants).
   131    *
   132    * A typical example for this is \ref UninitializedParameter.
   133    */
   134   class LogicError : public Exception {
   135   public:
   136     virtual const char* exceptionName() const {
   137       return "lemon::LogicError";
   138     }
   139   };
   140 
   141   /**
   142    * \brief \ref Exception for uninitialized parameters.
   143    *
   144    * This error represents problems in the initialization
   145    * of the parameters of the algorithms.
   146    */
   147   class UninitializedParameter : public LogicError {
   148   public:
   149     virtual const char* exceptionName() const {
   150       return "lemon::UninitializedParameter";
   151     }
   152   };
   153 
   154   
   155   /**
   156    * \brief One of the two main subclasses of \ref Exception.
   157    *
   158    * Runtime errors represent problems outside the scope of a program;
   159    * they cannot be easily predicted and can generally only be caught as
   160    * the program executes.
   161    */
   162   class RuntimeError : public Exception {
   163   public:
   164     virtual const char* exceptionName() const {
   165       return "lemon::RuntimeError";
   166     }
   167   };
   168 
   169   ///\e
   170   class RangeError : public RuntimeError {
   171   public:
   172     virtual const char* exceptionName() const {
   173       return "lemon::RangeError";
   174     }
   175   };
   176 
   177   ///\e 
   178   class IOError : public RuntimeError {
   179   public:
   180     virtual const char* exceptionName() const {
   181       return "lemon::IOError";
   182     }
   183   };
   184 
   185   ///\e 
   186   class DataFormatError : public IOError {
   187   protected:
   188     const char *_message;
   189     int _line;
   190     boost::shared_ptr<std::string> _file;
   191 
   192   public:
   193     ///\e 
   194     explicit DataFormatError(const char *the_message)
   195       : _message(the_message), _line(0) {}
   196     ///\e 
   197     DataFormatError(const std::string &file_name, int line_num,
   198 		    const char *the_message)
   199       : _message(the_message), _line(line_num) { file(file_name); }
   200 
   201     ///\e 
   202     void line(int line_num) { _line=line_num; }
   203     ///\e 
   204     void message(char *the_message) { _message=the_message; }
   205     ///\e 
   206     void file(const std::string &file_name) {
   207       try {
   208 	_file.reset(new std::string);
   209 	*_file = file_name;
   210       }
   211       catch(...) {
   212 	_file.reset();
   213       }
   214     }
   215 
   216     ///\e
   217     int line() const { return _line; }
   218     ///\e
   219     const char* message() const { return _message; }
   220 
   221     /// \brief Returns the filename.
   222     ///
   223     /// Returns \e "(unknown)" if the filename was not specified.
   224     const char* file() const {
   225       if( _file )
   226 	return _file->c_str();
   227       else
   228 	return "(unknown)";
   229     }
   230 
   231     ///\e 
   232     virtual const char* what() const throw() {
   233       const char *mes = 0;
   234       try {
   235 	std::ostringstream ostr;
   236 	ostr << _message;
   237 	if( _file || _line ) {
   238 	  ostr << " (";
   239 	  if( _file ) ostr << "in file '" << *_file << "'";
   240 	  if( _file && _line ) ostr << " ";
   241 	  if( _line ) ostr << "at line " << _line;
   242 	  ostr << ")";
   243 	}
   244 	mes = ostr.str().c_str();
   245       }
   246       catch(...) {}
   247       if( mes ) return mes;
   248       return exceptionName();
   249     }
   250 
   251     virtual const char* exceptionName() const {
   252       return "lemon::DataFormatError";
   253     }
   254 
   255     virtual ~DataFormatError() throw() {}
   256   };
   257 
   258 
   259   ///\e
   260   class AssertionFailedError : public LogicError {
   261   protected:
   262     const char *assertion;
   263     const char *file;
   264     int line;
   265     const char *function;
   266     const char *message;
   267   public:
   268     ///\e
   269     AssertionFailedError(const char *_file, int _line, const char *func,
   270 			 const char *msg, const char *_assertion = 0) :
   271       assertion(_assertion), file(_file), line(_line), function(func),
   272       message(msg) {}
   273 
   274     ///\e
   275     const char* get_assertion() const { return assertion; }
   276     ///\e
   277     const char* get_message() const { return message; }
   278     ///\e
   279     const char* get_file() const { return file; }
   280     ///\e
   281     const char* get_function() const { return function; }
   282     ///\e
   283     int get_line() const { return line; }
   284 
   285 
   286     virtual const char* what() const throw() {
   287       const char *mes = 0;
   288       try {
   289 	std::ostringstream ostr;
   290 	ostr << file << ":" << line << ": ";
   291 	if( function )
   292 	  ostr << function << ": ";
   293 	ostr << message;
   294 	if( assertion )
   295 	  ostr << " (assertion '" << assertion << "' failed)";
   296 	mes = ostr.str().c_str();
   297       }
   298       catch(...) {}
   299       if( mes ) return mes;
   300       return exceptionName();
   301     }
   302 
   303     virtual const char* exceptionName() const {
   304       return "lemon::AssertionFailedError";
   305     }
   306 
   307     virtual ~AssertionFailedError() throw() {}
   308   };
   309 
   310 
   311   /****************  Macros  ****************/
   312 
   313 
   314   inline
   315   void assert_fail(const char *file, int line, const char *func,
   316 		   const char *message, const char *assertion = 0,
   317 		   bool do_abort=true)
   318   {
   319     using namespace std;
   320     cerr << file << ":" << line << ": ";
   321     if( func )
   322       cerr << func << ": ";
   323     cerr << message;
   324     if( assertion )
   325       cerr << " (assertion '" << assertion << "' failed)";
   326     cerr << endl;
   327     if(do_abort)
   328       abort();
   329   }
   330 
   331   inline
   332   void assert_fail_throw(const char *file, int line, const char *func,
   333 		   const char *message, const char *assertion = 0,
   334 		   bool = true)
   335   {
   336     throw AssertionFailedError(file, line, func, message, assertion);
   337   }
   338 
   339 /// @}
   340 
   341 }
   342 #endif // LEMON_ERROR_H
   343 
   344 #undef LEMON_ASSERT
   345 #undef LEMON_FIXME
   346 
   347 #ifndef LEMON_ASSERT_ABORT
   348 #  define LEMON_ASSERT_ABORT 1
   349 #endif
   350 
   351 #ifndef LEMON_ASSERT_HANDLER
   352 #  ifdef LEMON_ASSERT_EXCEPTION
   353 #    define LEMON_ASSERT_HANDLER ::lemon::assert_fail_throw
   354 #  else
   355 #    define LEMON_ASSERT_HANDLER ::lemon::assert_fail
   356 #  endif
   357 #endif
   358 
   359 #if defined(NDEBUG) || defined(LEMON_DISABLE_ASSERTS)
   360 
   361 #  define LEMON_ASSERT(exp, msg)  (static_cast<void> (0))
   362 
   363 #else
   364 
   365 /**
   366  * \brief Macro for assertions with customizable message
   367  *
   368  * Macro for assertions with customizable message.
   369  *
   370  * The behaviour can be customized with LEMON_ASSERT_HANDLER,
   371  * LEMON_ASSERT_EXCEPTION and LEMON_ASSERT_ABORT defines. Asserts can be
   372  * disabled by defining either NDEBUG or LEMON_DISABLE_ASSERTS macros.
   373  *
   374  * \todo We should provide some way to reset to the default behaviour,
   375  * shouldn't we?
   376  *
   377  * \todo This whole 'assert' business should be placed in a separate
   378  * include file.
   379  *
   380  * \todo __PRETTY_FUNCTION__ should be replaced by something
   381  * compiler-independant, like BOOST_CURRENT_FUNCTION
   382  */
   383 
   384 #  define LEMON_ASSERT(exp, msg)                 \
   385      (static_cast<void> (!!(exp) ? 0 : (         \
   386        LEMON_ASSERT_HANDLER(__FILE__, __LINE__,  \
   387                             __PRETTY_FUNCTION__, \
   388 			    (msg), #exp, LEMON_ASSERT_ABORT), 0)))
   389 
   390 #endif // NDEBUG || LEMON_DISABLE_ASSERTS
   391 
   392 /**
   393  * \brief Macro for mark not yet implemented features.
   394  *
   395  * \todo Is this the right place for this? It should be used only in
   396  * modules under development.
   397  *
   398  * \todo __PRETTY_FUNCTION__ should be replaced by something
   399  * compiler-independant, like BOOST_CURRENT_FUNCTION
   400  */
   401 
   402 # define LEMON_FIXME(msg) \
   403     (LEMON_ASSERT_HANDLER(__FILE__, __LINE__, __PRETTY_FUNCTION__, \
   404 			  "FIXME: " msg))