Joshua
open source statistical hierarchical phrase-based machine translation system
|
00001 #ifndef UTIL_EXCEPTION_H 00002 #define UTIL_EXCEPTION_H 00003 00004 #include "util/string_stream.hh" 00005 00006 #include <exception> 00007 #include <limits> 00008 #include <string> 00009 #include <stdint.h> 00010 00011 namespace util { 00012 00013 template <class Except, class Data> typename Except::template ExceptionTag<Except&>::Identity operator<<(Except &e, const Data &data); 00014 00015 class Exception : public std::exception { 00016 public: 00017 Exception() throw(); 00018 virtual ~Exception() throw(); 00019 00020 const char *what() const throw() { return what_.c_str(); } 00021 00022 // For use by the UTIL_THROW macros. 00023 void SetLocation( 00024 const char *file, 00025 unsigned int line, 00026 const char *func, 00027 const char *child_name, 00028 const char *condition); 00029 00030 private: 00031 template <class Except, class Data> friend typename Except::template ExceptionTag<Except&>::Identity operator<<(Except &e, const Data &data); 00032 00033 // This helps restrict operator<< defined below. 00034 template <class T> struct ExceptionTag { 00035 typedef T Identity; 00036 }; 00037 00038 std::string what_; 00039 }; 00040 00041 /* This implements the normal operator<< for Exception and all its children. 00042 * SFINAE means it only applies to Exception. Think of this as an ersatz 00043 * boost::enable_if. 00044 */ 00045 template <class Except, class Data> typename Except::template ExceptionTag<Except&>::Identity operator<<(Except &e, const Data &data) { 00046 StringStream(e.what_) << data; 00047 return e; 00048 } 00049 00050 #ifdef __GNUC__ 00051 #define UTIL_FUNC_NAME __PRETTY_FUNCTION__ 00052 #else 00053 #ifdef _WIN32 00054 #define UTIL_FUNC_NAME __FUNCTION__ 00055 #else 00056 #define UTIL_FUNC_NAME NULL 00057 #endif 00058 #endif 00059 00060 /* Create an instance of Exception, add the message Modify, and throw it. 00061 * Modify is appended to the what() message and can contain << for ostream 00062 * operations. 00063 * 00064 * do .. while kludge to swallow trailing ; character 00065 * http://gcc.gnu.org/onlinedocs/cpp/Swallowing-the-Semicolon.html . 00066 * Arg can be a constructor argument to the exception. 00067 */ 00068 #define UTIL_THROW_BACKEND(Condition, Exception, Arg, Modify) do { \ 00069 Exception UTIL_e Arg; \ 00070 UTIL_e.SetLocation(__FILE__, __LINE__, UTIL_FUNC_NAME, #Exception, Condition); \ 00071 UTIL_e << Modify; \ 00072 throw UTIL_e; \ 00073 } while (0) 00074 00075 #define UTIL_THROW_ARG(Exception, Arg, Modify) \ 00076 UTIL_THROW_BACKEND(NULL, Exception, Arg, Modify) 00077 00078 #define UTIL_THROW(Exception, Modify) \ 00079 UTIL_THROW_BACKEND(NULL, Exception, , Modify); 00080 00081 #define UTIL_THROW2(Modify) \ 00082 UTIL_THROW_BACKEND(NULL, util::Exception, , Modify); 00083 00084 #if __GNUC__ >= 3 00085 #define UTIL_UNLIKELY(x) __builtin_expect (!!(x), 0) 00086 #else 00087 #define UTIL_UNLIKELY(x) (x) 00088 #endif 00089 00090 #if __GNUC__ >= 3 00091 #define UTIL_LIKELY(x) __builtin_expect (!!(x), 1) 00092 #else 00093 #define UTIL_LIKELY(x) (x) 00094 #endif 00095 00096 #define UTIL_THROW_IF_ARG(Condition, Exception, Arg, Modify) do { \ 00097 if (UTIL_UNLIKELY(Condition)) { \ 00098 UTIL_THROW_BACKEND(#Condition, Exception, Arg, Modify); \ 00099 } \ 00100 } while (0) 00101 00102 #define UTIL_THROW_IF(Condition, Exception, Modify) \ 00103 UTIL_THROW_IF_ARG(Condition, Exception, , Modify) 00104 00105 #define UTIL_THROW_IF2(Condition, Modify) \ 00106 UTIL_THROW_IF_ARG(Condition, util::Exception, , Modify) 00107 00108 // Exception that records errno and adds it to the message. 00109 class ErrnoException : public Exception { 00110 public: 00111 ErrnoException() throw(); 00112 00113 virtual ~ErrnoException() throw(); 00114 00115 int Error() const throw() { return errno_; } 00116 00117 private: 00118 int errno_; 00119 }; 00120 00121 // file wasn't there, or couldn't be open for some reason 00122 class FileOpenException : public Exception { 00123 public: 00124 FileOpenException() throw() {} 00125 ~FileOpenException() throw() {} 00126 }; 00127 00128 // Utilities for overflow checking. 00129 class OverflowException : public Exception { 00130 public: 00131 OverflowException() throw(); 00132 ~OverflowException() throw(); 00133 }; 00134 00135 template <unsigned len> inline std::size_t CheckOverflowInternal(uint64_t value) { 00136 UTIL_THROW_IF(value > static_cast<uint64_t>(std::numeric_limits<std::size_t>::max()), OverflowException, "Integer overflow detected. This model is too big for 32-bit code."); 00137 return value; 00138 } 00139 00140 template <> inline std::size_t CheckOverflowInternal<8>(uint64_t value) { 00141 return value; 00142 } 00143 00144 inline std::size_t CheckOverflow(uint64_t value) { 00145 return CheckOverflowInternal<sizeof(std::size_t)>(value); 00146 } 00147 00148 #if defined(_WIN32) || defined(_WIN64) 00149 /* Thrown for Windows specific operations. */ 00150 class WindowsException : public Exception { 00151 public: 00152 WindowsException() throw(); 00153 ~WindowsException() throw(); 00154 }; 00155 #endif 00156 00157 } // namespace util 00158 00159 #endif // UTIL_EXCEPTION_H