PFUNC  1.0
pfunc/exception.hpp
Go to the documentation of this file.
00001 #ifndef PFUNC_EXCEPTION_HPP
00002 #define PFUNC_EXCEPTION_HPP
00003 
00004 #include <exception>
00005 #include <typeinfo>
00006 #include <stdexcept>
00007 #include <string>
00008 #include <cstdlib>
00009 #include <pfunc/config.h>
00010 
00011 #if PFUNC_WINDOWS == 1
00012 #include <Windows.h>
00013 #endif
00014 
00020 namespace pfunc {
00021 #if PFUNC_WINDOWS == 1
00022     typedef DWORD error_code_type; 
00023 #else
00024     typedef int error_code_type;  
00025 #endif
00026 }
00027 
00031 #define LINE_TO_STR_HELP(line) #line
00032 
00036 #define LINE_TO_STR(line) LINE_TO_STR_HELP(line)
00037 
00041 #define FILE_AND_LINE() __FILE__ ":" LINE_TO_STR(__LINE__)
00042 
00054 #if PFUNC_USE_EXCEPTIONS == 1
00055 #define PFUNC_CATCH_AND_RETHROW(STRUCT_NAME,FUNC_NAME) \
00056   catch (const exception& error) { \
00057     /* Append append the information and throw again */ \
00058     if (NULL != except) except->destroy (); \
00059     except = error.clone (); \
00060     except->add_to_trace \
00061       (": from " #STRUCT_NAME"::"#FUNC_NAME " at " FILE_AND_LINE()); \
00062     except->rethrow (); \
00063   } catch (const std::exception& error) { \
00064     /* Wrap it up in a exception_generic_impl */ \
00065     std::string prev_trace (typeid (error).name()); \
00066     prev_trace += ": from " #STRUCT_NAME"::"#FUNC_NAME " at " FILE_AND_LINE(); \
00067     if (NULL != except) except->destroy (); \
00068     except = exception_generic_impl::convert \
00069                  (prev_trace.c_str(), error.what(), \
00070                   static_cast<error_code_type>(PFUNC_ERROR)); \
00071     except->rethrow (); \
00072   } catch (...) { \
00073     throw exception_generic_impl  \
00074      (#STRUCT_NAME"::"#FUNC_NAME " at " FILE_AND_LINE(), \
00075       "Unknown error", \
00076       static_cast<error_code_type>(PFUNC_ERROR)); \
00077   } 
00078 
00090 #define PFUNC_CATCH_AND_STORE(STRUCT_NAME,FUNC_NAME) \
00091   catch (const exception& error) { \
00092     /* Append append the information and throw again */ \
00093     if (NULL != except) except->destroy (); \
00094     except = error.clone (); \
00095     except->add_to_trace \
00096       (": from " #STRUCT_NAME"::"#FUNC_NAME " at " FILE_AND_LINE()); \
00097   } catch (const std::exception& error) { \
00098     /* Wrap it up in a exception_generic_impl */ \
00099     std::string prev_trace (typeid (error).name()); \
00100     prev_trace += ": from " #STRUCT_NAME"::"#FUNC_NAME " at " FILE_AND_LINE(); \
00101     if (NULL != except) except->destroy (); \
00102     except = exception_generic_impl::convert \
00103                  (prev_trace.c_str(), error.what(), \
00104                   static_cast<error_code_type>(PFUNC_ERROR)); \
00105   } catch (...) { \
00106     except = new exception_generic_impl  \
00107      (#STRUCT_NAME"::"#FUNC_NAME " at " FILE_AND_LINE(), \
00108       "Unknown error", \
00109       static_cast<error_code_type>(PFUNC_ERROR)); \
00110   } 
00111 
00115 #define PFUNC_CHECK_AND_RETHROW() if (NULL != except) except->rethrow();
00116 
00121 #define PFUNC_C_CATCH_AND_RETURN_EXCEPTION_CODE() \
00122   catch (const pfunc::exception& error) { \
00123     return error.code(); \
00124   }
00125 
00129 #define PFUNC_CXX_CATCH_AND_RETHROW() \
00130  catch (const exception& error) { error.rethrow(); }
00131 
00135 #define PFUNC_START_TRY_BLOCK() try {
00136 
00140 #define PFUNC_CONSTRUCTOR_TRY_BLOCK() try 
00141 
00145 #define PFUNC_END_TRY_BLOCK() }
00146 
00150 #define PFUNC_DEFINE_EXCEPT_PTR() exception* except;
00151 
00155 #define PFUNC_EXCEPT_PTR_INIT() , except (NULL) 
00156 
00160 #define PFUNC_EXCEPT_PTR_CLEAR() \
00161  if (NULL != except) { \
00162     except->destroy(); \
00163     except = NULL; \
00164  }
00165 
00170 #define PFUNC_CAPTURE_RETURN_VALUE(var) error_code_type var = 
00171 
00172 #else
00173 #define PFUNC_CATCH_AND_RETHROW(STRUCT_NAME,FUNC_NAME) 
00174 #define PFUNC_CATCH_AND_STORE(STRUCT_NAME,FUNC_NAME) 
00175 #define PFUNC_C_CATCH_AND_RETURN_EXCEPTION_CODE() 
00176 #define PFUNC_CHECK_AND_RETHROW() 
00177 #define PFUNC_CXX_CATCH_AND_RETHROW() 
00178 #define PFUNC_START_TRY_BLOCK() 
00179 #define PFUNC_CONSTRUCTOR_TRY_BLOCK() 
00180 #define PFUNC_END_TRY_BLOCK() 
00181 #define PFUNC_DEFINE_EXCEPT_PTR() 
00182 #define PFUNC_EXCEPT_PTR_INIT() 
00183 #define PFUNC_EXCEPT_PTR_CLEAR()
00184 #define PFUNC_CAPTURE_RETURN_VALUE(var) 
00185 #endif
00186 
00187 #if PFUNC_USE_EXCEPTIONS == 1
00188 namespace pfunc {
00189 
00194   struct exception : public std::exception {
00196     virtual const char* trace () const throw() = 0;
00197 
00199     virtual void add_to_trace (const char*) throw() = 0;
00200   
00202     virtual const char* what () const throw() = 0;
00203 
00205     virtual error_code_type code () const throw() = 0; 
00206   
00208     virtual exception* clone () const throw()  = 0;
00209   
00211     virtual void rethrow () const = 0;
00212   
00214     virtual void destroy () throw() = 0;
00215   };
00216   
00220   struct exception_generic_impl : virtual exception {
00221     private:
00222     std::string error_trace; 
00223     std::string error_string; 
00224     error_code_type error_code; 
00226     public:
00234     exception_generic_impl (const char* error_trace, 
00235                             const char* error_string,
00236                             const error_code_type& error_code=0) : 
00237                             error_trace (error_trace),
00238                             error_string (error_string),
00239                             error_code (error_code) {}
00240 
00246     exception_generic_impl (const exception_generic_impl& other) : 
00247                                     exception (),
00248                                     error_trace (other.trace()), 
00249                                     error_string (other.what()),
00250                                     error_code (other.code()) {}
00251 
00253     virtual ~exception_generic_impl () throw() {} 
00254 
00258     const char* trace (void) const throw() { return error_trace.c_str(); }
00259 
00265     void add_to_trace (const char* new_trace) throw() { 
00266       error_trace += new_trace; 
00267     }
00268   
00272     const char* what (void) const throw () { return error_string.c_str(); }
00273 
00277     error_code_type code (void) const throw() { return error_code; }
00278   
00284     exception* clone () const throw() {
00285       exception* clone = 
00286         reinterpret_cast<exception*> (malloc (sizeof (exception_generic_impl)));
00287       if (NULL != clone) new (clone) exception_generic_impl(*this);
00288       return clone;
00289     }
00290   
00296     void rethrow () const { throw *this; }
00297   
00308     static exception* convert (const char* _error_trace, 
00309                                const char* _error_string,
00310                                const error_code_type& _error_code = 0) throw() {
00311       exception* clone = 
00312         reinterpret_cast<exception*> (malloc (sizeof (exception_generic_impl)));
00313       if (NULL != clone) 
00314         new (clone) exception_generic_impl(_error_trace, 
00315                                            _error_string,
00316                                            _error_code);
00317    
00318       return clone;
00319     }
00320   
00325     void destroy () throw() {
00326       this->exception_generic_impl::~exception_generic_impl();
00327       free (this);
00328     }
00329   };
00330 } /* namespace pfunc */
00331 #endif // PFUNC_USE_EXCEPTIONS
00332 #endif // PFUNC_EXCEPTION_HPP