COIN-OR::LEMON - Graph Library

source: lemon-0.x/lemon/error.h @ 2150:cce8ac91c08c

Last change on this file since 2150:cce8ac91c08c was 2150:cce8ac91c08c, checked in by Balazs Dezso, 13 years ago

Disable assertions in default behaviour
Documentation changed

File size: 16.7 KB
Line 
1/* -*- C++ -*-
2 *
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).
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 */
18
19#ifndef LEMON_ERROR_H
20#define LEMON_ERROR_H
21
22//! \ingroup exceptions
23//! \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>
32
33namespace lemon {
34
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  };
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 {
102  protected:
103    ///\e
104
105    ///\todo The good solution is boost::shared_ptr...
106    ///
107    mutable
108    std::auto_ptr<std::ostringstream> buf;
109   
110    ///\e
111    bool init() throw() {
112      try {
113        buf.reset(new std::ostringstream);
114      }
115      catch(...) {
116        buf.reset();
117      }
118      return buf.get();
119    }
120
121  public:
122
123    ///\e
124    ErrorMessage() throw() { init(); }
125
126    ErrorMessage(const ErrorMessage& em) throw() : buf(em.buf) { }
127
128    ///\e
129    ErrorMessage(const char *message) throw() {
130      init();
131      *this << message;
132    }
133
134    ///\e
135    ErrorMessage(const std::string &message) throw() {
136      init();
137      *this << message;
138    }
139
140    ///\e
141    template <typename T>
142    ErrorMessage& operator<<(const T &t) throw() {
143      if( ! buf.get() ) return *this;
144
145      try {
146        *buf << t;
147      }
148      catch(...) {
149        buf.reset();
150      }
151      return *this;
152    }
153
154    ///\e
155    const char* message() throw() {
156      if( ! buf.get() ) return 0;
157
158      const char* mes = 0;
159      try {
160        mes = buf->str().c_str();
161      }
162      catch(...) {}
163      return mes;
164    }
165   
166  };
167
168  /**
169   * \brief Generic exception class.
170   *
171   * Base class for exceptions used in LEMON.
172   */
173  class Exception : public std::exception {
174  public:
175    ///\e
176    Exception() {}
177    ///\e
178    virtual ~Exception() throw() {}
179
180    ///\e
181    virtual const char* exceptionName() const {
182      return "lemon::Exception";
183    }
184   
185    ///\e
186    virtual const char* what() const throw() {
187      return exceptionName();
188    }
189  };
190
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   *
198   * A typical example for this is \ref UninitializedParameter.
199   */
200  class LogicError : public Exception {
201  public:
202    virtual const char* exceptionName() const {
203      return "lemon::LogicError";
204    }
205  };
206
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
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   */
228  class RuntimeError : public Exception {
229  public:
230    virtual const char* exceptionName() const {
231      return "lemon::RuntimeError";
232    }
233  };
234
235  ///\e
236  class RangeError : public RuntimeError {
237  public:
238    virtual const char* exceptionName() const {
239      return "lemon::RangeError";
240    }
241  };
242
243  ///\e
244  class IOError : public RuntimeError {
245  public:
246    virtual const char* exceptionName() const {
247      return "lemon::IOError";
248    }
249  };
250
251  ///\e
252  class DataFormatError : public IOError {
253  protected:
254    ExceptionMember<std::string> _message;
255    ExceptionMember<std::string> _file;
256    int _line;
257
258    mutable ExceptionMember<std::string> _message_holder;
259  public:
260
261    DataFormatError(const DataFormatError &dfe) :
262      IOError(dfe), _message(dfe._message), _file(dfe._file),
263      _line(dfe._line) {}
264
265    ///\e
266    explicit DataFormatError(const char *the_message)
267      : _message(the_message), _line(0) {}
268
269    ///\e
270    DataFormatError(const std::string &file_name, int line_num,
271                    const char *the_message)
272      : _message(the_message), _line(line_num) { file(file_name); }
273
274    ///\e
275    void line(int line) { _line = line; }
276    ///\e
277    void message(const std::string& message) { _message.set(message); }
278    ///\e
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;
289      }
290    }
291
292    /// \brief Returns the filename.
293    ///
294    /// Returns \e null if the filename was not specified.
295    const char* file() const {
296      if (_file.valid() && !_file.get().empty()) {
297        return _file.get().c_str();
298      } else {
299        return 0;
300      }
301    }
302
303    ///\e
304    virtual const char* what() const throw() {
305      try {
306        std::ostringstream ostr;
307        ostr << exceptionName() << ": ";
308        if (message()) ostr << message();
309        if( file() || line() != 0 ) {
310          ostr << " (";
311          if( file() ) ostr << "in file '" << file() << "'";
312          if( file() && line() != 0 ) ostr << " ";
313          if( line() != 0 ) ostr << "at line " << line();
314          ostr << ")";
315        }
316        _message_holder.set(ostr.str());
317      }
318      catch (...) {}
319      if( _message_holder.valid()) return _message_holder.get().c_str();
320      return exceptionName();
321    }
322
323    virtual const char* exceptionName() const {
324      return "lemon::DataFormatError";
325    }
326
327    virtual ~DataFormatError() throw() {}
328  };
329
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
380  class IOParameterError : public IOError {
381  protected:
382    ExceptionMember<std::string> _message;
383    ExceptionMember<std::string> _file;
384
385    mutable ExceptionMember<std::string> _message_holder;
386  public:
387
388    IOParameterError(const IOParameterError &ile) :
389      IOError(ile), _message(ile._message), _file(ile._file) {}
390
391    ///\e
392    explicit IOParameterError(const char *the_message)
393      : _message(the_message) {}
394
395    ///\e
396    IOParameterError(const char *file_name, const char *the_message)
397      : _message(the_message), _file(file_name) {}
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 {
438      return "lemon::IOParameterError";
439    }
440
441    virtual ~IOParameterError() throw() {}
442  };
443
444
445  ///\e
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;
453
454    mutable ExceptionMember<std::string> _message_holder;
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 )
482           ostr << " (assertion '" << assertion << "' failed)";
483        _message_holder.set(ostr.str());
484        return ostr.str().c_str();
485      }
486      catch(...) {}
487      if( _message_holder.valid() ) return _message_holder.get().c_str();
488      return exceptionName();
489    }
490
491    virtual const char* exceptionName() const {
492      return "lemon::AssertionFailedError";
493    }
494
495    virtual ~AssertionFailedError() throw() {}
496  };
497
498
499  /****************  Macros  ****************/
500
501
502  template <typename Exception>
503  inline void assert_fail(const char *file, int line, const char *func,
504                   Exception exception, const char *assertion = 0,
505                   bool do_abort=true)
506  {
507    using namespace std;
508    cerr << file << ":" << line << ": ";
509    if( func )
510      cerr << func << ": ";
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,
521                                        const char *func,
522                                        const char *message,
523                                        const char *assertion,
524                                        bool do_abort)
525  {
526    using namespace std;
527    cerr << file << ":" << line << ": ";
528    if( func )
529      cerr << func << ": ";
530    cerr << message;
531    if( assertion )
532      cerr << " (assertion '" << assertion << "' failed)";
533    cerr << endl;
534    if(do_abort)
535      abort();
536  }
537
538  template <typename Exception>
539  inline void assert_fail_failure(const char *file, int line, const char *func,
540                           Exception exception,
541                           const char *assertion = 0,
542                           bool = true)
543  {
544    throw AssertionFailedError(file, line, func, exception.what(), assertion);
545  }
546
547  template <>
548  inline void assert_fail_failure<const char *>(const char *file, int line,
549                                         const char *func,
550                                         const char *message,
551                                         const char *assertion,
552                                         bool)
553  {
554    throw AssertionFailedError(file, line, func, message, assertion);
555  }
556
557  template <typename Exception>
558  inline void assert_fail_exception(const char *file, int line, const char *func,
559                             Exception exception,
560                             const char *assertion = 0, bool = true)
561  {
562    throw exception;
563  }
564
565  template <>
566  inline void assert_fail_exception<const char *>(const char *file, int line,
567                                           const char *func,
568                                           const char *message,
569                                           const char *assertion,
570                                           bool)
571  {
572    throw AssertionFailedError(file, line, func, message, assertion);
573  }
574
575/// @}
576
577}
578#endif // LEMON_ERROR_H
579
580#undef LEMON_ASSERT
581#undef LEMON_FIXME
582
583#ifdef LEMON_ENABLE_ASSERTS
584#  define LEMON_ASSERT_ABORT
585#endif
586
587#ifndef LEMON_ASSERT_DO_ABORT
588#  define LEMON_ASSERT_DO_ABORT 1
589#endif
590
591#ifndef LEMON_ASSERT_HANDLER
592#  if defined LEMON_ASSERT_EXCEPTION
593#    define LEMON_ASSERT_HANDLER ::lemon::assert_fail_exception
594#  elif defined LEMON_ASSERT_FAILURE
595#    define LEMON_ASSERT_HANDLER ::lemon::assert_fail_failure
596#  elif defined LEMON_ASSERT_ABORT
597#    define LEMON_ASSERT_HANDLER ::lemon::assert_fail
598#  else
599#    define LEMON_DISABLE_ASSERTS
600#  endif
601#endif
602
603#ifdef DOXYGEN
604
605/// \brief Macro for assertions with customizable message
606///
607/// Macro for assertions with customizable message.
608///
609/// The assertions are disabled in the default behaviour. You can
610/// enable the assertions with the LEMON_ENABLE_ASSERTS macro what
611/// provides a log on the standard error about the assertion and aborts
612/// the program.  If the LEMON_ASSERT_DO_ABORT macro is setted to false
613/// then the just the log message can be seen on the standard error but
614/// the program is not stopped. With the LEMON_ASSERT_FAILURE and
615/// LEMON_ASSERT_EXCEPTION macros you can set other behaviour to the
616/// assertions. The LEMON_ASSERT_FAILURE will always throw an \c
617/// AssertionFailedError exception with the \c msg error message. The
618/// \c LEMON_ASSERT_EXCEPTION can throw a user defined exception.
619///
620/// The LEMON_ASSERT macro should be called with the \c exp parameter
621/// which should be an expression convertible to bool. If the given
622/// parameter is false the assertion is raised and one of the assertion
623/// behaviour will be activated. The \c msg should be either a const
624/// char* message or an exception. When the \c msg is an exception the
625/// \ref "Exception::what" what() function is called to retrieve and
626/// display the error message.
627///
628///
629/// \todo We should provide some way to reset to the default behaviour,
630/// shouldn't we?
631///
632/// \todo This whole 'assert' business should be placed in a separate
633/// include file. The boost assert is not guarded by header sentries
634/// which may help to change the behaviour of the assertions in
635/// the files.
636///
637/// \todo __PRETTY_FUNCTION__ should be replaced by something
638/// compiler-independent, like BOOST_CURRENT_FUNCTION
639
640#  define LEMON_ASSERT(exp, msg)                 \
641     (static_cast<void> (!!(exp) ? 0 : (         \
642       LEMON_ASSERT_HANDLER(__FILE__, __LINE__,  \
643                            __PRETTY_FUNCTION__, \
644                            msg, #exp, LEMON_ASSERT_DO_ABORT), 0)))
645
646#else
647#  if defined LEMON_DISABLE_ASSERTS
648
649#    define LEMON_ASSERT(exp, msg)  (static_cast<void> (0))
650
651#  else
652#    define LEMON_ASSERT(exp, msg)                 \
653       (static_cast<void> (!!(exp) ? 0 : (         \
654         LEMON_ASSERT_HANDLER(__FILE__, __LINE__,  \
655                              __PRETTY_FUNCTION__, \
656                              msg, #exp, LEMON_ASSERT_DO_ABORT), 0)))
657#  endif
658#endif
659
660/**
661 * \brief Macro for mark not yet implemented features.
662 *
663 * \todo Is this the right place for this? It should be used only in
664 * modules under development.
665 *
666 * \todo __PRETTY_FUNCTION__ should be replaced by something
667 * compiler-independent, like BOOST_CURRENT_FUNCTION
668 */
669
670# define LEMON_FIXME(msg) \
671    (LEMON_ASSERT_HANDLER(__FILE__, __LINE__, __PRETTY_FUNCTION__, \
672                          "FIXME: " msg))
Note: See TracBrowser for help on using the repository browser.