Joshua
open source statistical hierarchical phrase-based machine translation system
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends
src/kenlm/util/exception.hh
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