COIN-OR::LEMON - Graph Library

source: lemon-0.x/lemon/error.h @ 2020:332245399dc6

Last change on this file since 2020:332245399dc6 was 1956:a055123339d5, checked in by Alpar Juttner, 14 years ago

Unified copyright notices

File size: 15.3 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, 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 << ": ";
529    cerr << message;
530    if( assertion )
531      cerr << " (assertion '" << assertion << "' failed)";
532    cerr << endl;
533    if(do_abort)
534      abort();
535  }
536
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)
570  {
571    throw AssertionFailedError(file, line, func, message, assertion);
572  }
573
574/// @}
575
576}
577#endif // LEMON_ERROR_H
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
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
591#  else
592#    define LEMON_ASSERT_HANDLER ::lemon::assert_fail
593#  endif
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 *
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
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.
618 *
619 * \todo __PRETTY_FUNCTION__ should be replaced by something
620 * compiler-independent, like BOOST_CURRENT_FUNCTION
621 */
622
623#  define LEMON_ASSERT(exp, msg)                 \
624     (static_cast<void> (!!(exp) ? 0 : (         \
625       LEMON_ASSERT_HANDLER(__FILE__, __LINE__,  \
626                            __PRETTY_FUNCTION__, \
627                            msg, #exp, LEMON_ASSERT_ABORT), 0)))
628
629#endif // NDEBUG || LEMON_DISABLE_ASSERTS
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
638 * compiler-independent, like BOOST_CURRENT_FUNCTION
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.