src/lemon/error.h
author alpar
Fri, 18 Feb 2005 14:46:04 +0000
changeset 1155 fe0fcdb5687b
parent 1125 377e240b050f
child 1157 3996d2098090
permissions -rw-r--r--
- Better addSource()
- More docs
alpar@906
     1
/* -*- C++ -*-
alpar@921
     2
 * src/lemon/error.h - Part of LEMON, a generic C++ optimization library
alpar@906
     3
 *
alpar@906
     4
 * Copyright (C) 2004 Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
alpar@906
     5
 * (Egervary Combinatorial Optimization Research Group, EGRES).
alpar@906
     6
 *
alpar@906
     7
 * Permission to use, modify and distribute this software is granted
alpar@906
     8
 * provided that this copyright notice appears in all copies. For
alpar@906
     9
 * precise terms see the accompanying LICENSE file.
alpar@906
    10
 *
alpar@906
    11
 * This software is provided "AS IS" with no warranty of any kind,
alpar@906
    12
 * express or implied, and with no claim as to its suitability for any
alpar@906
    13
 * purpose.
alpar@906
    14
 *
alpar@906
    15
 */
alpar@883
    16
alpar@921
    17
#ifndef LEMON_ERROR_H
alpar@921
    18
#define LEMON_ERROR_H
alpar@883
    19
alpar@1151
    20
//! \ingroup exceptions
alpar@883
    21
//! \file
klao@1067
    22
//! \brief Basic exception classes and error handling.
alpar@883
    23
alpar@883
    24
#include <exception>
alpar@883
    25
#include <string>
alpar@883
    26
#include <sstream>
klao@1067
    27
#include <iostream>
klao@1067
    28
#include <cstdlib>
alpar@883
    29
klao@1056
    30
#include <boost/shared_ptr.hpp>
alpar@883
    31
alpar@921
    32
