src/work/klao/error.h
author marci
Tue, 11 Jan 2005 17:16:29 +0000
changeset 1075 789bad021e2d
parent 1067 47939f501c81
child 1120 5d8d64bde9c5
permissions -rw-r--r--
:-}
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@883
    20
//! \ingroup misc
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
klao@1056
    34
  /// Exception-safe convenient "error message" class.
klao@1067
    35
klao@1067
    36
  /// Helper class which provides a convenient ostream-like (operator <<
klao@1067
    37
  /// based) interface to create a string message. Mostly useful in
klao@1067
    38
  /// exception classes (therefore the name).
klao@1056
    39
  class ErrorMessage {
klao@1056
    40
  protected:
klao@1067
    41
    ///\e 
klao@1056
    42
    boost::shared_ptr<std::ostringstream> buf;
klao@1056
    43
    
klao@1067
    44
    ///\e 
klao@1056
    45
    bool init() throw() {
klao@1056
    46
      try {
klao@1056
    47
	buf.reset(new std::ostringstream);
klao@1056
    48
      }
klao@1056
    49
      catch(...) {
klao@1056
    50
	buf.reset();
klao@1056
    51
      }
klao@1056
    52
      return buf;
klao@1056
    53
    }
klao@1056
    54
klao@1056
    55
  public:
klao@1056
    56
klao@1067
    57
    ///\e 
klao@1056
    58
    ErrorMessage() throw() { init(); }
klao@1056
    59
klao@1067
    60
    ///\e 
klao@1056
    61
    ErrorMessage(const char *message) throw() {
klao@1056
    62
      init();
klao@1056
    63
      *this << message;
klao@1056
    64
    }
klao@1056
    65
klao@1067
    66
    ///\e 
klao@1056
    67
    ErrorMessage(const std::string &message) throw() {
klao@1056
    68
      init();
klao@1056
    69
      *this << message;
klao@1056
    70
    }
klao@1056
    71
klao@1067
    72
    ///\e 
klao@1056
    73
    template <typename T>
klao@1056
    74
    ErrorMessage& operator<<(const T &t) throw() {
klao@1056
    75
      if( !buf ) return *this;
klao@1056
    76
klao@1056
    77
      try {
klao@1056
    78
	*buf << t;
klao@1056
    79
      }
klao@1056
    80
      catch(...) {
klao@1056
    81
	buf.reset();
klao@1056
    82
      }
klao@1056
    83
    }
klao@1056
    84
klao@1067
    85
    ///\e 
klao@1056
    86
    const char* message() throw() {
klao@1056
    87
      if( !buf ) return 0;
klao@1056
    88
klao@1056
    89
      const char* mes = 0;
klao@1056
    90
      try {
klao@1056
    91
	mes = buf->str().c_str();
klao@1056
    92
      }
klao@1056
    93
      catch(...) {}
klao@1056
    94
      return mes;
klao@1056
    95
    }
klao@1056
    96
    
klao@1056
    97
  };
klao@1056
    98
alpar@883
    99
  /**
alpar@883
   100
   * \brief Generic exception class.
alpar@883
   101
   *
klao@1056
   102
   * Base class for exceptions used in LEMON.
alpar@883
   103
   */
klao@1067
   104
  class Exception : public std::exception {
klao@1067
   105
  protected:
klao@1067
   106
    ///\e
klao@1067
   107
    const char *message;
klao@1067
   108
alpar@883
   109
  public:
klao@1067
   110
    ///\e 
klao@1067
   111
    Exception() throw() : message(0) {}
klao@1067
   112
    ///\e 
klao@1067
   113
    explicit Exception(const char *msg) throw()
klao@1067
   114
      : message(msg) {}
klao@1067
   115
    ///\e 
alpar@883
   116
    virtual ~Exception() throw() {}
alpar@883
   117
    
klao@1067
   118
    ///\e 
alpar@883
   119
    virtual const char* what() const throw() {
klao@1067
   120
      if( message ) return message;
klao@1056
   121
      return "lemon::Exception";
klao@1056
   122
    }
klao@1056
   123
  };
klao@1056
   124
alpar@1061
   125
  ///\e 
klao@1056
   126
  class LogicError : public Exception {
klao@1067
   127
  public:
klao@1067
   128
    ///\e 
klao@1067
   129
    explicit LogicError() {}
klao@1067
   130
    ///\e 
klao@1067
   131
    explicit LogicError(const char *s)
klao@1056
   132
      : Exception(s) {}
klao@1056
   133
  };
klao@1056
   134
alpar@1061
   135
  ///\e 
klao@1056
   136
  class RuntimeError : public Exception {
klao@1067
   137
  public:
klao@1067
   138
    ///\e
klao@1067
   139
    explicit RuntimeError() {}
klao@1067
   140
    ///\e
klao@1067
   141
    explicit RuntimeError(const char *s)
klao@1056
   142
      : Exception(s) {}
klao@1056
   143
  };
klao@1056
   144
