COIN-OR::LEMON - Graph Library

Changeset 108:889d0c289d19 in lemon-1.2 for lemon


Ignore:
Timestamp:
03/25/08 16:36:44 (17 years ago)
Author:
Balazs Dezso <deba@…>
Branch:
default
Children:
109:abddaa08b507, 112:d2ee5e7f00ef
Phase:
public
Message:

Reworking assertions and moving to distinict file

Location:
lemon
Files:
3 edited
1 copied

Legend:

Unmodified
Added
Removed
  • lemon/Makefile.am

    r106 r108  
    1818lemon_HEADERS += \
    1919        lemon/arg_parser.h \
     20        lemon/assert.h \
    2021        lemon/bfs.h \
    2122        lemon/bin_heap.h \
  • lemon/arg_parser.h

    r95 r108  
    2727#include <sstream>
    2828#include <algorithm>
    29 #include <lemon/error.h>
     29#include <lemon/assert.h>
    3030
    3131///\ingroup misc
  • lemon/assert.h

    r66 r108  
    1717 */
    1818
    19 #ifndef LEMON_ERROR_H
    20 #define LEMON_ERROR_H
     19#ifndef LEMON_ASSERT_H
     20#define LEMON_ASSERT_H
    2121
    2222/// \ingroup exceptions
    2323/// \file
    24 /// \brief Basic exception classes and error handling.
    25 
    26 #include <exception>
    27 #include <string>
    28 #include <sstream>
    29 #include <iostream>
    30 #include <cstdlib>
    31 #include <memory>
     24/// \brief Extended assertion handling
     25
     26#include <lemon/error.h>
    3227
    3328namespace lemon {
    3429
    35   /// \addtogroup exceptions
    3630  /// @{
    3731
    38   /// \brief Exception safe wrapper class.
    39   ///
    40   /// Exception safe wrapper class to implement the members of exceptions.
    41   template <typename _Type>
    42   class ExceptionMember {
    43   public:
    44     typedef _Type Type;
    45 
    46     ExceptionMember() throw() {
    47       try {
    48         ptr.reset(new Type());
    49       } catch (...) {}
    50     }
    51 
    52     ExceptionMember(const Type& type) throw() {
    53       try {
    54         ptr.reset(new Type());
    55         if (ptr.get() == 0) return;
    56         *ptr = type;
    57       } catch (...) {}
    58     }
    59 
    60     ExceptionMember(const ExceptionMember& copy) throw() {
    61       try {
    62         if (!copy.valid()) return;
    63         ptr.reset(new Type());
    64         if (ptr.get() == 0) return;
    65         *ptr = copy.get();
    66       } catch (...) {}
    67     }
    68 
    69     ExceptionMember& operator=(const ExceptionMember& copy) throw() {
    70       if (ptr.get() == 0) return;
    71       try {
    72         if (!copy.valid()) return;
    73         *ptr = copy.get();
    74       } catch (...) {}
    75     }
    76 
    77     void set(const Type& type) throw() {
    78       if (ptr.get() == 0) return;
    79       try {
    80         *ptr = type;
    81       } catch (...) {}
    82     }
    83 
    84     const Type& get() const {
    85       return *ptr;
    86     }
    87 
    88     bool valid() const throw() {
    89       return ptr.get() != 0;
    90     }
    91 
    92   private:
    93     std::auto_ptr<_Type> ptr;
    94   };
    95 
    96   /// Exception-safe convenient "error message" class.
    97 
    98   /// Helper class which provides a convenient ostream-like (operator <<
    99   /// based) interface to create a string message. Mostly useful in
    100   /// exception classes (therefore the name).
    101   class ErrorMessage {
     32  ///\e
     33  class AssertionFailedError : public LogicError {
    10234  protected:
    103     ///\e
    104 
    105     ///\todo The good solution is boost::shared_ptr...
    106     ///
    107     mutable std::auto_ptr<std::ostringstream> buf;
    108 
    109     ///\e
    110     bool init() throw() {
    111       try {
    112         buf.reset(new std::ostringstream);
    113       }
    114       catch(...) {
    115         buf.reset();
    116       }
    117       return buf.get();
    118     }
    119 
    120   public:
    121 
    122     ///\e
    123     ErrorMessage() throw() { init(); }
    124 
    125     ErrorMessage(const ErrorMessage& em) throw() : buf(em.buf) { }
    126 
    127     ///\e
    128     ErrorMessage(const char *msg) throw() {
    129       init();
    130       *this << msg;
    131     }
    132 
    133     ///\e
    134     ErrorMessage(const std::string &msg) throw() {
    135       init();
    136       *this << msg;
    137     }
    138 
    139     ///\e
    140     template <typename T>
    141     ErrorMessage& operator<<(const T &t) throw() {
    142       if( ! buf.get() ) return *this;
    143 
    144       try {
    145         *buf << t;
    146       }
    147       catch(...) {
    148         buf.reset();
    149       }
    150       return *this;
    151     }
    152 
    153     ///\e
    154     const char* message() throw() {
    155       if( ! buf.get() ) return 0;
    156 
    157       const char* mes = 0;
    158       try {
    159         mes = buf->str().c_str();
    160       }
    161       catch(...) {}
    162       return mes;
    163     }
    164 
    165   };
    166 
    167   /// Generic exception class.
    168 
    169   /// Base class for exceptions used in LEMON.
    170   ///
    171   class Exception : public std::exception {
    172   public:
    173     ///\e
    174     Exception() {}
    175     ///\e
    176     virtual ~Exception() throw() {}
    177     ///\e
    178     virtual const char* what() const throw() {
    179       return "lemon::Exception";
    180     }
    181   };
    182 
    183   /// One of the two main subclasses of \ref Exception.
    184 
    185   /// Logic errors represent problems in the internal logic of a program;
    186   /// in theory, these are preventable, and even detectable before the
    187   /// program runs (e.g. violations of class invariants).
    188   ///
    189   /// A typical example for this is \ref UninitializedParameter.
    190   class LogicError : public Exception {
    191   public:
    192     virtual const char* what() const throw() {
    193       return "lemon::LogicError";
    194     }
    195   };
    196 
    197   /// \ref Exception for uninitialized parameters.
    198 
    199   /// This error represents problems in the initialization
    200   /// of the parameters of the algorithms.
    201   class UninitializedParameter : public LogicError {
    202   public:
    203     virtual const char* what() const throw() {
    204       return "lemon::UninitializedParameter";
    205     }
    206   };
    207 
    208 
    209   /// One of the two main subclasses of \ref Exception.
    210 
    211   /// Runtime errors represent problems outside the scope of a program;
    212   /// they cannot be easily predicted and can generally only be caught
    213   /// as the program executes.
    214   class RuntimeError : public Exception {
    215   public:
    216     virtual const char* what() const throw() {
    217       return "lemon::RuntimeError";
    218     }
    219   };
    220 
    221   ///\e
    222   class RangeError : public RuntimeError {
    223   public:
    224     virtual const char* what() const throw() {
    225       return "lemon::RangeError";
    226     }
    227   };
    228 
    229   ///\e
    230   class IoError : public RuntimeError {
    231   public:
    232     virtual const char* what() const throw() {
    233       return "lemon::IoError";
    234     }
    235   };
    236 
    237   ///\e
    238   class DataFormatError : public IoError {
    239   protected:
    240     ExceptionMember<std::string> _message;
    241     ExceptionMember<std::string> _file;
     35    const char *_assertion;
     36    const char *_file;
    24237    int _line;
     38    const char *_function;
     39    const char *_message;
    24340
    24441    mutable ExceptionMember<std::string> _message_holder;
    24542  public:
    246 
    247     DataFormatError(const DataFormatError &dfe) :
    248       IoError(dfe), _message(dfe._message), _file(dfe._file),
    249       _line(dfe._line) {}
    250 
    251     ///\e
    252     explicit DataFormatError(const char *the_message)
    253       : _message(the_message), _line(0) {}
    254 
    255     ///\e
    256     DataFormatError(const std::string &file_name, int line_num,
    257                     const char *the_message)
    258       : _message(the_message), _line(line_num) { file(file_name); }
    259 
    260     ///\e
    261     void line(int ln) { _line = ln; }
    262     ///\e
    263     void message(const std::string& msg) { _message.set(msg); }
    264     ///\e
    265     void file(const std::string &fl) { _file.set(fl); }
    266 
     43    ///\e
     44    AssertionFailedError(const char *file, int line, const char *function,
     45                         const char *msg, const char *assertion = 0) :
     46      _assertion(assertion), _file(file), _line(line),
     47      _function(function), _message(msg) {}
     48
     49    ///\e
     50    const char* assertion() const { return _assertion; }
     51    ///\e
     52    const char* message() const { return _message; }
     53    ///\e
     54    const char* file() const { return _file; }
     55    ///\e
     56    const char* function() const { return _function; }
    26757    ///\e
    26858    int line() const { return _line; }
    269     ///\e
    270     const char* message() const {
    271       if (_message.valid() && !_message.get().empty()) {
    272         return _message.get().c_str();
    273       } else {
    274         return 0;
    275       }
    276     }
    277 
    278     /// \brief Returns the filename.
    279     ///
    280     /// Returns \e null if the filename was not specified.
    281     const char* file() const {
    282       if (_file.valid() && !_file.get().empty()) {
    283         return _file.get().c_str();
    284       } else {
    285         return 0;
    286       }
    287     }
    288 
    289     ///\e
     59
     60
    29061    virtual const char* what() const throw() {
    29162      try {
    29263        std::ostringstream ostr;
    293         ostr << "lemon:DataFormatError" << ": ";
    294         if (message()) ostr << message();
    295         if( file() || line() != 0 ) {
    296           ostr << " (";
    297           if( file() ) ostr << "in file '" << file() << "'";
    298           if( file() && line() != 0 ) ostr << " ";
    299           if( line() != 0 ) ostr << "at line " << line();
    300           ostr << ")";
    301         }
    302         _message_holder.set(ostr.str());
    303       }
    304       catch (...) {}
    305       if( _message_holder.valid()) return _message_holder.get().c_str();
    306       return "lemon:DataFormatError";
    307     }
    308 
    309     virtual ~DataFormatError() throw() {}
    310   };
    311 
    312   ///\e
    313   class FileOpenError : public IoError {
    314   protected:
    315     ExceptionMember<std::string> _file;
    316 
    317     mutable ExceptionMember<std::string> _message_holder;
    318   public:
    319 
    320     FileOpenError(const FileOpenError &foe) :
    321       IoError(foe), _file(foe._file) {}
    322 
    323     ///\e
    324     explicit FileOpenError(const std::string& fl)
    325       : _file(fl) {}
    326 
    327 
    328     ///\e
    329     void file(const std::string &fl) { _file.set(fl); }
    330 
    331     /// \brief Returns the filename.
    332     ///
    333     /// Returns \e null if the filename was not specified.
    334     const char* file() const {
    335       if (_file.valid() && !_file.get().empty()) {
    336         return _file.get().c_str();
    337       } else {
    338         return 0;
    339       }
    340     }
    341 
    342     ///\e
    343     virtual const char* what() const throw() {
    344       try {
    345         std::ostringstream ostr;
    346         ostr << "lemon::FileOpenError" << ": ";
    347         ostr << "Cannot open file - " << file();
    348         _message_holder.set(ostr.str());
    349       }
    350       catch (...) {}
    351       if( _message_holder.valid()) return _message_holder.get().c_str();
    352       return "lemon::FileOpenError";
    353     }
    354     virtual ~FileOpenError() throw() {}
    355   };
    356 
    357   class IoParameterError : public IoError {
    358   protected:
    359     ExceptionMember<std::string> _message;
    360     ExceptionMember<std::string> _file;
    361 
    362     mutable ExceptionMember<std::string> _message_holder;
    363   public:
    364 
    365     IoParameterError(const IoParameterError &ile) :
    366       IoError(ile), _message(ile._message), _file(ile._file) {}
    367 
    368     ///\e
    369     explicit IoParameterError(const char *the_message)
    370       : _message(the_message) {}
    371 
    372     ///\e
    373     IoParameterError(const char *file_name, const char *the_message)
    374       : _message(the_message), _file(file_name) {}
    375 
    376      ///\e
    377     void message(const std::string& msg) { _message.set(msg); }
    378     ///\e
    379     void file(const std::string &fl) { _file.set(fl); }
    380 
    381      ///\e
    382     const char* message() const {
    383       if (_message.valid()) {
    384         return _message.get().c_str();
    385       } else {
    386         return 0;
    387       }
    388     }
    389 
    390     /// \brief Returns the filename.
    391     ///
    392     /// Returns \c 0 if the filename was not specified.
    393     const char* file() const {
    394       if (_file.valid()) {
    395         return _file.get().c_str();
    396       } else {
    397         return 0;
    398       }
    399     }
    400 
    401     ///\e
    402     virtual const char* what() const throw() {
    403       try {
    404         std::ostringstream ostr;
    405         if (message()) ostr << message();
    406         if (file()) ostr << "(when reading file '" << file() << "')";
    407         _message_holder.set(ostr.str());
    408       }
    409       catch (...) {}
    410       if( _message_holder.valid() ) return _message_holder.get().c_str();
    411       return "lemon:IoParameterError";
    412     }
    413     virtual ~IoParameterError() throw() {}
    414   };
    415 
    416 
    417   ///\e
    418   class AssertionFailedError : public LogicError {
    419   protected:
    420     const char *assertion;
    421     const char *file;
    422     int line;
    423     const char *function;
    424     const char *message;
    425 
    426     mutable ExceptionMember<std::string> _message_holder;
    427   public:
    428     ///\e
    429     AssertionFailedError(const char *_file, int _line, const char *func,
    430                          const char *msg, const char *_assertion = 0) :
    431       assertion(_assertion), file(_file), line(_line), function(func),
    432       message(msg) {}
    433 
    434     ///\e
    435     const char* get_assertion() const { return assertion; }
    436     ///\e
    437     const char* get_message() const { return message; }
    438     ///\e
    439     const char* get_file() const { return file; }
    440     ///\e
    441     const char* get_function() const { return function; }
    442     ///\e
    443     int get_line() const { return line; }
    444 
    445 
    446     virtual const char* what() const throw() {
    447       try {
    448         std::ostringstream ostr;
    449         ostr << file << ":" << line << ": ";
    450         if( function )
    451           ostr << function << ": ";
    452         ostr << message;
    453         if( assertion )
    454            ostr << " (assertion '" << assertion << "' failed)";
     64        ostr << _file << ":" << _line << ": ";
     65        if (_function)
     66          ostr << _function << ": ";
     67        ostr << _message;
     68        if (_assertion)
     69           ostr << " (assertion '" << _assertion << "' failed)";
    45570        _message_holder.set(ostr.str());
    45671        return ostr.str().c_str();
     
    46075      return "lemon::AssertionFailedError";
    46176    }
    462    virtual ~AssertionFailedError() throw() {}
     77    virtual ~AssertionFailedError() throw() {}
    46378  };
    46479
    46580
    466   /****************  Macros  ****************/
    467 
     81  inline void assert_fail_log(const char *file, int line,
     82                              const char *function,
     83                              const std::exception& exception,
     84                              const char *assertion)
     85  {
     86    std::cerr << file << ":" << line << ": ";
     87    if (function)
     88      std::cerr << function << ": ";
     89    std::cerr << exception.what();
     90    if (assertion)
     91      std::cerr << " (assertion '" << assertion << "' failed)";
     92    std::cerr << std::endl;
     93  }
     94
     95  inline void assert_fail_log(const char *file, int line, const char *function,
     96                              const char *message, const char *assertion)
     97  {
     98    std::cerr << file << ":" << line << ": ";
     99    if (function)
     100      std::cerr << function << ": ";
     101    std::cerr << message;
     102    if (assertion)
     103      std::cerr << " (assertion '" << assertion << "' failed)";
     104    std::cerr << std::endl;
     105  }
     106
     107  inline void assert_fail_log(const char *file, int line, const char *function,
     108                              const std::string& message, const char *assertion)
     109  {
     110    assert_fail_log(file, line, function, message.c_str(), assertion);
     111  }
     112
     113  inline void assert_fail_abort(const char *file, int line,
     114                                const char *function,
     115                                const std::exception& exception,
     116                                const char *assertion)
     117  {
     118    std::cerr << file << ":" << line << ": ";
     119    if (function)
     120      std::cerr << function << ": ";
     121    std::cerr << exception.what();
     122    if (assertion)
     123      std::cerr << " (assertion '" << assertion << "' failed)";
     124    std::cerr << std::endl;
     125    std::abort();
     126  }
     127
     128  inline void assert_fail_abort(const char *file, int line,
     129                                const char *function, const char* message,
     130                                const char *assertion)
     131  {
     132    std::cerr << file << ":" << line << ": ";
     133    if (function)
     134      std::cerr << function << ": ";
     135    std::cerr << message;
     136    if (assertion)
     137      std::cerr << " (assertion '" << assertion << "' failed)";
     138    std::cerr << std::endl;
     139    std::abort();
     140  }
     141
     142  inline void assert_fail_abort(const char *file, int line,
     143                                const char *function,
     144                                const std::string& message,
     145                                const char *assertion)
     146  {
     147    assert_fail_abort(file, line, function, message.c_str(), assertion);
     148  }
     149
     150  inline void assert_fail_error(const char *file, int line,
     151                                  const char *function,
     152                                  const std::exception& exception,
     153                                  const char *assertion)
     154  {
     155    throw AssertionFailedError(file, line, function,
     156                               exception.what(), assertion);
     157  }
     158
     159  inline void assert_fail_error(const char *file, int line,
     160                                  const char *function, const char *message,
     161                                  const char *assertion)
     162  {
     163    throw AssertionFailedError(file, line, function, message, assertion);
     164  }
     165
     166  inline void assert_fail_error(const char *file, int line,
     167                                  const char *function,
     168                                  const std::string& message,
     169                                  const char *assertion)
     170  {
     171    assert_fail_error(file, line, function, message.c_str(), assertion);
     172  }
    468173
    469174  template <typename Exception>
    470   inline void assert_fail(const char *file, int line,
    471                           const char *func,
    472                           Exception exception,
    473                           const char *assertion = 0,
    474                           bool do_abort=true)
    475   {
    476     using namespace std;
    477     cerr << file << ":" << line << ": ";
    478     if (func)
    479       cerr << func << ": ";
    480     cerr << exception.what();
    481     if (assertion)
    482       cerr << " (assertion '" << assertion << "' failed)";
    483     cerr << endl;
    484     if (do_abort)
    485       abort();
    486   }
    487 
    488   template <>
    489   inline void assert_fail<const char *>(const char *file, int line,
    490                                         const char *func,
    491                                         const char *message,
    492                                         const char *assertion,
    493                                         bool do_abort)
    494   {
    495     using namespace std;
    496     cerr << file << ":" << line << ": ";
    497     if (func)
    498       cerr << func << ": ";
    499     cerr << message;
    500     if (assertion)
    501       cerr << " (assertion '" << assertion << "' failed)";
    502     cerr << endl;
    503     if (do_abort)
    504       abort();
    505   }
    506 
    507   template <>
    508   inline void assert_fail<std::string>(const char *file, int line,
    509                                        const char *func,
    510                                        std::string message,
    511                                        const char *assertion,
    512                                        bool do_abort)
    513   {
    514     assert_fail(file, line, func, message.c_str(), assertion, do_abort);
    515   }
    516 
    517   template <typename Exception>
    518   inline void assert_fail_failure(const char *file, int line, const char *func,
    519                            Exception exception,
    520                            const char *assertion = 0,
    521                            bool = true)
    522   {
    523     throw AssertionFailedError(file, line, func, exception.what(), assertion);
    524   }
    525 
    526   template <>
    527   inline void assert_fail_failure<const char *>(const char *file, int line,
    528                                                 const char *func,
    529                                                 const char *message,
    530                                                 const char *assertion,
    531                                                 bool)
    532   {
    533     throw AssertionFailedError(file, line, func, message, assertion);
    534   }
    535 
    536   template <>
    537   inline void assert_fail_failure<std::string>(const char *file, int line,
    538                                                const char *func,
    539                                                std::string message,
    540                                                const char *assertion,
    541                                                bool)
    542   {
    543     assert_fail_failure(file, line, func, message.c_str(), assertion, true);
    544   }
    545 
    546   template <typename Exception>
    547   inline void assert_fail_exception(const char *file, int line, const char *func,
    548                              Exception exception,
    549                              const char *assertion = 0, bool = true)
     175  inline void assert_fail_exception(const char *, int, const char *,
     176                                    const Exception& exception,
     177                                    const char *, const std::exception* =
     178                                    static_cast<const Exception*>(0))
    550179  {
    551180    throw exception;
    552181  }
    553182
    554   template <>
    555   inline void assert_fail_exception<const char *>(const char *file, int line,
    556                                            const char *func,
    557                                            const char *message,
    558                                            const char *assertion,
    559                                            bool)
    560   {
    561     throw AssertionFailedError(file, line, func, message, assertion);
    562   }
    563 
    564   template <>
    565   inline void assert_fail_exception<std::string>(const char *file, int line,
    566                                                  const char *func,
    567                                                  std::string message,
    568                                                  const char *assertion,
    569                                                  bool)
    570   {
    571     assert_fail_exception(file, line, func, message.c_str(), assertion, true);
     183  inline void assert_fail_exception(const char *file, int line,
     184                                    const char *function, const char *message,
     185                                    const char *assertion)
     186  {
     187    throw AssertionFailedError(file, line, function, message, assertion);
     188  }
     189
     190  inline void assert_fail_exception(const char *file, int line,
     191                                    const char *function,
     192                                    const std::string& message,
     193                                    const char *assertion)
     194  {
     195    assert_fail_exception(file, line, function, message.c_str(), assertion);
    572196  }
    573197
     
    575199
    576200}
    577 #endif // LEMON_ERROR_H
     201#endif // LEMON_ASSERT_H
    578202
    579203#undef LEMON_ASSERT
    580204#undef LEMON_FIXME
    581205
    582 #ifdef LEMON_ENABLE_ASSERTS
    583 #  define LEMON_ASSERT_ABORT
    584 #endif
    585 
    586 #ifndef LEMON_ASSERT_DO_ABORT
    587 #  define LEMON_ASSERT_DO_ABORT 1
    588 #endif
    589 
    590 #ifndef LEMON_ASSERT_HANDLER
    591 #  if defined LEMON_ASSERT_EXCEPTION
    592 #    define LEMON_ASSERT_HANDLER ::lemon::assert_fail_exception
    593 #  elif defined LEMON_ASSERT_FAILURE
    594 #    define LEMON_ASSERT_HANDLER ::lemon::assert_fail_failure
    595 #  elif defined LEMON_ASSERT_ABORT
    596 #    define LEMON_ASSERT_HANDLER ::lemon::assert_fail
    597 #  else
    598 #    define LEMON_DISABLE_ASSERTS
     206#if (defined(LEMON_ASSERT_LOG) ? 1 : 0) +               \
     207  (defined(LEMON_ASSERT_ABORT) ? 1 : 0) +               \
     208  (defined(LEMON_ASSERT_ERROR) ? 1 : 0) +               \
     209  (defined(LEMON_ASSERT_EXCEPTION) ? 1 : 0) +           \
     210  (defined(LEMON_ASSERT_CUSTOM) ? 1 : 0) > 1
     211#error "Lemon assertion system is not set properly"
     212#endif
     213
     214#if ((defined(LEMON_ASSERT_LOG) ? 1 : 0) +              \
     215     (defined(LEMON_ASSERT_ABORT) ? 1 : 0) +            \
     216     (defined(LEMON_ASSERT_ERROR) ? 1 : 0) +            \
     217     (defined(LEMON_ASSERT_EXCEPTION) ? 1 : 0) +        \
     218     (defined(LEMON_ASSERT_CUSTOM) ? 1 : 0) == 1 ||     \
     219     defined(LEMON_ENABLE_ASSERT)) &&                   \
     220  defined(LEMON_DISABLE_ASSERTS)
     221#error "Lemon assertion system is not set properly"
     222#endif
     223
     224
     225#if defined LEMON_ASSERT_LOG
     226#  undef LEMON_ASSERT_HANDLER
     227#  define LEMON_ASSERT_HANDLER ::lemon::assert_fail_log
     228#elif defined LEMON_ASSERT_ABORT
     229#  undef LEMON_ASSERT_HANDLER
     230#  define LEMON_ASSERT_HANDLER ::lemon::assert_fail_abort
     231#elif defined LEMON_ASSERT_ERROR
     232#  undef LEMON_ASSERT_HANDLER
     233#  define LEMON_ASSERT_HANDLER ::lemon::assert_fail_error
     234#elif defined LEMON_ASSERT_EXCEPTION
     235#  undef LEMON_ASSERT_HANDLER
     236#  define LEMON_ASSERT_HANDLER ::lemon::assert_fail_exception
     237#elif defined LEMON_ASSERT_CUSTOM
     238#  undef LEMON_ASSERT_HANDLER
     239#  ifndef LEMON_CUSTOM_ASSERT_HANDLER
     240#    error "LEMON_CUSTOM_ASSERT_HANDLER is not set"
    599241#  endif
     242#  define LEMON_ASSERT_HANDLER LEMON_CUSTOM_ASSERT_HANDLER
     243#elif defined LEMON_ENABLE_ASSERTS
     244#  undef LEMON_ASSERT_HANDLER
     245#  define LEMON_ASSERT_HANDLER ::lemon::assert_fail_abort
     246#else
     247#  undef LEMON_ASSERT_HANDLER
     248#endif
     249
     250
     251#ifndef LEMON_FUNCTION_NAME
     252#  define LEMON_FUNCTION_NAME (__PRETTY_FUNCTION__)
    600253#endif
    601254
    602255#ifdef DOXYGEN
    603256
     257/// \ingroup exceptions
     258///
    604259/// \brief Macro for assertions with customizable message
    605260///
    606 /// Macro for assertions with customizable message.
     261/// Macro for assertions with customizable message. 
     262/// \param exp An expression convertible to bool. If the expression is
     263/// false, then an assertion is raised. The concrete behaviour depends
     264/// on the settings of the assertion system.
     265/// \param msg A \e const \e char*, a \e const std::string& or a \e
     266/// const \e std::exception& parameter. The variable can be used to
     267/// provide information about the circumstances of failed assertion.
    607268///
    608269/// The assertions are disabled in the default behaviour. You can
    609 /// enable the assertions with the
     270/// enable the assertions with the following code:
    610271/// \code
    611272/// #define LEMON_ENABLE_ASSERTS
    612273/// \endcode
    613 /// Then an assert
    614 /// provides a log on the standard error about the assertion and aborts
    615 /// the program if LEMON_ASSERT_DO_ABORT is also defined (otherwise the
    616 /// program keeps on running).
    617 /// By defining LEMON_ASSERT_FAILURE or
    618 /// LEMON_ASSERT_EXCEPTION, you can set other behaviour to the
    619 /// assertions. In case LEMON_ASSERT_FAILURE is given, LEMON_ASSERT
    620 /// will always throw an \c AssertionFailedError exception with
    621 /// the \c msg error message. By using
    622 /// LEMON_ASSERT_EXCEPTION, one can define an arbitrary exception to be thrown.
    623 ///
    624 /// The LEMON_ASSERT macro should be called with the \c exp parameter
    625 /// which should be an expression convertible to bool. If the given
    626 /// parameter is false the assertion is raised and one of the assertion
    627 /// behaviour will be activated. The \c msg should be either a const
    628 /// char* message or an exception. When the \c msg is an exception the
    629 /// \ref lemon::Exception::what() "what()" function is called to retrieve and
    630 /// display the error message.
    631 ///
    632 /// \todo We should provide some way to reset to the default behaviour,
    633 /// shouldn't we?
    634 ///
    635 /// \todo This whole 'assert' business should be placed in a separate
    636 /// include file. The boost assert is not guarded by header sentries
    637 /// which may help to change the behaviour of the assertions in
    638 /// the files.
    639 ///
    640 /// \todo __PRETTY_FUNCTION__ should be replaced by something
    641 /// compiler-independent, like BOOST_CURRENT_FUNCTION
    642 
    643 #  define LEMON_ASSERT(exp, msg)                 \
    644      (static_cast<void> (!!(exp) ? 0 : (         \
    645        LEMON_ASSERT_HANDLER(__FILE__, __LINE__,  \
    646                             __PRETTY_FUNCTION__, \
    647                             msg, #exp, LEMON_ASSERT_DO_ABORT), 0)))
     274/// or with compilation parameters:
     275/// \code
     276/// g++ -DLEMON_ENABLE_ASSERTS
     277/// make CXXFLAGS='-DLEMON_ENABLE_ASSERTS'
     278/// \endcode
     279///
     280/// The %lemon assertion system has a wide range of customization
     281/// properties. As default behaviour the failed assertion prints a
     282/// short log message to the standard ouput and aborts the execution.
     283///
     284/// The following modes can be used in the assertion system:
     285///
     286/// - \e LEMON_ASSERT_LOG The failed assert print a short convenient
     287///   error message to the standard error and continues the
     288///   execution.
     289/// - \e LEMON_ASSERT_ABORT This mode is similar to the \e
     290///   LEMON_ASSERT_LOG, but it aborts the program. It is the default
     291///   operation mode when the asserts are enabled with \e
     292///   LEMON_ENABLE_ASSERTS.
     293/// - \e LEMON_ASSERT_ERROR The assert throws an \ref
     294///   lemon::AssertionFailedError "AssertionFailedError". If the \c
     295///   msg parameter is an exception, then the result of the \ref
     296///   lemon::Exception::what() "what()" member function is passed as
     297///   error message.
     298/// - \e LEMON_ASSERT_EXCEPTION If the specified \c msg is an
     299///   exception then it raised directly (solving that the exception
     300///   can not be thrown polymorphically), otherwise an \ref
     301///   lemon::AssertionFailedError "AssertionFailedError" is thrown with
     302///   the given parameter.
     303/// - \e LEMON_ASSERT_CUSTOM The user can define an own assertion
     304///   handler functions. Three overloaded functions should be defined
     305///   with the following parameter lists:
     306///   \code
     307///     void custom_assert_handler(const char* file, int line,
     308///                                const char* function, const char* message, const char* expression);
     309///     void custom_assert_handler(const char* file, int line,
     310///                                const char* function, const std::string& message, const char* expression);
     311///     void custom_assert_handler(const char* file, int line,
     312///                                const char* function, const std::exception& message, const char* expression);
     313///   \endcode
     314///   The name of the functions should be defined as the \c
     315///   LEMON_CUSTOM_ASSERT_HANDLER macro name.
     316///   \code
     317///     #define LEMON_CUSTOM_ASSERT_HANDLER custom_assert_handler
     318///   \endcode
     319///   Whenever an assertion is occured, one of the custom assertion
     320///   handler is called with appropiate parameters.
     321///
     322/// The assertion mode can be changed within one compilation unit, if
     323/// the macros are redefined with other settings and the
     324/// lemon/assert.h file is reincluded then the behaviour is changed
     325/// appropiately to the new settings.
     326#  define LEMON_ASSERT(exp, msg)                                        \
     327  (static_cast<void> (!!(exp) ? 0 : (                                   \
     328    LEMON_ASSERT_HANDLER(__FILE__, __LINE__,                            \
     329                         LEMON_FUNCTION_NAME,                           \
     330                         msg, #exp), 0)))
     331
     332
     333/// \ingroup exceptions
     334///
     335/// \brief Macro for mark not yet implemented features.
     336///
     337/// Macro for mark not yet implemented features and outstanding bugs.
     338/// It is close to be the shortcut of the following code:
     339/// \code
     340///   LEMON_ASSERT(false, msg);
     341/// \endcode
     342#  define LEMON_FIXME(msg)                                              \
     343       (LEMON_ASSERT_HANDLER(__FILE__, __LINE__, LEMON_FUNCTION_NAME,   \
     344                             "FIXME: " msg, static_cast<const char*>(0)))
    648345
    649346#else
    650 #  if defined LEMON_DISABLE_ASSERTS
    651 
     347
     348#  ifndef LEMON_ASSERT_HANDLER
    652349#    define LEMON_ASSERT(exp, msg)  (static_cast<void> (0))
    653 
     350#    define LEMON_FIXME(msg) (static_cast<void>(0))
    654351#  else
    655352#    define LEMON_ASSERT(exp, msg)                 \
    656353       (static_cast<void> (!!(exp) ? 0 : (         \
    657354         LEMON_ASSERT_HANDLER(__FILE__, __LINE__,  \
    658                               __PRETTY_FUNCTION__, \
    659                               msg, #exp, LEMON_ASSERT_DO_ABORT), 0)))
     355                              LEMON_FUNCTION_NAME, \
     356                              msg, #exp), 0)))
     357#    define LEMON_FIXME(msg) \
     358       (LEMON_ASSERT_HANDLER(__FILE__, __LINE__, LEMON_FUNCTION_NAME,   \
     359                             "FIXME: " msg,  static_cast<const char*>(0)))
    660360#  endif
    661 #endif
    662 
    663 /**
    664  * \brief Macro for mark not yet implemented features.
    665  *
    666  * \todo Is this the right place for this? It should be used only in
    667  * modules under development.
    668  *
    669  * \todo __PRETTY_FUNCTION__ should be replaced by something
    670  * compiler-independent, like BOOST_CURRENT_FUNCTION
    671  */
    672 
    673 #define LEMON_FIXME(msg) \
    674     (LEMON_ASSERT_HANDLER(__FILE__, __LINE__, __PRETTY_FUNCTION__, \
    675                           "FIXME: " msg))
     361
     362#endif
     363
     364
  • lemon/error.h

    r66 r108  
    9494  };
    9595
    96   /// Exception-safe convenient "error message" class.
     96  /// Exception-safe convenient error message builder class.
    9797
    9898  /// Helper class which provides a convenient ostream-like (operator <<
     
    414414  };
    415415
    416 
    417   ///\e
    418   class AssertionFailedError : public LogicError {
    419   protected:
    420     const char *assertion;
    421     const char *file;
    422     int line;
    423     const char *function;
    424     const char *message;
    425 
    426     mutable ExceptionMember<std::string> _message_holder;
    427   public:
    428     ///\e
    429     AssertionFailedError(const char *_file, int _line, const char *func,
    430                          const char *msg, const char *_assertion = 0) :
    431       assertion(_assertion), file(_file), line(_line), function(func),
    432       message(msg) {}
    433 
    434     ///\e
    435     const char* get_assertion() const { return assertion; }
    436     ///\e
    437     const char* get_message() const { return message; }
    438     ///\e
    439     const char* get_file() const { return file; }
    440     ///\e
    441     const char* get_function() const { return function; }
    442     ///\e
    443     int get_line() const { return line; }
    444 
    445 
    446     virtual const char* what() const throw() {
    447       try {
    448         std::ostringstream ostr;
    449         ostr << file << ":" << line << ": ";
    450         if( function )
    451           ostr << function << ": ";
    452         ostr << message;
    453         if( assertion )
    454            ostr << " (assertion '" << assertion << "' failed)";
    455         _message_holder.set(ostr.str());
    456         return ostr.str().c_str();
    457       }
    458       catch(...) {}
    459       if( _message_holder.valid() ) return _message_holder.get().c_str();
    460       return "lemon::AssertionFailedError";
    461     }
    462    virtual ~AssertionFailedError() throw() {}
    463   };
    464 
    465 
    466   /****************  Macros  ****************/
    467 
    468 
    469   template <typename Exception>
    470   inline void assert_fail(const char *file, int line,
    471                           const char *func,
    472                           Exception exception,
    473                           const char *assertion = 0,
    474                           bool do_abort=true)
    475   {
    476     using namespace std;
    477     cerr << file << ":" << line << ": ";
    478     if (func)
    479       cerr << func << ": ";
    480     cerr << exception.what();
    481     if (assertion)
    482       cerr << " (assertion '" << assertion << "' failed)";
    483     cerr << endl;
    484     if (do_abort)
    485       abort();
    486   }
    487 
    488   template <>
    489   inline void assert_fail<const char *>(const char *file, int line,
    490                                         const char *func,
    491                                         const char *message,
    492                                         const char *assertion,
    493                                         bool do_abort)
    494   {
    495     using namespace std;
    496     cerr << file << ":" << line << ": ";
    497     if (func)
    498       cerr << func << ": ";
    499     cerr << message;
    500     if (assertion)
    501       cerr << " (assertion '" << assertion << "' failed)";
    502     cerr << endl;
    503     if (do_abort)
    504       abort();
    505   }
    506 
    507   template <>
    508   inline void assert_fail<std::string>(const char *file, int line,
    509                                        const char *func,
    510                                        std::string message,
    511                                        const char *assertion,
    512                                        bool do_abort)
    513   {
    514     assert_fail(file, line, func, message.c_str(), assertion, do_abort);
    515   }
    516 
    517   template <typename Exception>
    518   inline void assert_fail_failure(const char *file, int line, const char *func,
    519                            Exception exception,
    520                            const char *assertion = 0,
    521                            bool = true)
    522   {
    523     throw AssertionFailedError(file, line, func, exception.what(), assertion);
    524   }
    525 
    526   template <>
    527   inline void assert_fail_failure<const char *>(const char *file, int line,
    528                                                 const char *func,
    529                                                 const char *message,
    530                                                 const char *assertion,
    531                                                 bool)
    532   {
    533     throw AssertionFailedError(file, line, func, message, assertion);
    534   }
    535 
    536   template <>
    537   inline void assert_fail_failure<std::string>(const char *file, int line,
    538                                                const char *func,
    539                                                std::string message,
    540                                                const char *assertion,
    541                                                bool)
    542   {
    543     assert_fail_failure(file, line, func, message.c_str(), assertion, true);
    544   }
    545 
    546   template <typename Exception>
    547   inline void assert_fail_exception(const char *file, int line, const char *func,
    548                              Exception exception,
    549                              const char *assertion = 0, bool = true)
    550   {
    551     throw exception;
    552   }
    553 
    554   template <>
    555   inline void assert_fail_exception<const char *>(const char *file, int line,
    556                                            const char *func,
    557                                            const char *message,
    558                                            const char *assertion,
    559                                            bool)
    560   {
    561     throw AssertionFailedError(file, line, func, message, assertion);
    562   }
    563 
    564   template <>
    565   inline void assert_fail_exception<std::string>(const char *file, int line,
    566                                                  const char *func,
    567                                                  std::string message,
    568                                                  const char *assertion,
    569                                                  bool)
    570   {
    571     assert_fail_exception(file, line, func, message.c_str(), assertion, true);
    572   }
    573 
    574 /// @}
     416  /// @}
    575417
    576418}
     419
    577420#endif // LEMON_ERROR_H
    578 
    579 #undef LEMON_ASSERT
    580 #undef LEMON_FIXME
    581 
    582 #ifdef LEMON_ENABLE_ASSERTS
    583 #  define LEMON_ASSERT_ABORT
    584 #endif
    585 
    586 #ifndef LEMON_ASSERT_DO_ABORT
    587 #  define LEMON_ASSERT_DO_ABORT 1
    588 #endif
    589 
    590 #ifndef LEMON_ASSERT_HANDLER
    591 #  if defined LEMON_ASSERT_EXCEPTION
    592 #    define LEMON_ASSERT_HANDLER ::lemon::assert_fail_exception
    593 #  elif defined LEMON_ASSERT_FAILURE
    594 #    define LEMON_ASSERT_HANDLER ::lemon::assert_fail_failure
    595 #  elif defined LEMON_ASSERT_ABORT
    596 #    define LEMON_ASSERT_HANDLER ::lemon::assert_fail
    597 #  else
    598 #    define LEMON_DISABLE_ASSERTS
    599 #  endif
    600 #endif
    601 
    602 #ifdef DOXYGEN
    603 
    604 /// \brief Macro for assertions with customizable message
    605 ///
    606 /// Macro for assertions with customizable message.
    607 ///
    608 /// The assertions are disabled in the default behaviour. You can
    609 /// enable the assertions with the
    610 /// \code
    611 /// #define LEMON_ENABLE_ASSERTS
    612 /// \endcode
    613 /// Then an assert
    614 /// provides a log on the standard error about the assertion and aborts
    615 /// the program if LEMON_ASSERT_DO_ABORT is also defined (otherwise the
    616 /// program keeps on running).
    617 /// By defining LEMON_ASSERT_FAILURE or
    618 /// LEMON_ASSERT_EXCEPTION, you can set other behaviour to the
    619 /// assertions. In case LEMON_ASSERT_FAILURE is given, LEMON_ASSERT
    620 /// will always throw an \c AssertionFailedError exception with
    621 /// the \c msg error message. By using
    622 /// LEMON_ASSERT_EXCEPTION, one can define an arbitrary exception to be thrown.
    623 ///
    624 /// The LEMON_ASSERT macro should be called with the \c exp parameter
    625 /// which should be an expression convertible to bool. If the given
    626 /// parameter is false the assertion is raised and one of the assertion
    627 /// behaviour will be activated. The \c msg should be either a const
    628 /// char* message or an exception. When the \c msg is an exception the
    629 /// \ref lemon::Exception::what() "what()" function is called to retrieve and
    630 /// display the error message.
    631 ///
    632 /// \todo We should provide some way to reset to the default behaviour,
    633 /// shouldn't we?
    634 ///
    635 /// \todo This whole 'assert' business should be placed in a separate
    636 /// include file. The boost assert is not guarded by header sentries
    637 /// which may help to change the behaviour of the assertions in
    638 /// the files.
    639 ///
    640 /// \todo __PRETTY_FUNCTION__ should be replaced by something
    641 /// compiler-independent, like BOOST_CURRENT_FUNCTION
    642 
    643 #  define LEMON_ASSERT(exp, msg)                 \
    644      (static_cast<void> (!!(exp) ? 0 : (         \
    645        LEMON_ASSERT_HANDLER(__FILE__, __LINE__,  \
    646                             __PRETTY_FUNCTION__, \
    647                             msg, #exp, LEMON_ASSERT_DO_ABORT), 0)))
    648 
    649 #else
    650 #  if defined LEMON_DISABLE_ASSERTS
    651 
    652 #    define LEMON_ASSERT(exp, msg)  (static_cast<void> (0))
    653 
    654 #  else
    655 #    define LEMON_ASSERT(exp, msg)                 \
    656        (static_cast<void> (!!(exp) ? 0 : (         \
    657          LEMON_ASSERT_HANDLER(__FILE__, __LINE__,  \
    658                               __PRETTY_FUNCTION__, \
    659                               msg, #exp, LEMON_ASSERT_DO_ABORT), 0)))
    660 #  endif
    661 #endif
    662 
    663 /**
    664  * \brief Macro for mark not yet implemented features.
    665  *
    666  * \todo Is this the right place for this? It should be used only in
    667  * modules under development.
    668  *
    669  * \todo __PRETTY_FUNCTION__ should be replaced by something
    670  * compiler-independent, like BOOST_CURRENT_FUNCTION
    671  */
    672 
    673 #define LEMON_FIXME(msg) \
    674     (LEMON_ASSERT_HANDLER(__FILE__, __LINE__, __PRETTY_FUNCTION__, \
    675                           "FIXME: " msg))
Note: See TracChangeset for help on using the changeset viewer.