COIN-OR::LEMON - Graph Library

source: lemon-0.x/lemon/error.h @ 1979:c2992fd74dad

Last change on this file since 1979:c2992fd74dad was 1956:a055123339d5, checked in by Alpar Juttner, 18 years ago

Unified copyright notices

File size: 15.3 KB
RevLine 
[906]1/* -*- C++ -*-
2 *
[1956]3 * This file is a part of LEMON, a generic C++ optimization library
4 *
5 * Copyright (C) 2003-2006
6 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
7 * (Egervary Research Group on Combinatorial Optimization, 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
[1536]104
105    ///\todo The good solution is boost::shared_ptr...
106    ///
[1157]107    mutable
108    std::auto_ptr<std::ostringstream> buf;
[1056]109   
[1067]110    ///\e
[1056]111    bool init() throw() {
112      try {
113        buf.reset(new std::ostringstream);
114      }
115      catch(...) {
116        buf.reset();
117      }
[1157]118      return buf.get();
[1056]119    }
120
121  public:
122
[1067]123    ///\e
[1056]124    ErrorMessage() throw() { init(); }
125
[1157]126    ErrorMessage(const ErrorMessage& em) throw() : buf(em.buf) { }
127
[1067]128    ///\e
[1056]129    ErrorMessage(const char *message) throw() {
130      init();
131      *this << message;
132    }
133
[1067]134    ///\e
[1056]135    ErrorMessage(const std::string &message) throw() {
136      init();
137      *this << message;
138    }
139
[1067]140    ///\e
[1056]141    template <typename T>
142    ErrorMessage& operator<<(const T &t) throw() {
[1157]143      if( ! buf.get() ) return *this;
[1056]144
145      try {
146        *buf << t;
147      }
148      catch(...) {
149        buf.reset();
150      }
[1207]151      return *this;
[1056]152    }
153
[1067]154    ///\e
[1056]155    const char* message() throw() {
[1157]156      if( ! buf.get() ) return 0;
[1056]157
158      const char* mes = 0;
159      try {
160        mes = buf->str().c_str();
161      }
162      catch(...) {}
163      return mes;
164    }
165   
166  };
167
[883]168  /**
169   * \brief Generic exception class.
170   *
[1056]171   * Base class for exceptions used in LEMON.
[883]172   */
[1067]173  class Exception : public std::exception {
[883]174  public:
[1067]175    ///\e
[1120]176    Exception() {}
[1067]177    ///\e
[883]178    virtual ~Exception() throw() {}
[1120]179
180    ///\e
181    virtual const char* exceptionName() const {
182      return "lemon::Exception";
183    }
[883]184   
[1067]185    ///\e
[883]186    virtual const char* what() const throw() {
[1120]187      return exceptionName();
[1056]188    }
189  };
190
[1120]191  /**
192   * \brief One of the two main subclasses of \ref Exception.
193   *
194   * Logic errors represent problems in the internal logic of a program;
195   * in theory, these are preventable, and even detectable before the
196   * program runs (e.g., violations of class invariants).
197   *
[1125]198   * A typical example for this is \ref UninitializedParameter.
[1120]199   */
[1056]200  class LogicError : public Exception {
[1067]201  public:
[1120]202    virtual const char* exceptionName() const {
203      return "lemon::LogicError";
204    }
[1056]205  };
206
[1125]207  /**
208   * \brief \ref Exception for uninitialized parameters.
209   *
210   * This error represents problems in the initialization
211   * of the parameters of the algorithms.
212   */
213  class UninitializedParameter : public LogicError {
214  public:
215    virtual const char* exceptionName() const {
216      return "lemon::UninitializedParameter";
217    }
218  };
219
[1120]220 
221  /**
222   * \brief One of the two main subclasses of \ref Exception.
223   *
224   * Runtime errors represent problems outside the scope of a program;
225   * they cannot be easily predicted and can generally only be caught as
226   * the program executes.
227   */
[1056]228  class RuntimeError : public Exception {
[1067]229  public:
[1120]230    virtual const char* exceptionName() const {
231      return "lemon::RuntimeError";
232    }
[1056]233  };
234
[1067]235  ///\e
[1056]236  class RangeError : public RuntimeError {
[1067]237  public:
[1120]238    virtual const char* exceptionName() const {
239      return "lemon::RangeError";
240    }
[1056]241  };
242
[1061]243  ///\e
[1056]244  class IOError : public RuntimeError {
[1067]245  public:
[1120]246    virtual const char* exceptionName() const {
247      return "lemon::IOError";
248    }
[1056]249  };
250
[1061]251  ///\e
[1056]252  class DataFormatError : public IOError {
[1067]253  protected:
[1207]254    ExceptionMember<std::string> _message;
255    ExceptionMember<std::string> _file;
[1120]256    int _line;
[1157]257
[1207]258    mutable ExceptionMember<std::string> _message_holder;
[1067]259  public:
[1157]260
261    DataFormatError(const DataFormatError &dfe) :
[1207]262      IOError(dfe), _message(dfe._message), _file(dfe._file),
263      _line(dfe._line) {}
[1157]264
[1067]265    ///\e
[1120]266    explicit DataFormatError(const char *the_message)
267      : _message(the_message), _line(0) {}
[1207]268
[1067]269    ///\e
[1056]270    DataFormatError(const std::string &file_name, int line_num,
[1120]271                    const char *the_message)
272      : _message(the_message), _line(line_num) { file(file_name); }
[1056]273
[1067]274    ///\e
[1207]275    void line(int line) { _line = line; }
[1067]276    ///\e
[1207]277    void message(const std::string& message) { _message.set(message); }
[1120]278    ///\e
[1207]279    void file(const std::string &file) { _file.set(file); }
280 
281    ///\e
282    int line() const { return _line; }
283    ///\e
284    const char* message() const {
285      if (_message.valid() && !_message.get().empty()) {
286        return _message.get().c_str();
287      } else {
288        return 0;
[1056]289      }
[883]290    }
291
[1067]292    /// \brief Returns the filename.
293    ///
[1207]294    /// Returns \e null if the filename was not specified.
[1120]295    const char* file() const {
[1207]296      if (_file.valid() && !_file.get().empty()) {
297        return _file.get().c_str();
298      } else {
299        return 0;
300      }
[1067]301    }
302
303    ///\e
304    virtual const char* what() const throw() {
[1056]305      try {
306        std::ostringstream ostr;
[1399]307        ostr << exceptionName() << ": ";
[1207]308        if (message()) ostr << message();
309        if( file() || line() != 0 ) {
[1056]310          ostr << " (";
[1207]311          if( file() ) ostr << "in file '" << file() << "'";
312          if( file() && line() != 0 ) ostr << " ";
313          if( line() != 0 ) ostr << "at line " << line();
[1067]314          ostr << ")";
[1056]315        }
[1207]316        _message_holder.set(ostr.str());
[1056]317      }
[1207]318      catch (...) {}
319      if( _message_holder.valid()) return _message_holder.get().c_str();
[1120]320      return exceptionName();
321    }
322
323    virtual const char* exceptionName() const {
[1056]324      return "lemon::DataFormatError";
325    }
[1067]326
327    virtual ~DataFormatError() throw() {}
[883]328  };
329
[1746]330  ///\e
331  class FileOpenError : public IOError {
332  protected:
333    ExceptionMember<std::string> _file;
334
335    mutable ExceptionMember<std::string> _message_holder;
336  public:
337
338    FileOpenError(const FileOpenError &foe) :
339      IOError(foe), _file(foe._file) {}
340
341    ///\e
342    explicit FileOpenError(const std::string& file)
343      : _file(file) {}
344
345
346    ///\e
347    void file(const std::string &file) { _file.set(file); }
348 
349    /// \brief Returns the filename.
350    ///
351    /// Returns \e null if the filename was not specified.
352    const char* file() const {
353      if (_file.valid() && !_file.get().empty()) {
354        return _file.get().c_str();
355      } else {
356        return 0;
357      }
358    }
359
360    ///\e
361    virtual const char* what() const throw() {
362      try {
363        std::ostringstream ostr;
364        ostr << exceptionName() << ": ";
365        ostr << "Cannot open file - " << file();
366        _message_holder.set(ostr.str());
367      }
368      catch (...) {}
369      if( _message_holder.valid()) return _message_holder.get().c_str();
370      return exceptionName();
371    }
372
373    virtual const char* exceptionName() const {
374      return "lemon::FileOpenError";
375    }
376
377    virtual ~FileOpenError() throw() {}
378  };
379
[1845]380  class IOParameterError : public IOError {
[1207]381  protected:
382    ExceptionMember<std::string> _message;
383    ExceptionMember<std::string> _file;
384
385    mutable ExceptionMember<std::string> _message_holder;
386  public:
387
[1213]388    IOParameterError(const IOParameterError &ile) :
[1845]389      IOError(ile), _message(ile._message), _file(ile._file) {}
[1207]390
391    ///\e
[1213]392    explicit IOParameterError(const char *the_message)
393      : _message(the_message) {}
[1207]394
395    ///\e
[1213]396    IOParameterError(const char *file_name, const char *the_message)
[1393]397      : _message(the_message), _file(file_name) {}
[1207]398
399     ///\e
400    void message(const std::string& message) { _message.set(message); }
401    ///\e
402    void file(const std::string &file) { _file.set(file); }
403 
404     ///\e
405    const char* message() const {
406      if (_message.valid()) {
407        return _message.get().c_str();
408      } else {
409        return 0;
410      }
411    }
412
413    /// \brief Returns the filename.
414    ///
415    /// Returns \e null if the filename was not specified.
416    const char* file() const {
417      if (_file.valid()) {
418        return _file.get().c_str();
419      } else {
420        return 0;
421      }
422    }
423
424    ///\e
425    virtual const char* what() const throw() {
426      try {
427        std::ostringstream ostr;
428        if (message()) ostr << message();
429        if (file()) ostr << "(when reading file '" << file() << "')";
430        _message_holder.set(ostr.str());
431      }
432      catch (...) {}
433      if( _message_holder.valid() ) return _message_holder.get().c_str();
434      return exceptionName();
435    }
436
437    virtual const char* exceptionName() const {
[1213]438      return "lemon::IOParameterError";
[1207]439    }
440
[1213]441    virtual ~IOParameterError() throw() {}
[1207]442  };
443
[1056]444
[1068]445  ///\e
[1067]446  class AssertionFailedError : public LogicError {
447  protected:
448    const char *assertion;
449    const char *file;
450    int line;
451    const char *function;
452    const char *message;
[1213]453
454    mutable ExceptionMember<std::string> _message_holder;
[1067]455  public:
456    ///\e
457    AssertionFailedError(const char *_file, int _line, const char *func,
458                         const char *msg, const char *_assertion = 0) :
459      assertion(_assertion), file(_file), line(_line), function(func),
460      message(msg) {}
461
462    ///\e
463    const char* get_assertion() const { return assertion; }
464    ///\e
465    const char* get_message() const { return message; }
466    ///\e
467    const char* get_file() const { return file; }
468    ///\e
469    const char* get_function() const { return function; }
470    ///\e
471    int get_line() const { return line; }
472
473
474    virtual const char* what() const throw() {
475      try {
476        std::ostringstream ostr;
477        ostr << file << ":" << line << ": ";
478        if( function )
479          ostr << function << ": ";
480        ostr << message;
481        if( assertion )
[1213]482           ostr << " (assertion '" << assertion << "' failed)";
483        _message_holder.set(ostr.str());
[1209]484        return ostr.str().c_str();
[1067]485      }
486      catch(...) {}
[1213]487      if( _message_holder.valid() ) return _message_holder.get().c_str();
[1120]488      return exceptionName();
489    }
490
491    virtual const char* exceptionName() const {
[1067]492      return "lemon::AssertionFailedError";
493    }
494
495    virtual ~AssertionFailedError() throw() {}
496  };
497
[1056]498
499  /****************  Macros  ****************/
500
501
[1785]502  template <typename Exception>
503  inline void assert_fail(const char *file, int line, const char *func,
504                   Exception exception, const char *assertion = 0,
[1067]505                   bool do_abort=true)
506  {
507    using namespace std;
508    cerr << file << ":" << line << ": ";
509    if( func )
510      cerr << func << ": ";
[1785]511    cerr << exception.what();
512    if( assertion )
513      cerr << " (assertion '" << assertion << "' failed)";
514    cerr << endl;
515    if(do_abort)
516      abort();
517  }
518
519  template <>
520  inline void assert_fail<const char *>(const char *file, int line, const char *func,
521                                 const char *message,
522                                 const char *assertion,
523                                 bool do_abort)
524  {
525    using namespace std;
526    cerr << file << ":" << line << ": ";
527    if( func )
528      cerr << func << ": ";
[1067]529    cerr << message;
530    if( assertion )
531      cerr << " (assertion '" << assertion << "' failed)";
532    cerr << endl;
533    if(do_abort)
534      abort();
535  }
[1056]536
[1785]537  template <typename Exception>
538  inline void assert_fail_failure(const char *file, int line, const char *func,
539                           Exception exception,
540                           const char *assertion = 0,
541                           bool = true)
542  {
543    throw AssertionFailedError(file, line, func, exception.what(), assertion);
544  }
545
546  template <>
547  inline void assert_fail_failure<const char *>(const char *file, int line,
548                                         const char *func,
549                                         const char *message,
550                                         const char *assertion,
551                                         bool)
552  {
553    throw AssertionFailedError(file, line, func, message, assertion);
554  }
555
556  template <typename Exception>
557  inline void assert_fail_exception(const char *file, int line, const char *func,
558                             Exception exception,
559                             const char *assertion = 0, bool = true)
560  {
561    throw exception;
562  }
563
564  template <>
565  inline void assert_fail_exception<const char *>(const char *file, int line,
566                                           const char *func,
567                                           const char *message,
568                                           const char *assertion,
569                                           bool)
[1067]570  {
571    throw AssertionFailedError(file, line, func, message, assertion);
572  }
[1056]573
[1151]574/// @}
[883]575
576}
[921]577#endif // LEMON_ERROR_H
[1067]578
579#undef LEMON_ASSERT
580#undef LEMON_FIXME
581
582#ifndef LEMON_ASSERT_ABORT
583#  define LEMON_ASSERT_ABORT 1
584#endif
585
586#ifndef LEMON_ASSERT_HANDLER
[1785]587#  if defined LEMON_ASSERT_EXCEPTION
588#    define LEMON_ASSERT_HANDLER ::lemon::assert_fail_exception
589#  elif defined LEMON_ASSERT_FAILURE
590#    define LEMON_ASSERT_HANDLER ::lemon::assert_fail_failure
[1120]591#  else
592#    define LEMON_ASSERT_HANDLER ::lemon::assert_fail
593#  endif
[1067]594#endif
595
596#if defined(NDEBUG) || defined(LEMON_DISABLE_ASSERTS)
597
598#  define LEMON_ASSERT(exp, msg)  (static_cast<void> (0))
599
600#else
601
602/**
603 * \brief Macro for assertions with customizable message
604 *
[1120]605 * Macro for assertions with customizable message.
606 *
607 * The behaviour can be customized with LEMON_ASSERT_HANDLER,
608 * LEMON_ASSERT_EXCEPTION and LEMON_ASSERT_ABORT defines. Asserts can be
609 * disabled by defining either NDEBUG or LEMON_DISABLE_ASSERTS macros.
610 *
611 * \todo We should provide some way to reset to the default behaviour,
612 * shouldn't we?
613 *
614 * \todo This whole 'assert' business should be placed in a separate
[1785]615 * include file. The boost assert is not guarded by header sentries
616 * which may help to change the behaviour of the assertions in
617 * the files.
[1120]618 *
[1067]619 * \todo __PRETTY_FUNCTION__ should be replaced by something
[1274]620 * compiler-independent, like BOOST_CURRENT_FUNCTION
[1067]621 */
622
623#  define LEMON_ASSERT(exp, msg)                 \
624     (static_cast<void> (!!(exp) ? 0 : (         \
625       LEMON_ASSERT_HANDLER(__FILE__, __LINE__,  \
626                            __PRETTY_FUNCTION__, \
[1827]627                            msg, #exp, LEMON_ASSERT_ABORT), 0)))
[1067]628
[1120]629#endif // NDEBUG || LEMON_DISABLE_ASSERTS
[1067]630
631/**
632 * \brief Macro for mark not yet implemented features.
633 *
634 * \todo Is this the right place for this? It should be used only in
635 * modules under development.
636 *
637 * \todo __PRETTY_FUNCTION__ should be replaced by something
[1274]638 * compiler-independent, like BOOST_CURRENT_FUNCTION
[1067]639 */
640
641# define LEMON_FIXME(msg) \
642    (LEMON_ASSERT_HANDLER(__FILE__, __LINE__, __PRETTY_FUNCTION__, \
643                          "FIXME: " msg))
Note: See TracBrowser for help on using the repository browser.