namespace lemon {
alpar@883
    33
alpar@1151
    34
/// \addtogroup exceptions
alpar@1151
    35
/// @{
alpar@1151
    36
klao@1056
    37
  /// Exception-safe convenient "error message" class.
klao@1067
    38
klao@1067
    39
  /// Helper class which provides a convenient ostream-like (operator <<
klao@1067
    40
  /// based) interface to create a string message. Mostly useful in
klao@1067
    41
  /// exception classes (therefore the name).
klao@1056
    42
  class ErrorMessage {
klao@1056
    43
  protected:
klao@1067
    44
    ///\e 
klao@1056
    45
    boost::shared_ptr<std::ostringstream> buf;
klao@1056
    46
    
klao@1067
    47
    ///\e 
klao@1056
    48
    bool init() throw() {
klao@1056
    49
      try {
klao@1056
    50
	buf.reset(new std::ostringstream);
klao@1056
    51
      }
klao@1056
    52
      catch(...) {
klao@1056
    53
	buf.reset();
klao@1056
    54
      }
klao@1056
    55
      return buf;
klao@1056
    56
    }
klao@1056
    57
klao@1056
    58
  public:
klao@1056
    59
klao@1067
    60
    ///\e 
klao@1056
    61
    ErrorMessage() throw() { init(); }
klao@1056
    62
klao@1067
    63
    ///\e 
klao@1056
    64
    ErrorMessage(const char *message) throw() {
klao@1056
    65
      init();
klao@1056
    66
      *this << message;
klao@1056
    67
    }
klao@1056
    68
klao@1067
    69
    ///\e 
klao@1056
    70
    ErrorMessage(const std::string &message) throw() {
klao@1056
    71
      init();
klao@1056
    72
      *this << message;
klao@1056
    73
    }
klao@1056
    74
klao@1067
    75
    ///\e 
klao@1056
    76
    template <typename T>
klao@1056
    77
    ErrorMessage& operator<<(const T &t) throw() {
klao@1056
    78
      if( !buf ) return *this;
klao@1056
    79
klao@1056
    80
      try {
klao@1056
    81
	*buf << t;
klao@1056
    82
      }
klao@1056
    83
      catch(...) {
klao@1056
    84
	buf.reset();
klao@1056
    85
      }
klao@1056
    86
    }
klao@1056
    87
klao@1067
    88
    ///\e 
klao@1056
    89
    const char* message() throw() {
klao@1056
    90
      if( !buf ) return 0;
klao@1056
    91
klao@1056
    92
      const char* mes = 0;
klao@1056
    93
      try {
klao@1056
    94
	mes = buf->str().c_str();
klao@1056
    95
      }
klao@1056
    96
      catch(...) {}
klao@1056
    97
      return mes;
klao@1056
    98
    }
klao@1056
    99
    
klao@1056
   100
  };
klao@1056
   101
alpar@883
   102
  /**
alpar@883
   103
   * \brief Generic exception class.
alpar@883
   104
   *
klao@1056
   105
   * Base class for exceptions used in LEMON.
alpar@883
   106
   */
klao@1067
   107
  class Exception : public std::exception {
alpar@883
   108
  public:
klao@1067
   109
    ///\e 
klao@1120
   110
    Exception() {}
klao@1067
   111
    ///\e 
alpar@883
   112
    virtual ~Exception() throw() {}
klao@1120
   113
klao@1120
   114
    ///\e
klao@1120
   115
    virtual const char* exceptionName() const {
klao@1120
   116
      return "lemon::Exception";
klao@1120
   117
    }
alpar@883
   118
    
klao@1067
   119
    ///\e 
alpar@883
   120
    virtual const char* what() const throw() {
klao@1120
   121
      return exceptionName();
klao@1056
   122
    }
klao@1056
   123
  };
klao@1056
   124
klao@1120
   125
  /**
klao@1120
   126
   * \brief One of the two main subclasses of \ref Exception.
klao@1120
   127
   *
klao@1120
   128
   * Logic errors represent problems in the internal logic of a program;
klao@1120
   129
   * in theory, these are preventable, and even detectable before the
klao@1120
   130
   * program runs (e.g., violations of class invariants).
klao@1120
   131
   *
alpar@1125
   132
   * A typical example for this is \ref UninitializedParameter.
klao@1120
   133
   */
klao@1056
   134
  class LogicError : public Exception {
klao@1067
   135
  public:
klao@1120
   136
    virtual const char* exceptionName() const {
klao@1120
   137
      return "lemon::LogicError";
klao@1120
   138
    }
klao@1056
   139
  };
klao@1056
   140
alpar@1125
   141
  /**
alpar@1125
   142
   * \brief \ref Exception for uninitialized parameters.
alpar@1125
   143
   *
alpar@1125
   144
   * This error represents problems in the initialization
alpar@1125
   145
   * of the parameters of the algorithms.
alpar@1125
   146
   */
alpar@1125
   147
  class UninitializedParameter : public LogicError {
alpar@1125
   148
  public:
alpar@1125
   149
    virtual const char* exceptionName() const {
alpar@1125
   150
      return "lemon::UninitializedParameter";
alpar@1125
   151
    }
alpar@1125
   152
  };
alpar@1125
   153
klao@1120
   154
  
klao@1120
   155
  /**
klao@1120
   156
   * \brief One of the two main subclasses of \ref Exception.
klao@1120
   157
   *
klao@1120
   158
   * Runtime errors represent problems outside the scope of a program;
klao@1120
   159
   * they cannot be easily predicted and can generally only be caught as
klao@1120
   160
   * the program executes.
klao@1120
   161
   */
klao@1056
   162
  class RuntimeError : public Exception {
klao@1067
   163
  public:
klao@1120
   164
    virtual const char* exceptionName() const {
klao@1120
   165
      return "lemon::RuntimeError";
klao@1120
   166
    }
klao@1056
   167
  };
klao@1056
   168
klao@1067
   169
  ///\e
klao@1056
   170
  class RangeError : public RuntimeError {
klao@1067
   171
  public:
klao@1120
   172
    virtual const char* exceptionName() const {
klao@1120
   173
      return "lemon::RangeError";
klao@1120
   174
    }
klao@1056
   175
  };
klao@1056
   176
alpar@1061
   177
  ///\e 
klao@1056
   178
  class IOError : public RuntimeError {
klao@1067
   179
  public:
klao@1120
   180
    virtual const char* exceptionName() const {
klao@1120
   181
      return "lemon::IOError";
klao@1120
   182
    }
klao@1056
   183
  };
klao@1056
   184
alpar@1061
   185
  ///\e 
klao@1056
   186
  class DataFormatError : public IOError {
klao@1067
   187
  protected:
klao@1120
   188
    const char *_message;
klao@1120
   189
    int _line;
klao@1120
   190
    boost::shared_ptr<std::string> _file;
klao@1067
   191
klao@1067
   192
  public:
klao@1067
   193
    ///\e 
klao@1120
   194
    explicit DataFormatError(const char *the_message)
klao@1120
   195
      : _message(the_message), _line(0) {}
klao@1067
   196
    ///\e 
klao@1056
   197
    DataFormatError(const std::string &file_name, int line_num,
klao@1120
   198
		    const char *the_message)
klao@1120
   199
      : _message(the_message), _line(line_num) { file(file_name); }
klao@1056
   200
klao@1067
   201
    ///\e 
klao@1120
   202
    void line(int line_num) { _line=line_num; }
klao@1067
   203
    ///\e 
klao@1120
   204
    void message(char *the_message) { _message=the_message; }
klao@1120
   205
    ///\e 
klao@1120
   206
    void file(const std::string &file_name) {
klao@1056
   207
      try {
klao@1120
   208
	_file.reset(new std::string);
klao@1120
   209
	*_file = file_name;
klao@1056
   210
      }
klao@1056
   211
      catch(...) {
klao@1120
   212
	_file.reset();
klao@1056
   213
      }
alpar@883
   214
    }
alpar@883
   215
klao@1067
   216
    ///\e
klao@1120
   217
    int line() const { return _line; }
klao@1120
   218
    ///\e
klao@1120
   219
    const char* message() const { return _message; }
klao@1067
   220
klao@1067
   221
    /// \brief Returns the filename.
klao@1067
   222
    ///
klao@1068
   223
    /// Returns \e "(unknown)" if the filename was not specified.
klao@1120
   224
    const char* file() const {
klao@1120
   225
      if( _file )
klao@1120
   226
	return _file->c_str();
klao@1067
   227
      else
klao@1067
   228
	return "(unknown)";
klao@1067
   229
    }
klao@1067
   230
klao@1067
   231
    ///\e 
klao@1067
   232
    virtual const char* what() const throw() {
klao@1056
   233
      const char *mes = 0;
klao@1056
   234
      try {
klao@1056
   235
	std::ostringstream ostr;
klao@1120
   236
	ostr << _message;
klao@1120
   237
	if( _file || _line ) {
klao@1056
   238
	  ostr << " (";
klao@1120
   239
	  if( _file ) ostr << "in file '" << *_file << "'";
klao@1120
   240
	  if( _file && _line ) ostr << " ";
klao@1120
   241
	  if( _line ) ostr << "at line " << _line;
klao@1067
   242
	  ostr << ")";
klao@1056
   243
	}
klao@1056
   244
	mes = ostr.str().c_str();
klao@1056
   245
      }
klao@1056
   246
      catch(...) {}
klao@1056
   247
      if( mes ) return mes;
klao@1120
   248
      return exceptionName();
klao@1120
   249
    }
klao@1120
   250
klao@1120
   251
    virtual const char* exceptionName() const {
klao@1056
   252
      return "lemon::DataFormatError";
klao@1056
   253
    }
klao@1067
   254
klao@1067
   255
    virtual ~DataFormatError() throw() {}
alpar@883
   256
  };
alpar@883
   257
klao@1056
   258
klao@1068
   259
  ///\e
klao@1067
   260
  class AssertionFailedError : public LogicError {
klao@1067
   261
  protected:
klao@1067
   262
    const char *assertion;
klao@1067
   263
    const char *file;
klao@1067
   264
    int line;
klao@1067
   265
    const char *function;
klao@1067
   266
    const char *message;
klao@1067
   267
  public:
klao@1067
   268
    ///\e
klao@1067
   269
    AssertionFailedError(const char *_file, int _line, const char *func,
klao@1067
   270
			 const char *msg, const char *_assertion = 0) :
klao@1067
   271
      assertion(_assertion), file(_file), line(_line), function(func),
klao@1067
   272
      message(msg) {}
klao@1067
   273
klao@1067
   274
    ///\e
klao@1067
   275
    const char* get_assertion() const { return assertion; }
klao@1067
   276
    ///\e
klao@1067
   277
    const char* get_message() const { return message; }
klao@1067
   278
    ///\e
klao@1067
   279
    const char* get_file() const { return file; }
klao@1067
   280
    ///\e
klao@1067
   281
    const char* get_function() const { return function; }
klao@1067
   282
    ///\e
klao@1067
   283
    int get_line() const { return line; }
klao@1067
   284
klao@1067
   285
klao@1067
   286
    virtual const char* what() const throw() {
klao@1067
   287
      const char *mes = 0;
klao@1067
   288
      try {
klao@1067
   289
	std::ostringstream ostr;
klao@1067
   290
	ostr << file << ":" << line << ": ";
klao@1067
   291
	if( function )
klao@1067
   292
	  ostr << function << ": ";
klao@1067
   293
	ostr << message;
klao@1067
   294
	if( assertion )
klao@1067
   295
	  ostr << " (assertion '" << assertion << "' failed)";
klao@1067
   296
	mes = ostr.str().c_str();
klao@1067
   297
      }
klao@1067
   298
      catch(...) {}
klao@1067
   299
      if( mes ) return mes;
klao@1120
   300
      return exceptionName();
klao@1120
   301
    }
klao@1120
   302
klao@1120
   303
    virtual const char* exceptionName() const {
klao@1067
   304
      return "lemon::AssertionFailedError";
klao@1067
   305
    }
klao@1067
   306
klao@1067
   307
    virtual ~AssertionFailedError() throw() {}
klao@1067
   308
  };
klao@1067
   309
klao@1056
   310
klao@1056
   311
  /****************  Macros  ****************/
klao@1056
   312
klao@1056
   313
klao@1067
   314
  inline
klao@1067
   315
  void assert_fail(const char *file, int line, const char *func,
klao@1067
   316
		   const char *message, const char *assertion = 0,
klao@1067
   317
		   bool do_abort=true)
klao@1067
   318
  {
klao@1067
   319
    using namespace std;
klao@1067
   320
    cerr << file << ":" << line << ": ";
klao@1067
   321
    if( func )
klao@1067
   322
      cerr << func << ": ";
klao@1067
   323
    cerr << message;
klao@1067
   324
    if( assertion )
klao@1067
   325
      cerr << " (assertion '" << assertion << "' failed)";
klao@1067
   326
    cerr << endl;
klao@1067
   327
    if(do_abort)
klao@1067
   328
      abort();
klao@1067
   329
  }
klao@1056
   330
klao@1067
   331
  inline
klao@1067
   332
  void assert_fail_throw(const char *file, int line, const char *func,
klao@1067
   333
		   const char *message, const char *assertion = 0,
klao@1067
   334
		   bool = true)
klao@1067
   335
  {
klao@1067
   336
    throw AssertionFailedError(file, line, func, message, assertion);
klao@1067
   337
  }
klao@1056
   338
alpar@1151
   339
/// @}
alpar@883
   340
alpar@883
   341
}
alpar@921
   342
