|
Joshua
open source statistical hierarchical phrase-based machine translation system
|
00001 #ifndef UTIL_EXCEPTION__ 00002 #define UTIL_EXCEPTION__ 00003 00004 #include <exception> 00005 #include <sstream> 00006 #include <string> 00007 00008 namespace util { 00009 00010 template <class Except, class Data> typename Except::template ExceptionTag<Except&>::Identity operator<<(Except &e, const Data &data); 00011 00012 class Exception : public std::exception { 00013 public: 00014 Exception() throw(); 00015 virtual ~Exception() throw(); 00016 00017 Exception(const Exception &from); 00018 Exception &operator=(const Exception &from); 00019 00020 // Not threadsafe, but probably doesn't matter. FWIW, Boost's exception guidance implies that what() isn't threadsafe. 00021 const char *what() const throw(); 00022 00023 // For use by the UTIL_THROW macros. 00024 void SetLocation( 00025 const char *file, 00026 unsigned int line, 00027 const char *func, 00028 const char *child_name, 00029 const char *condition); 00030 00031 private: 00032 template <class Except, class Data> friend typename Except::template ExceptionTag<Except&>::Identity operator<<(Except &e, const Data &data); 00033 00034 // This helps restrict operator<< defined below. 00035 template <class T> struct ExceptionTag { 00036 typedef T Identity; 00037 }; 00038 00039 std::stringstream stream_; 00040 mutable std::string text_; 00041 }; 00042 00043 /* This implements the normal operator<< for Exception and all its children. 00044 * SNIFAE means it only applies to Exception. Think of this as an ersatz 00045 * boost::enable_if. 00046 */ 00047 template <class Except, class Data> typename Except::template ExceptionTag<Except&>::Identity operator<<(Except &e, const Data &data) { 00048 e.stream_ << data; 00049 return e; 00050 } 00051 00052 #ifdef __GNUC__ 00053 #define UTIL_FUNC_NAME __PRETTY_FUNCTION__ 00054 #else 00055 #ifdef _WIN32 00056 #define UTIL_FUNC_NAME __FUNCTION__ 00057 #else 00058 #define UTIL_FUNC_NAME NULL 00059 #endif 00060 #endif 00061 00062 #define UTIL_SET_LOCATION(UTIL_e, child, condition) do { \ 00063 (UTIL_e).SetLocation(__FILE__, __LINE__, UTIL_FUNC_NAME, (child), (condition)); \ 00064 } while (0) 00065 00066 /* Create an instance of Exception, add the message Modify, and throw it. 00067 * Modify is appended to the what() message and can contain << for ostream 00068 * operations. 00069 * 00070 * do .. while kludge to swallow trailing ; character 00071 * http://gcc.gnu.org/onlinedocs/cpp/Swallowing-the-Semicolon.html . 00072 */ 00073 #define UTIL_THROW(Exception, Modify) do { \ 00074 Exception UTIL_e; \ 00075 UTIL_SET_LOCATION(UTIL_e, #Exception, NULL); \ 00076 UTIL_e << Modify; \ 00077 throw UTIL_e; \ 00078 } while (0) 00079 00080 #define UTIL_THROW_VAR(Var, Modify) do { \ 00081 Exception &UTIL_e = (Var); \ 00082 UTIL_SET_LOCATION(UTIL_e, NULL, NULL); \ 00083 UTIL_e << Modify; \ 00084 throw UTIL_e; \ 00085 } while (0) 00086 00087 #define UTIL_THROW_IF(Condition, Exception, Modify) do { \ 00088 if (Condition) { \ 00089 Exception UTIL_e; \ 00090 UTIL_SET_LOCATION(UTIL_e, #Exception, #Condition); \ 00091 UTIL_e << Modify; \ 00092 throw UTIL_e; \ 00093 } \ 00094 } while (0) 00095 00096 class ErrnoException : public Exception { 00097 public: 00098 ErrnoException() throw(); 00099 00100 virtual ~ErrnoException() throw(); 00101 00102 int Error() const throw() { return errno_; } 00103 00104 private: 00105 int errno_; 00106 }; 00107 00108 } // namespace util 00109 00110 #endif // UTIL_EXCEPTION__