#ifndef UTIL_EXCEPTION_H #define UTIL_EXCEPTION_H #include "string_stream.hh" #include #include #include #include namespace util { template typename Except::template ExceptionTag::Identity operator<<(Except &e, const Data &data); class Exception : public std::exception { public: Exception() throw(); virtual ~Exception() throw(); const char *what() const throw() { return what_.str().c_str(); } // For use by the UTIL_THROW macros. void SetLocation( const char *file, unsigned int line, const char *func, const char *child_name, const char *condition); private: template friend typename Except::template ExceptionTag::Identity operator<<(Except &e, const Data &data); // This helps restrict operator<< defined below. template struct ExceptionTag { typedef T Identity; }; StringStream what_; }; /* This implements the normal operator<< for Exception and all its children. * SFINAE means it only applies to Exception. Think of this as an ersatz * boost::enable_if. */ template typename Except::template ExceptionTag::Identity operator<<(Except &e, const Data &data) { e.what_ << data; return e; } #ifdef __GNUC__ #define UTIL_FUNC_NAME __PRETTY_FUNCTION__ #else #ifdef _WIN32 #define UTIL_FUNC_NAME __FUNCTION__ #else #define UTIL_FUNC_NAME NULL #endif #endif /* Create an instance of Exception, add the message Modify, and throw it. * Modify is appended to the what() message and can contain << for ostream * operations. * * do .. while kludge to swallow trailing ; character * http://gcc.gnu.org/onlinedocs/cpp/Swallowing-the-Semicolon.html . * Arg can be a constructor argument to the exception. */ #define UTIL_THROW_BACKEND(Condition, Exception, Arg, Modify) do { \ Exception UTIL_e Arg; \ UTIL_e.SetLocation(__FILE__, __LINE__, UTIL_FUNC_NAME, #Exception, Condition); \ UTIL_e << Modify; \ throw UTIL_e; \ } while (0) #define UTIL_THROW_ARG(Exception, Arg, Modify) \ UTIL_THROW_BACKEND(NULL, Exception, Arg, Modify) #define UTIL_THROW(Exception, Modify) \ UTIL_THROW_BACKEND(NULL, Exception, , Modify); #define UTIL_THROW2(Modify) \ UTIL_THROW_BACKEND(NULL, util::Exception, , Modify); #if __GNUC__ >= 3 #define UTIL_UNLIKELY(x) __builtin_expect (!!(x), 0) #else #define UTIL_UNLIKELY(x) (x) #endif #if __GNUC__ >= 3 #define UTIL_LIKELY(x) __builtin_expect (!!(x), 1) #else #define UTIL_LIKELY(x) (x) #endif #define UTIL_THROW_IF_ARG(Condition, Exception, Arg, Modify) do { \ if (UTIL_UNLIKELY(Condition)) { \ UTIL_THROW_BACKEND(#Condition, Exception, Arg, Modify); \ } \ } while (0) #define UTIL_THROW_IF(Condition, Exception, Modify) \ UTIL_THROW_IF_ARG(Condition, Exception, , Modify) #define UTIL_THROW_IF2(Condition, Modify) \ UTIL_THROW_IF_ARG(Condition, util::Exception, , Modify) // Exception that records errno and adds it to the message. class ErrnoException : public Exception { public: ErrnoException() throw(); virtual ~ErrnoException() throw(); int Error() const throw() { return errno_; } private: int errno_; }; // file wasn't there, or couldn't be open for some reason class FileOpenException : public Exception { public: FileOpenException() throw() {} ~FileOpenException() throw() {} }; // Utilities for overflow checking. class OverflowException : public Exception { public: OverflowException() throw(); ~OverflowException() throw(); }; template inline std::size_t CheckOverflowInternal(uint64_t value) { UTIL_THROW_IF(value > static_cast(std::numeric_limits::max()), OverflowException, "Integer overflow detected. This model is too big for 32-bit code."); return static_cast(value); } template <> inline std::size_t CheckOverflowInternal<8>(uint64_t value) { return value; } inline std::size_t CheckOverflow(uint64_t value) { return CheckOverflowInternal(value); } #if defined(_WIN32) || defined(_WIN64) /* Thrown for Windows specific operations. */ class WindowsException : public Exception { public: WindowsException() throw(); ~WindowsException() throw(); }; #endif } // namespace util #endif // UTIL_EXCEPTION_H