#endif // LEMON_ERROR_H
klao@1067
   343
klao@1067
   344
#undef LEMON_ASSERT
klao@1067
   345
#undef LEMON_FIXME
klao@1067
   346
klao@1067
   347
#ifndef LEMON_ASSERT_ABORT
klao@1067
   348
#  define LEMON_ASSERT_ABORT 1
klao@1067
   349
#endif
klao@1067
   350
klao@1067
   351
#ifndef LEMON_ASSERT_HANDLER
klao@1120
   352
#  ifdef LEMON_ASSERT_EXCEPTION
klao@1120
   353
#    define LEMON_ASSERT_HANDLER ::lemon::assert_fail_throw
klao@1120
   354
#  else
klao@1120
   355
#    define LEMON_ASSERT_HANDLER ::lemon::assert_fail
klao@1120
   356
#  endif
klao@1067
   357
#endif
klao@1067
   358
klao@1067
   359
#if defined(NDEBUG) || defined(LEMON_DISABLE_ASSERTS)
klao@1067
   360
klao@1067
   361
#  define LEMON_ASSERT(exp, msg)  (static_cast<void> (0))
klao@1067
   362
klao@1067
   363
#else
klao@1067
   364
klao@1067
   365
/**
klao@1067
   366
 * \brief Macro for assertions with customizable message
klao@1067
   367
 *
klao@1120
   368
 * Macro for assertions with customizable message.
klao@1120
   369
 *
klao@1120
   370
 * The behaviour can be customized with LEMON_ASSERT_HANDLER,
klao@1120
   371
 * LEMON_ASSERT_EXCEPTION and LEMON_ASSERT_ABORT defines. Asserts can be
klao@1120
   372
 * disabled by defining either NDEBUG or LEMON_DISABLE_ASSERTS macros.
klao@1120
   373
 *
klao@1120
   374
 * \todo We should provide some way to reset to the default behaviour,
klao@1120
   375
 * shouldn't we?
klao@1120
   376
 *
klao@1120
   377
 * \todo This whole 'assert' business should be placed in a separate
klao@1120
   378
 * include file.
klao@1120
   379
 *
klao@1067
   380
 * \todo __PRETTY_FUNCTION__ should be replaced by something
klao@1067
   381
 * compiler-independant, like BOOST_CURRENT_FUNCTION
klao@1067
   382
 */
