2014-07-19 02:54:01 +04:00
# ifndef UTIL_EXCEPTION_H
# define UTIL_EXCEPTION_H
2012-10-15 16:58:33 +04:00
# include <exception>
# include <limits>
# include <sstream>
# include <string>
2012-10-18 21:54:38 +04:00
# include <stdint.h>
2012-10-15 16:58:33 +04:00
namespace util {
template < class Except , class Data > typename Except : : template ExceptionTag < Except & > : : Identity operator < < ( Except & e , const Data & data ) ;
class Exception : public std : : exception {
public :
Exception ( ) throw ( ) ;
virtual ~ Exception ( ) throw ( ) ;
Exception ( const Exception & from ) ;
Exception & operator = ( const Exception & from ) ;
// Not threadsafe, but probably doesn't matter. FWIW, Boost's exception guidance implies that what() isn't threadsafe.
const char * what ( ) const throw ( ) ;
// 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 < class Except , class Data > friend typename Except : : template ExceptionTag < Except & > : : Identity operator < < ( Except & e , const Data & data ) ;
// This helps restrict operator<< defined below.
template < class T > struct ExceptionTag {
typedef T Identity ;
} ;
std : : stringstream stream_ ;
mutable std : : string text_ ;
} ;
/* This implements the normal operator<< for Exception and all its children.
2013-01-17 15:58:58 +04:00
* SFINAE means it only applies to Exception . Think of this as an ersatz
2012-10-15 16:58:33 +04:00
* boost : : enable_if .
*/
template < class Except , class Data > typename Except : : template ExceptionTag < Except & > : : Identity operator < < ( Except & e , const Data & data ) {
e . stream_ < < 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 .
2013-01-17 15:58:58 +04:00
* Arg can be a constructor argument to the exception .
2012-10-15 16:58:33 +04:00
*/
2013-01-17 15:58:58 +04:00
# define UTIL_THROW_BACKEND(Condition, Exception, Arg, Modify) do { \
Exception UTIL_e Arg ; \
UTIL_e . SetLocation ( __FILE__ , __LINE__ , UTIL_FUNC_NAME , # Exception , Condition ) ; \
2012-10-15 16:58:33 +04:00
UTIL_e < < Modify ; \
throw UTIL_e ; \
} while ( 0 )
2013-01-17 15:58:58 +04:00
# 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 ) ;
2012-10-15 16:58:33 +04:00
2014-01-13 18:37:05 +04:00
# define UTIL_THROW2(Modify) \
2014-07-19 02:54:01 +04:00
UTIL_THROW_BACKEND ( NULL , util : : Exception , , Modify ) ;
2014-01-13 18:37:05 +04:00
2012-11-15 16:00:15 +04:00
# if __GNUC__ >= 3
# define UTIL_UNLIKELY(x) __builtin_expect (!!(x), 0)
# else
# define UTIL_UNLIKELY(x) (x)
# endif
2013-01-17 15:58:58 +04:00
# define UTIL_THROW_IF_ARG(Condition, Exception, Arg, Modify) do { \
2012-11-15 16:00:15 +04:00
if ( UTIL_UNLIKELY ( Condition ) ) { \
2013-01-17 15:58:58 +04:00
UTIL_THROW_BACKEND ( # Condition , Exception , Arg , Modify ) ; \
2012-10-15 16:58:33 +04:00
} \
} while ( 0 )
2013-01-17 15:58:58 +04:00
# define UTIL_THROW_IF(Condition, Exception, Modify) \
UTIL_THROW_IF_ARG ( Condition , Exception , , Modify )
2013-11-15 22:29:22 +04:00
# define UTIL_THROW_IF2(Condition, Modify) \
UTIL_THROW_IF_ARG ( Condition , util : : Exception , , Modify )
2013-01-17 15:58:58 +04:00
// Exception that records errno and adds it to the message.
2012-10-15 16:58:33 +04:00
class ErrnoException : public Exception {
public :
ErrnoException ( ) throw ( ) ;
virtual ~ ErrnoException ( ) throw ( ) ;
int Error ( ) const throw ( ) { return errno_ ; }
private :
int errno_ ;
} ;
2013-11-16 00:14:10 +04:00
// file wasn't there, or couldn't be open for some reason
class FileOpenException : public Exception {
public :
FileOpenException ( ) throw ( ) { }
~ FileOpenException ( ) throw ( ) { }
} ;
2013-01-17 15:58:58 +04:00
// Utilities for overflow checking.
2012-10-15 16:58:33 +04:00
class OverflowException : public Exception {
public :
OverflowException ( ) throw ( ) ;
~ OverflowException ( ) throw ( ) ;
} ;
template < unsigned len > inline std : : size_t CheckOverflowInternal ( uint64_t value ) {
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. " ) ;
return value ;
}
template < > inline std : : size_t CheckOverflowInternal < 8 > ( uint64_t value ) {
return value ;
}
inline std : : size_t CheckOverflow ( uint64_t value ) {
return CheckOverflowInternal < sizeof ( std : : size_t ) > ( value ) ;
}
} // namespace util
2014-07-19 02:54:01 +04:00
# endif // UTIL_EXCEPTION_H