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