klao@1067
   145
  ///\e
klao@1056
   146
  class RangeError : public RuntimeError {
klao@1067
   147
  public:
klao@1067
   148
    ///\e 
klao@1067
   149
    explicit RangeError(const char *s)
klao@1056
   150
      : RuntimeError(s) {}
klao@1056
   151
  };
klao@1056
   152
alpar@1061
   153
  ///\e 
klao@1056
   154
  class IOError : public RuntimeError {
klao@1067
   155
  public:
klao@1067
   156
    ///\e 
klao@1067
   157
    explicit IOError(const char *s)
klao@1056
   158
      : RuntimeError(s) {}
klao@1056
   159
  };
klao@1056
   160
alpar@1061
   161
  ///\e 
klao@1056
   162
  class DataFormatError : public IOError {
klao@1067
   163
  protected:
klao@1067
   164
    int line;
klao@1067
   165
    boost::shared_ptr<std::string> file;
klao@1067
   166
klao@1067
   167
  public:
klao@1067
   168
    ///\e 
klao@1067
   169
    explicit DataFormatError(const char *message)
klao@1067
   170
      : IOError(message), line(0) {}
klao@1067
   171
    ///\e 
klao@1056
   172
    DataFormatError(const std::string &file_name, int line_num,
klao@1067
   173
		    const char *message)
klao@1056
   174
      : IOError(message), line(line_num) { set_file(file_name); }
klao@1056
   175
klao@1067
   176
    ///\e 
klao@1056
   177
    void set_line(int line_num) { line=line_num; }
klao@1067
   178
    ///\e 
klao@1056
   179
    void set_file(const std::string &file_name) {
klao@1056
   180
      try {
klao@1056
   181
	file.reset(new std::string);
klao@1056
   182
	*file = file_name;
klao@1056
   183
      }
klao@1056
   184
      catch(...) {
klao@1056
   185
	file.reset();
klao@1056
   186
      }
alpar@883
   187
    }
alpar@883
   188
klao@1067
   189
    ///\e
klao@1067
   190
    int get_line() const { return line; }
klao@1067
   191
klao@1067
   192
    /// \brief Returns the filename.
klao@1067
   193
    ///
klao@1068
   194
    /// Returns \e "(unknown)" if the filename was not specified.
klao@1067
   195
    const char* get_file() const {
klao@1067
   196
      if( file )
klao@1067
   197
	return file->c_str();
klao@1067
   198
      else
klao@1067
   199
	return "(unknown)";
klao@1067
   200
    }
klao@1067
   201
klao@1067
   202
    ///\e 
klao@1067
   203
    virtual const char* what() const throw() {
klao@1056
   204
      const char *mes = 0;
klao@1056
   205
      try {
klao@1056
   206
	std::ostringstream ostr;
klao@1056
   207
	ostr << IOError::what();
klao@1056
   208
	if( file || line ) {
klao@1056
   209
	  ostr << " (";
klao@1067
   210
	  if( file ) ostr << "in file '" << *file << "'";
klao@1067
   211
	  if( file && line ) ostr << " ";
klao@1067
   212
	  if( line ) ostr << "at line " << line;
klao@1067
   213
	  ostr << ")";
klao@1056
   214
	}
klao@1056
   215
	mes = ostr.str().c_str();
klao@1056
   216
      }
klao@1056
   217
      catch(...) {}
klao@1056
   218
      if( mes ) return mes;
klao@1056
   219
      return "lemon::DataFormatError";
klao@1056
   220
    }
klao@1067
   221
klao@1067
   222
    virtual ~DataFormatError() throw() {}
alpar@883
   223
  };
alpar@883
   224
klao@1056
   225
klao@1068
   226
  ///\e
klao@1067
   227
  class AssertionFailedError : public LogicError {
klao@1067
   228
  protected:
klao@1067
   229
    const char *assertion;
klao@1067
   230
    const char *file;
klao@1067
   231
    int line;
klao@1067
   232
    const char *function;
klao@1067
   233
    const char *message;
klao@1067
   234
  public:
klao@1067
   235
    ///\e
klao@1067
   236
    AssertionFailedError(const char *_file, int _line, const char *func,
klao@1067
   237
			 const char *msg, const char *_assertion = 0) :
klao@1067
   238
      assertion(_assertion), file(_file), line(_line), function(func),
klao@1067
   239
      message(msg) {}
klao@1067
   240
klao@1067
   241
    ///\e
klao@1067
   242
    const char* get_assertion() const { return assertion; }
klao@1067
   243
    ///\e
klao@1067
   244
    const char* get_message() const { return message; }
klao@1067
   245
    ///\e
klao@1067
   246
    const char* get_file() const { return file; }
klao@1067
   247
    ///\e
klao@1067
   248
    const char* get_function() const { return function; }
klao@1067
   249
    ///\e
klao@1067
   250
    int get_line() const { return line; }
klao@1067
   251
klao@1067
   252
klao@1067
   253
    virtual const char* what() const throw() {
klao@1067
   254
      const char *mes = 0;
klao@1067
   255
      try {
klao@1067
   256
	std::ostringstream ostr;
klao@1067
   257
	ostr << file << ":" << line << ": ";
klao@1067
   258
	if( function )
klao@1067
   259
	  ostr << function << ": ";
klao@1067
   260
	ostr << message;
klao@1067
   261
	if( assertion )
klao@1067
   262
	  ostr << " (assertion '" << assertion << "' failed)";
klao@1067
   263
	mes = ostr.str().c_str();
klao@1067
   264
      }
klao@1067
   265
      catch(...) {}
klao@1067
   266
      if( mes ) return mes;
klao@1067
   267
      return "lemon::AssertionFailedError";
klao@1067
   268
    }
klao@1067
   269
klao@1067
   270
    virtual ~AssertionFailedError() throw() {}
klao@1067
   271
  };
