COIN-OR::LEMON - Graph Library

source: lemon-0.x/lemon/error.h @ 1494:ae55ba000ebb

Last change on this file since 1494:ae55ba000ebb was 1435:8e85e6bbefdf, checked in by Akos Ladanyi, 19 years ago

trunk/src/* move to trunk/

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