klao@1067
   383
klao@1067
   384
#  define LEMON_ASSERT(exp, msg)                 \
klao@1067
   385
     (static_cast<void> (!!(exp) ? 0 : (         \
klao@1067
   386
       LEMON_ASSERT_HANDLER(__FILE__, __LINE__,  \
klao@1067
   387
                            __PRETTY_FUNCTION__, \
klao@1067
   388
			    (msg), #exp, LEMON_ASSERT_ABORT), 0)))
klao@1067
   389
klao@1120
   390
#endif // NDEBUG || LEMON_DISABLE_ASSERTS
klao@1067
   391
klao@1067
   392
/**
klao@1067
   393
 * \brief Macro for mark not yet implemented features.
klao@1067
   394
 *
klao@1067
   395
 * \todo Is this the right place for this? It should be used only in
klao@1067
   396
 * modules under development.
klao@1067
   397
 *
klao@1067
   398
 * \todo __PRETTY_FUNCTION__ should be replaced by something
klao@1067
   399
 * compiler-independant, like BOOST_CURRENT_FUNCTION
klao@1067
   400
 */
klao@1067
   401
klao@1067
   402
# define LEMON_FIXME(msg) \
klao@1067
   403
    (LEMON_ASSERT_HANDLER(__FILE__, __LINE__, __PRETTY_FUNCTION__, \
klao@1067
   404
			  "FIXME: " msg))