COIN-OR::LEMON - Graph Library

source: lemon/lemon/error.h @ 77:2de55e4f57a7

Last change on this file since 77:2de55e4f57a7 was 66:5f7a8570687d, checked in by Peter Kovacs <kpeter@…>, 17 years ago

Port error.h from svn -r3438 + minor changes (error_test does not pass!)

In svn -r3438 error_test is not used as a test program and it does not pass.

File size: 17.7 KB
Line 
1/* -*- C++ -*-
2 *
3 * This file is a part of LEMON, a generic C++ optimization library
4 *
5 * Copyright (C) 2003-2008
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) 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 {
102  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;
242    int _line;
243
244    mutable ExceptionMember<std::string> _message_holder;
245  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
267    ///\e
268    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
290    virtual const char* what() const throw() {
291      try {
292        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)";
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/// @}
575
576}
577#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 TracBrowser for help on using the repository browser.