COIN-OR::LEMON - Graph Library

source: lemon-0.x/src/lemon/error.h @ 1399:d3ae1f06843d

Last change on this file since 1399:d3ae1f06843d was 1399:d3ae1f06843d, checked in by Alpar Juttner, 19 years ago

DataFormatError::what() also prints the name of the exception.

File size: 12.6 KB
RevLine 
[906]1/* -*- C++ -*-
[1157]2 *
[921]3 * src/lemon/error.h - Part of LEMON, a generic C++ optimization library
[906]4 *
[1164]5 * Copyright (C) 2005 Egervary Jeno Kombinatorikus Optimalizalasi
[1359]6 * Kutatocsoport (Egervary Research Group on Combinatorial Optimization,
[1157]7 * EGRES).
[906]8 *
9 * Permission to use, modify and distribute this software is granted
10 * provided that this copyright notice appears in all copies. For
11 * precise terms see the accompanying LICENSE file.
12 *
13 * This software is provided "AS IS" with no warranty of any kind,
14 * express or implied, and with no claim as to its suitability for any
15 * purpose.
16 *
17 */
[883]18
[921]19#ifndef LEMON_ERROR_H
20#define LEMON_ERROR_H
[883]21
[1151]22//! \ingroup exceptions
[883]23//! \file
[1067]24//! \brief Basic exception classes and error handling.
[883]25
26#include <exception>
27#include <string>
28#include <sstream>
[1067]29#include <iostream>
30#include <cstdlib>
[1157]31#include <memory>
[883]32
[921]33namespace lemon {
[883]34
[1207]35  /// \addtogroup exceptions
36  /// @{
37 
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) {
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) {
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 {
89      return ptr.get() != 0;
90    }
91   
92  private:
93    std::auto_ptr<_Type> ptr;
94  };
[1151]95
[1056]96  /// Exception-safe convenient "error message" class.
[1067]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).
[1056]101  class ErrorMessage {
102  protected:
[1067]103    ///\e
[1157]104    ///\todo The good solution is boost:shared_ptr...
105    mutable
106    std::auto_ptr<std::ostringstream> buf;
[1056]107   
[1067]108    ///\e
[1056]109    bool init() throw() {
110      try {
111        buf.reset(new std::ostringstream);
112      }
113      catch(...) {
114        buf.reset();
115      }
[1157]116      return buf.get();
[1056]117    }
118
119  public:
120
[1067]121    ///\e
[1056]122    ErrorMessage() throw() { init(); }
123
[1157]124    ErrorMessage(const ErrorMessage& em) throw() : buf(em.buf) { }
125
[1067]126    ///\e
[1056]127    ErrorMessage(const char *message) throw() {
128      init();
129      *this << message;
130    }
131
[1067]132    ///\e
[1056]133    ErrorMessage(const std::string &message) throw() {
134      init();
135      *this << message;
136    }
137
[1067]138    ///\e
[1056]139    template <typename T>
140    ErrorMessage& operator<<(const T &t) throw() {
[1157]141      if( ! buf.get() ) return *this;
[1056]142
143      try {
144        *buf << t;
145      }
146      catch(...) {
147        buf.reset();
148      }
[1207]149      return *this;
[1056]150    }
151
[1067]152    ///\e
[1056]153    const char* message() throw() {
[1157]154      if( ! buf.get() ) return 0;
[1056]155
156      const char* mes = 0;
157      try {
158        mes = buf->str().c_str();
159      }
160      catch(...) {}
161      return mes;
162    }
163   
164  };
165
[883]166  /**
167   * \brief Generic exception class.
168   *
[1056]169   * Base class for exceptions used in LEMON.
[883]170   */
[1067]171  class Exception : public std::exception {
[883]172  public:
[1067]173    ///\e
[1120]174    Exception() {}
[1067]175    ///\e
[883]176    virtual ~Exception() throw() {}
[1120]177
178    ///\e
179    virtual const char* exceptionName() const {
180      return "lemon::Exception";
181    }
[883]182   
[1067]183    ///\e
[883]184    virtual const char* what() const throw() {
[1120]185      return exceptionName();
[1056]186    }
187  };
188
[1120]189  /**
190   * \brief One of the two main subclasses of \ref Exception.
191   *
192   * Logic errors represent problems in the internal logic of a program;
193   * in theory, these are preventable, and even detectable before the
194   * program runs (e.g., violations of class invariants).
195   *
[1125]196   * A typical example for this is \ref UninitializedParameter.
[1120]197   */
[1056]198  class LogicError : public Exception {
[1067]199  public:
[1120]200    virtual const char* exceptionName() const {
201      return "lemon::LogicError";
202    }
[1056]203  };
204
[1125]205  /**
206   * \brief \ref Exception for uninitialized parameters.
207   *
208   * This error represents problems in the initialization
209   * of the parameters of the algorithms.
210   */
211  class UninitializedParameter : public LogicError {
212  public:
213    virtual const char* exceptionName() const {
214      return "lemon::UninitializedParameter";
215    }
216  };
217
[1120]218 
219  /**
220   * \brief One of the two main subclasses of \ref Exception.
221   *
222   * Runtime errors represent problems outside the scope of a program;
223   * they cannot be easily predicted and can generally only be caught as
224   * the program executes.
225   */
[1056]226  class RuntimeError : public Exception {
[1067]227  public:
[1120]228    virtual const char* exceptionName() const {
229      return "lemon::RuntimeError";
230    }
[1056]231  };
232
[1067]233  ///\e
[1056]234  class RangeError : public RuntimeError {
[1067]235  public:
[1120]236    virtual const char* exceptionName() const {
237      return "lemon::RangeError";
238    }
[1056]239  };
240
[1061]241  ///\e
[1056]242  class IOError : public RuntimeError {
[1067]243  public:
[1120]244    virtual const char* exceptionName() const {
245      return "lemon::IOError";
246    }
[1056]247  };
248
[1061]249  ///\e
[1056]250  class DataFormatError : public IOError {
[1067]251  protected:
[1207]252    ExceptionMember<std::string> _message;
253    ExceptionMember<std::string> _file;
[1120]254    int _line;
[1157]255
[1207]256    mutable ExceptionMember<std::string> _message_holder;
[1067]257  public:
[1157]258
259    DataFormatError(const DataFormatError &dfe) :
[1207]260      IOError(dfe), _message(dfe._message), _file(dfe._file),
261      _line(dfe._line) {}
[1157]262
[1067]263    ///\e
[1120]264    explicit DataFormatError(const char *the_message)
265      : _message(the_message), _line(0) {}
[1207]266
[1067]267    ///\e
[1056]268    DataFormatError(const std::string &file_name, int line_num,
[1120]269                    const char *the_message)
270      : _message(the_message), _line(line_num) { file(file_name); }
[1056]271
[1067]272    ///\e
[1207]273    void line(int line) { _line = line; }
[1067]274    ///\e
[1207]275    void message(const std::string& message) { _message.set(message); }
[1120]276    ///\e
[1207]277    void file(const std::string &file) { _file.set(file); }
278 
279    ///\e
280    int line() const { return _line; }
281    ///\e
282    const char* message() const {
283      if (_message.valid() && !_message.get().empty()) {
284        return _message.get().c_str();
285      } else {
286        return 0;
[1056]287      }
[883]288    }
289
[1067]290    /// \brief Returns the filename.
291    ///
[1207]292    /// Returns \e null if the filename was not specified.
[1120]293    const char* file() const {
[1207]294      if (_file.valid() && !_file.get().empty()) {
295        return _file.get().c_str();
296      } else {
297        return 0;
298      }
[1067]299    }
300
301    ///\e
302    virtual const char* what() const throw() {
[1056]303      try {
304        std::ostringstream ostr;
[1399]305        ostr << exceptionName() << ": ";
[1207]306        if (message()) ostr << message();
307        if( file() || line() != 0 ) {
[1056]308          ostr << " (";
[1207]309          if( file() ) ostr << "in file '" << file() << "'";
310          if( file() && line() != 0 ) ostr << " ";
311          if( line() != 0 ) ostr << "at line " << line();
[1067]312          ostr << ")";
[1056]313        }
[1207]314        _message_holder.set(ostr.str());
[1056]315      }
[1207]316      catch (...) {}
317      if( _message_holder.valid()) return _message_holder.get().c_str();
[1120]318      return exceptionName();
319    }
320
321    virtual const char* exceptionName() const {
[1056]322      return "lemon::DataFormatError";
323    }
[1067]324
325    virtual ~DataFormatError() throw() {}
[883]326  };
327
[1213]328  class IOParameterError : public LogicError {
[1207]329  protected:
330    ExceptionMember<std::string> _message;
331    ExceptionMember<std::string> _file;
332
333    mutable ExceptionMember<std::string> _message_holder;
334  public:
335
[1213]336    IOParameterError(const IOParameterError &ile) :
337      LogicError(ile), _message(ile._message), _file(ile._file) {}
[1207]338
339    ///\e
[1213]340    explicit IOParameterError(const char *the_message)
341      : _message(the_message) {}
[1207]342
343    ///\e
[1213]344    IOParameterError(const char *file_name, const char *the_message)
[1393]345      : _message(the_message), _file(file_name) {}
[1207]346
347     ///\e
348    void message(const std::string& message) { _message.set(message); }
349    ///\e
350    void file(const std::string &file) { _file.set(file); }
351 
352     ///\e
353    const char* message() const {
354      if (_message.valid()) {
355        return _message.get().c_str();
356      } else {
357        return 0;
358      }
359    }
360
361    /// \brief Returns the filename.
362    ///
363    /// Returns \e null if the filename was not specified.
364    const char* file() const {
365      if (_file.valid()) {
366        return _file.get().c_str();
367      } else {
368        return 0;
369      }
370    }
371
372    ///\e
373    virtual const char* what() const throw() {
374      try {
375        std::ostringstream ostr;
376        if (message()) ostr << message();
377        if (file()) ostr << "(when reading file '" << file() << "')";
378        _message_holder.set(ostr.str());
379      }
380      catch (...) {}
381      if( _message_holder.valid() ) return _message_holder.get().c_str();
382      return exceptionName();
383    }
384
385    virtual const char* exceptionName() const {
[1213]386      return "lemon::IOParameterError";
[1207]387    }
388
[1213]389    virtual ~IOParameterError() throw() {}
[1207]390  };
391
[1056]392
[1068]393  ///\e
[1067]394  class AssertionFailedError : public LogicError {
395  protected:
396    const char *assertion;
397    const char *file;
398    int line;
399    const char *function;
400    const char *message;
[1213]401
402    mutable ExceptionMember<std::string> _message_holder;
[1067]403  public:
404    ///\e
405    AssertionFailedError(const char *_file, int _line, const char *func,
406                         const char *msg, const char *_assertion = 0) :
407      assertion(_assertion), file(_file), line(_line), function(func),
408      message(msg) {}
409
410    ///\e
411    const char* get_assertion() const { return assertion; }
412    ///\e
413    const char* get_message() const { return message; }
414    ///\e
415    const char* get_file() const { return file; }
416    ///\e
417    const char* get_function() const { return function; }
418    ///\e
419    int get_line() const { return line; }
420
421
422    virtual const char* what() const throw() {
423      try {
424        std::ostringstream ostr;
425        ostr << file << ":" << line << ": ";
426        if( function )
427          ostr << function << ": ";
428        ostr << message;
429        if( assertion )
[1213]430           ostr << " (assertion '" << assertion << "' failed)";
431        _message_holder.set(ostr.str());
[1209]432        return ostr.str().c_str();
[1067]433      }
434      catch(...) {}
[1213]435      if( _message_holder.valid() ) return _message_holder.get().c_str();
[1120]436      return exceptionName();
437    }
438
439    virtual const char* exceptionName() const {
[1067]440      return "lemon::AssertionFailedError";
441    }
442
443    virtual ~AssertionFailedError() throw() {}
444  };
445
[1056]446
447  /****************  Macros  ****************/
448
449
[1067]450  inline
451  void assert_fail(const char *file, int line, const char *func,
452                   const char *message, const char *assertion = 0,
453                   bool do_abort=true)
454  {
455    using namespace std;
456    cerr << file << ":" << line << ": ";
457    if( func )
458      cerr << func << ": ";
459    cerr << message;
460    if( assertion )
461      cerr << " (assertion '" << assertion << "' failed)";
462    cerr << endl;
463    if(do_abort)
464      abort();
465  }
[1056]466
[1067]467  inline
468  void assert_fail_throw(const char *file, int line, const char *func,
469                   const char *message, const char *assertion = 0,
470                   bool = true)
471  {
472    throw AssertionFailedError(file, line, func, message, assertion);
473  }
[1056]474
[1151]475/// @}
[883]476
477}
[921]478#endif // LEMON_ERROR_H
[1067]479
480#undef LEMON_ASSERT
481#undef LEMON_FIXME
482
483#ifndef LEMON_ASSERT_ABORT
484#  define LEMON_ASSERT_ABORT 1
485#endif
486
487#ifndef LEMON_ASSERT_HANDLER
[1120]488#  ifdef LEMON_ASSERT_EXCEPTION
489#    define LEMON_ASSERT_HANDLER ::lemon::assert_fail_throw
490#  else
491#    define LEMON_ASSERT_HANDLER ::lemon::assert_fail
492#  endif
[1067]493#endif
494
495#if defined(NDEBUG) || defined(LEMON_DISABLE_ASSERTS)
496
497#  define LEMON_ASSERT(exp, msg)  (static_cast<void> (0))
498
499#else
500
501/**
502 * \brief Macro for assertions with customizable message
503 *
[1120]504 * Macro for assertions with customizable message.
505 *
506 * The behaviour can be customized with LEMON_ASSERT_HANDLER,
507 * LEMON_ASSERT_EXCEPTION and LEMON_ASSERT_ABORT defines. Asserts can be
508 * disabled by defining either NDEBUG or LEMON_DISABLE_ASSERTS macros.
509 *
510 * \todo We should provide some way to reset to the default behaviour,
511 * shouldn't we?
512 *
513 * \todo This whole 'assert' business should be placed in a separate
514 * include file.
515 *
[1067]516 * \todo __PRETTY_FUNCTION__ should be replaced by something
[1274]517 * compiler-independent, like BOOST_CURRENT_FUNCTION
[1067]518 */
519
520#  define LEMON_ASSERT(exp, msg)                 \
521     (static_cast<void> (!!(exp) ? 0 : (         \
522       LEMON_ASSERT_HANDLER(__FILE__, __LINE__,  \
523                            __PRETTY_FUNCTION__, \
524                            (msg), #exp, LEMON_ASSERT_ABORT), 0)))
525
[1120]526#endif // NDEBUG || LEMON_DISABLE_ASSERTS
[1067]527
528/**
529 * \brief Macro for mark not yet implemented features.
530 *
531 * \todo Is this the right place for this? It should be used only in
532 * modules under development.
533 *
534 * \todo __PRETTY_FUNCTION__ should be replaced by something
[1274]535 * compiler-independent, like BOOST_CURRENT_FUNCTION
[1067]536 */
537
538# define LEMON_FIXME(msg) \
539    (LEMON_ASSERT_HANDLER(__FILE__, __LINE__, __PRETTY_FUNCTION__, \
540                          "FIXME: " msg))
Note: See TracBrowser for help on using the repository browser.