klao@1067
   272
klao@1056
   273
klao@1056
   274
  /****************  Macros  ****************/
klao@1056
   275
klao@1056
   276
klao@1067
   277
  inline
klao@1067
   278
  void assert_fail(const char *file, int line, const char *func,
klao@1067
   279
		   const char *message, const char *assertion = 0,
klao@1067
   280
		   bool do_abort=true)
klao@1067
   281
  {
klao@1067
   282
    using namespace std;
klao@1067
   283
    cerr << file << ":" << line << ": ";
klao@1067
   284
    if( func )
klao@1067
   285
      cerr << func << ": ";
klao@1067
   286
    cerr << message;
klao@1067
   287
    if( assertion )
klao@1067
   288
      cerr << " (assertion '" << assertion << "' failed)";
klao@1067
   289
    cerr << endl;
klao@1067
   290
    if(do_abort)
klao@1067
   291
      abort();
klao@1067
   292
  }
klao@1056
   293
klao@1067
   294
  inline
klao@1067
   295
  void assert_fail_throw(const char *file, int line, const char *func,
klao@1067
   296
		   const char *message, const char *assertion = 0,
klao@1067
   297
		   bool = true)
klao@1067
   298
  {
klao@1067
   299
    throw AssertionFailedError(file, line, func, message, assertion);
klao@1067
   300
  }
klao@1056
   301
alpar@883
   302
alpar@883
   303
}
alpar@921
   304
#endif // LEMON_ERROR_H
klao@1067
   305
klao@1067
   306
#undef LEMON_ASSERT
klao@1067
   307
#undef LEMON_FIXME
klao@1067
   308
klao@1067
   309
#ifndef LEMON_ASSERT_ABORT
klao@1067
   310
#  define LEMON_ASSERT_ABORT 1
klao@1067
   311
#endif
klao@1067
   312
klao@1067
   313
#ifndef LEMON_ASSERT_HANDLER
klao@1067
   314
#  define LEMON_ASSERT_HANDLER ::lemon::assert_fail
klao@1067
   315
#endif
klao@1067
   316
klao@1067
   317
#if defined(NDEBUG) || defined(LEMON_DISABLE_ASSERTS)
klao@1067
   318
klao@1067
   319
#  define LEMON_ASSERT(exp, msg)  (static_cast<void> (0))
klao@1067
   320
klao@1067
   321
#else
klao@1067
   322
klao@1067
   323
/**
klao@1067
   324
 * \brief Macro for assertions with customizable message
klao@1067
   325
 *
klao@1067
   326
 * \todo __PRETTY_FUNCTION__ should be replaced by something
klao@1067
   327
 * compiler-independant, like BOOST_CURRENT_FUNCTION
klao@1067
   328
 */
klao@1067
   329
klao@1067
   330
#  define LEMON_ASSERT(exp, msg)                 \
klao@1067
   331
     (static_cast<void> (!!(exp) ? 0 : (         \
klao@1067
   332
       LEMON_ASSERT_HANDLER(__FILE__, __LINE__,  \
klao@1067
   333
                            __PRETTY_FUNCTION__, \
klao@1067
   334
			    (msg), #exp, LEMON_ASSERT_ABORT), 0)))
klao@1067
   335
klao@1067
   336
# endif // NDEBUG
klao@1067
   337
klao@1067
   338
/**
klao@1067
   339
 * \brief Macro for mark not yet implemented features.
klao@1067
   340
 *
klao@1067
   341
 * \todo Is this the right place for this? It should be used only in
klao@1067
   342
 * modules under development.
klao@1067
   343
 *
klao@1067
   344
 * \todo __PRETTY_FUNCTION__ should be replaced by something
klao@1067
   345
 * compiler-independant, like BOOST_CURRENT_FUNCTION
klao@1067
   346
 */
klao@1067
   347
klao@1067
   348
# define LEMON_FIXME(msg) \
klao@1067
   349
    (LEMON_ASSERT_HANDLER(__FILE__, __LINE__, __PRETTY_FUNCTION__, \
klao@1067
   350
			  "FIXME: " msg))