lemon/error.h
author Peter Kovacs <kpeter@inf.elte.hu>
Mon, 29 Sep 2008 12:34:08 +0200
changeset 289 d91884dcd572
parent 212 1ae84dea7d09
child 290 f6899946c1ac
permissions -rw-r--r--
Use DEBUG instead of ASSERT in graph extenders (ticket #17)
     1 /* -*- mode: C++; indent-tabs-mode: nil; -*-
     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 
    33 namespace 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 builder 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     mutable 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 *msg) throw() {
   127       init();
   128       *this << msg;
   129     }
   130 
   131     ///\e
   132     ErrorMessage(const std::string &msg) throw() {
   133       init();
   134       *this << msg;
   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   /// Generic exception class.
   166 
   167   /// Base class for exceptions used in LEMON.
   168   ///
   169   class Exception : public std::exception {
   170   public:
   171     ///\e
   172     Exception() {}
   173     ///\e
   174     virtual ~Exception() throw() {}
   175     ///\e
   176     virtual const char* what() const throw() {
   177       return "lemon::Exception";
   178     }
   179   };
   180 
   181   /// One of the two main subclasses of \ref Exception.
   182 
   183   /// Logic errors represent problems in the internal logic of a program;
   184   /// in theory, these are preventable, and even detectable before the
   185   /// program runs (e.g. violations of class invariants).
   186   ///
   187   /// A typical example for this is \ref UninitializedParameter.
   188   class LogicError : public Exception {
   189   public:
   190     virtual const char* what() const throw() {
   191       return "lemon::LogicError";
   192     }
   193   };
   194 
   195   /// \ref Exception for uninitialized parameters.
   196 
   197   /// This error represents problems in the initialization
   198   /// of the parameters of the algorithms.
   199   class UninitializedParameter : public LogicError {
   200   public:
   201     virtual const char* what() const throw() {
   202       return "lemon::UninitializedParameter";
   203     }
   204   };
   205 
   206 
   207   /// One of the two main subclasses of \ref Exception.
   208 
   209   /// Runtime errors represent problems outside the scope of a program;
   210   /// they cannot be easily predicted and can generally only be caught
   211   /// as the program executes.
   212   class RuntimeError : public Exception {
   213   public:
   214     virtual const char* what() const throw() {
   215       return "lemon::RuntimeError";
   216     }
   217   };
   218 
   219   ///\e
   220   class RangeError : public RuntimeError {
   221   public:
   222     virtual const char* what() const throw() {
   223       return "lemon::RangeError";
   224     }
   225   };
   226 
   227   ///\e
   228   class IoError : public RuntimeError {
   229   public:
   230     virtual const char* what() const throw() {
   231       return "lemon::IoError";
   232     }
   233   };
   234 
   235   ///\e
   236   class DataFormatError : public IoError {
   237   protected:
   238     ExceptionMember<std::string> _message;
   239     ExceptionMember<std::string> _file;
   240     int _line;
   241 
   242     mutable ExceptionMember<std::string> _message_holder;
   243   public:
   244 
   245     DataFormatError(const DataFormatError &dfe) :
   246       IoError(dfe), _message(dfe._message), _file(dfe._file),
   247       _line(dfe._line) {}
   248 
   249     ///\e
   250     explicit DataFormatError(const char *the_message)
   251       : _message(the_message), _line(0) {}
   252 
   253     ///\e
   254     DataFormatError(const std::string &file_name, int line_num,
   255                     const char *the_message)
   256       : _message(the_message), _line(line_num) { file(file_name); }
   257 
   258     ///\e
   259     void line(int ln) { _line = ln; }
   260     ///\e
   261     void message(const std::string& msg) { _message.set(msg); }
   262     ///\e
   263     void file(const std::string &fl) { _file.set(fl); }
   264 
   265     ///\e
   266     int line() const { return _line; }
   267     ///\e
   268     const char* message() const {
   269       if (_message.valid() && !_message.get().empty()) {
   270         return _message.get().c_str();
   271       } else {
   272         return 0;
   273       }
   274     }
   275 
   276     /// \brief Returns the filename.
   277     ///
   278     /// Returns \e null if the filename was not specified.
   279     const char* file() const {
   280       if (_file.valid() && !_file.get().empty()) {
   281         return _file.get().c_str();
   282       } else {
   283         return 0;
   284       }
   285     }
   286 
   287     ///\e
   288     virtual const char* what() const throw() {
   289       try {
   290         std::ostringstream ostr;
   291         ostr << "lemon:DataFormatError" << ": ";
   292         if (message()) ostr << message();
   293         if( file() || line() != 0 ) {
   294           ostr << " (";
   295           if( file() ) ostr << "in file '" << file() << "'";
   296           if( file() && line() != 0 ) ostr << " ";
   297           if( line() != 0 ) ostr << "at line " << line();
   298           ostr << ")";
   299         }
   300         _message_holder.set(ostr.str());
   301       }
   302       catch (...) {}
   303       if( _message_holder.valid()) return _message_holder.get().c_str();
   304       return "lemon:DataFormatError";
   305     }
   306 
   307     virtual ~DataFormatError() throw() {}
   308   };
   309 
   310   ///\e
   311   class FileOpenError : public IoError {
   312   protected:
   313     ExceptionMember<std::string> _file;
   314 
   315     mutable ExceptionMember<std::string> _message_holder;
   316   public:
   317 
   318     FileOpenError(const FileOpenError &foe) :
   319       IoError(foe), _file(foe._file) {}
   320 
   321     ///\e
   322     explicit FileOpenError(const std::string& fl)
   323       : _file(fl) {}
   324 
   325 
   326     ///\e
   327     void file(const std::string &fl) { _file.set(fl); }
   328 
   329     /// \brief Returns the filename.
   330     ///
   331     /// Returns \e null if the filename was not specified.
   332     const char* file() const {
   333       if (_file.valid() && !_file.get().empty()) {
   334         return _file.get().c_str();
   335       } else {
   336         return 0;
   337       }
   338     }
   339 
   340     ///\e
   341     virtual const char* what() const throw() {
   342       try {
   343         std::ostringstream ostr;
   344         ostr << "lemon::FileOpenError" << ": ";
   345         ostr << "Cannot open file - " << file();
   346         _message_holder.set(ostr.str());
   347       }
   348       catch (...) {}
   349       if( _message_holder.valid()) return _message_holder.get().c_str();
   350       return "lemon::FileOpenError";
   351     }
   352     virtual ~FileOpenError() throw() {}
   353   };
   354 
   355   class IoParameterError : public IoError {
   356   protected:
   357     ExceptionMember<std::string> _message;
   358     ExceptionMember<std::string> _file;
   359 
   360     mutable ExceptionMember<std::string> _message_holder;
   361   public:
   362 
   363     IoParameterError(const IoParameterError &ile) :
   364       IoError(ile), _message(ile._message), _file(ile._file) {}
   365 
   366     ///\e
   367     explicit IoParameterError(const char *the_message)
   368       : _message(the_message) {}
   369 
   370     ///\e
   371     IoParameterError(const char *file_name, const char *the_message)
   372       : _message(the_message), _file(file_name) {}
   373 
   374      ///\e
   375     void message(const std::string& msg) { _message.set(msg); }
   376     ///\e
   377     void file(const std::string &fl) { _file.set(fl); }
   378 
   379      ///\e
   380     const char* message() const {
   381       if (_message.valid()) {
   382         return _message.get().c_str();
   383       } else {
   384         return 0;
   385       }
   386     }
   387 
   388     /// \brief Returns the filename.
   389     ///
   390     /// Returns \c 0 if the filename was not specified.
   391     const char* file() const {
   392       if (_file.valid()) {
   393         return _file.get().c_str();
   394       } else {
   395         return 0;
   396       }
   397     }
   398 
   399     ///\e
   400     virtual const char* what() const throw() {
   401       try {
   402         std::ostringstream ostr;
   403         if (message()) ostr << message();
   404         if (file()) ostr << "(when reading file '" << file() << "')";
   405         _message_holder.set(ostr.str());
   406       }
   407       catch (...) {}
   408       if( _message_holder.valid() ) return _message_holder.get().c_str();
   409       return "lemon:IoParameterError";
   410     }
   411     virtual ~IoParameterError() throw() {}
   412   };
   413 
   414   /// @}
   415 
   416 }
   417 
   418 #endif // LEMON_ERROR_H