upgrade exception handling to support custom types in 3rd party libraries
This commit is contained in:
parent
0a2a9ec25b
commit
d046526974
3 changed files with 228 additions and 299 deletions
|
|
@ -6,11 +6,32 @@
|
|||
#include <fc/log/log_message.hpp>
|
||||
#include <fc/optional.hpp>
|
||||
#include <exception>
|
||||
#include <unordered_map>
|
||||
|
||||
|
||||
namespace fc
|
||||
{
|
||||
namespace detail { class exception_impl; }
|
||||
|
||||
enum exception_code
|
||||
{
|
||||
/** for exceptions we threw that don't have an assigned code */
|
||||
unspecified_exception_code = 0,
|
||||
unhandled_exception_code = 1, ///< for unhandled 3rd party exceptions
|
||||
timeout_exception_code = 2, ///< timeout exceptions
|
||||
file_not_found_exception_code = 3,
|
||||
parse_error_exception_code = 4,
|
||||
invalid_arg_exception_code = 5,
|
||||
key_not_found_exception_code = 6,
|
||||
bad_cast_exception_code = 7,
|
||||
out_of_range_exception_code = 8,
|
||||
canceled_exception_code = 9,
|
||||
assert_exception_code = 10,
|
||||
eof_exception_code = 11,
|
||||
std_exception_code = 13,
|
||||
invalid_operation_exception_code = 14
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Used to generate a useful error report when an exception is thrown.
|
||||
* @ingroup serializable
|
||||
|
|
@ -28,13 +49,27 @@ namespace fc
|
|||
class exception
|
||||
{
|
||||
public:
|
||||
exception();
|
||||
exception( log_message&& );
|
||||
enum code_enum
|
||||
{
|
||||
code_value = unspecified_exception_code
|
||||
};
|
||||
|
||||
exception( int64_t code = unspecified_exception_code,
|
||||
const std::string& name_value = "exception",
|
||||
const std::string& what_value = "unspecified");
|
||||
exception( log_message&&, int64_t code = unspecified_exception_code,
|
||||
const std::string& name_value = "exception",
|
||||
const std::string& what_value = "unspecified");
|
||||
exception( log_messages&&, int64_t code = unspecified_exception_code,
|
||||
const std::string& name_value = "exception",
|
||||
const std::string& what_value = "unspecified");
|
||||
exception( const exception& e );
|
||||
exception( exception&& e );
|
||||
~exception();
|
||||
|
||||
virtual const char* what()const throw() { return "exception"; }
|
||||
const char* name()const throw();
|
||||
int64_t code()const throw();
|
||||
virtual const char* what()const throw();
|
||||
|
||||
/**
|
||||
* @return a reference to log messages that have
|
||||
|
|
@ -69,16 +104,14 @@ namespace fc
|
|||
* catch( ... ) { return std::current_exception(); }
|
||||
* @endcode
|
||||
*/
|
||||
virtual std::shared_ptr<exception> dynamic_copy_exception()const;
|
||||
virtual std::shared_ptr<exception> dynamic_copy_exception()const;
|
||||
|
||||
protected:
|
||||
friend void to_variant( const exception& e, variant& v );
|
||||
friend void from_variant( const variant& e, exception& ll );
|
||||
virtual void from_variant( const variant& ){}
|
||||
virtual void to_variant( variant& ){}
|
||||
|
||||
protected:
|
||||
std::unique_ptr<detail::exception_impl> my;
|
||||
};
|
||||
|
||||
void to_variant( const exception& e, variant& v );
|
||||
void from_variant( const variant& e, exception& ll );
|
||||
typedef std::shared_ptr<exception> exception_ptr;
|
||||
|
|
@ -86,7 +119,6 @@ namespace fc
|
|||
typedef optional<exception> oexception;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief re-thrown whenever an unhandled exception is caught.
|
||||
* @ingroup serializable
|
||||
|
|
@ -100,14 +132,17 @@ namespace fc
|
|||
class unhandled_exception : public exception
|
||||
{
|
||||
public:
|
||||
enum code_enum {
|
||||
code_value = unhandled_exception_code,
|
||||
};
|
||||
unhandled_exception( log_message&& m, std::exception_ptr e = std::current_exception() );
|
||||
unhandled_exception( log_messages );
|
||||
unhandled_exception( const exception& );
|
||||
virtual const char* what()const throw() { return "Unhandled _exception"; }
|
||||
|
||||
std::exception_ptr get_inner_exception()const;
|
||||
|
||||
virtual NO_RETURN void dynamic_rethrow_exception()const;
|
||||
virtual std::shared_ptr<exception> dynamic_copy_exception()const;
|
||||
virtual NO_RETURN void dynamic_rethrow_exception()const;
|
||||
virtual std::shared_ptr<exception> dynamic_copy_exception()const;
|
||||
private:
|
||||
std::exception_ptr _inner;
|
||||
};
|
||||
|
|
@ -116,78 +151,120 @@ namespace fc
|
|||
fc::exception_ptr copy_exception( T&& e )
|
||||
{
|
||||
#if defined(_MSC_VER) && (_MSC_VER < 1700)
|
||||
return std::make_shared<unhandled_exception>( log_message(), std::copy_exception(fc::forward<T>(e)) );
|
||||
return std::make_shared<unhandled_exception>( log_message(),
|
||||
std::copy_exception(fc::forward<T>(e)) );
|
||||
#else
|
||||
return std::make_shared<unhandled_exception>( log_message(), std::make_exception_ptr(fc::forward<T>(e)) );
|
||||
return std::make_shared<unhandled_exception>( log_message(),
|
||||
std::make_exception_ptr(fc::forward<T>(e)) );
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief wraps unhanlded std::exception's
|
||||
* @ingroup serializable
|
||||
*
|
||||
* This exception allows the 'what' field of unhandled std::exceptions
|
||||
* to be propagated across process boundaries.
|
||||
*/
|
||||
class std_exception : public unhandled_exception
|
||||
{
|
||||
public:
|
||||
std_exception( log_message&& m, std::exception_ptr e, const char* w );
|
||||
std_exception( log_messages );
|
||||
std_exception( const exception& c);
|
||||
virtual const char* what()const throw() { return _what.c_str(); }
|
||||
|
||||
protected:
|
||||
void from_variant( const variant& v );
|
||||
void to_variant( variant& v );
|
||||
class exception_factory
|
||||
{
|
||||
public:
|
||||
struct base_exception_builder
|
||||
{
|
||||
virtual NO_RETURN void rethrow( const exception& e )const = 0;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct exception_builder : public base_exception_builder
|
||||
{
|
||||
virtual NO_RETURN void rethrow( const exception& e )const override
|
||||
{
|
||||
throw T( e );
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
void register_exception()
|
||||
{
|
||||
static exception_builder<T> builder;
|
||||
auto itr = _registered_exceptions.find( T::code_value );
|
||||
assert( itr == _registered_exceptions.end() );
|
||||
_registered_exceptions[T::code_value] = &builder;
|
||||
}
|
||||
|
||||
void rethrow( const exception& e )const;
|
||||
|
||||
static exception_factory& instance()
|
||||
{
|
||||
static exception_factory once;
|
||||
return once;
|
||||
}
|
||||
|
||||
private:
|
||||
string _what;
|
||||
std::unordered_map<int64_t,base_exception_builder*> _registered_exceptions;
|
||||
};
|
||||
#define FC_REGISTER_EXCEPTION(r, unused, base) \
|
||||
fc::exception_factory::instance().register_exception<base>();
|
||||
|
||||
#define FC_REGISTER_EXCEPTIONS( SEQ )\
|
||||
\
|
||||
static bool exception_init = []()->bool{ \
|
||||
BOOST_PP_SEQ_FOR_EACH( FC_REGISTER_EXCEPTION, v, SEQ ) \
|
||||
return true; \
|
||||
}(); \
|
||||
|
||||
|
||||
#define FC_DECLARE_EXCEPTION( TYPE, WHAT ) \
|
||||
class TYPE : public exception \
|
||||
#define FC_DECLARE_EXCEPTION( TYPE, CODE, WHAT ) \
|
||||
class TYPE : public fc::exception \
|
||||
{ \
|
||||
public: \
|
||||
TYPE( log_message&& m ); \
|
||||
TYPE( log_messages ); \
|
||||
TYPE( const TYPE& c ); \
|
||||
TYPE(); \
|
||||
virtual const char* what()const throw() { return WHAT; } \
|
||||
enum code_enum { \
|
||||
code_value = CODE, \
|
||||
}; \
|
||||
TYPE( fc::log_message&& m ) \
|
||||
:exception( fc::move(m), CODE, BOOST_PP_STRINGIZE(TYPE), WHAT ){}\
|
||||
TYPE( fc::log_messages msgs ) \
|
||||
:exception( fc::move( msgs ), CODE, BOOST_PP_STRINGIZE(TYPE), WHAT ) {} \
|
||||
TYPE( const TYPE& c ) \
|
||||
:exception(c){} \
|
||||
TYPE( const exception& c ) \
|
||||
:exception(c){} \
|
||||
TYPE():exception(){}\
|
||||
\
|
||||
virtual std::shared_ptr<exception> dynamic_copy_exception()const\
|
||||
{ return std::make_shared<TYPE>( *this ); } \
|
||||
virtual NO_RETURN void dynamic_rethrow_exception()const \
|
||||
{ if( code() == CODE ) throw *this;\
|
||||
else fc::exception::dynamic_rethrow_exception(); \
|
||||
} \
|
||||
};
|
||||
|
||||
|
||||
FC_DECLARE_EXCEPTION( timeout_exception, "Timeout" );
|
||||
FC_DECLARE_EXCEPTION( file_not_found_exception, "File Not Found" );
|
||||
FC_DECLARE_EXCEPTION( timeout_exception, timeout_exception_code, "Timeout" );
|
||||
FC_DECLARE_EXCEPTION( file_not_found_exception, file_not_found_exception_code, "File Not Found" );
|
||||
/**
|
||||
* @brief report's parse errors
|
||||
*/
|
||||
FC_DECLARE_EXCEPTION( parse_error_exception, "Parse Error" );
|
||||
FC_DECLARE_EXCEPTION( invalid_arg_exception, "Invalid Argument" );
|
||||
FC_DECLARE_EXCEPTION( parse_error_exception, parse_error_exception_code, "Parse Error" );
|
||||
FC_DECLARE_EXCEPTION( invalid_arg_exception, invalid_arg_exception_code, "Invalid Argument" );
|
||||
/**
|
||||
* @brief reports when a key, guid, or other item is not found.
|
||||
*/
|
||||
FC_DECLARE_EXCEPTION( key_not_found_exception, "Key Not Found" );
|
||||
FC_DECLARE_EXCEPTION( bad_cast_exception, "Bad Cast" );
|
||||
FC_DECLARE_EXCEPTION( out_of_range_exception, "Out of Range" );
|
||||
FC_DECLARE_EXCEPTION( key_not_found_exception, key_not_found_exception_code, "Key Not Found" );
|
||||
FC_DECLARE_EXCEPTION( bad_cast_exception, bad_cast_exception_code, "Bad Cast" );
|
||||
FC_DECLARE_EXCEPTION( out_of_range_exception, out_of_range_exception_code, "Out of Range" );
|
||||
|
||||
/** @brief if an operation is unsupported or not valid this may be thrown */
|
||||
FC_DECLARE_EXCEPTION( invalid_operation_exception, "Invalid Operation" );
|
||||
FC_DECLARE_EXCEPTION( invalid_operation_exception,
|
||||
invalid_operation_exception_code,
|
||||
"Invalid Operation" );
|
||||
|
||||
/**
|
||||
* @brief used to report a canceled Operation
|
||||
*/
|
||||
FC_DECLARE_EXCEPTION( canceled_exception, "Canceled" );
|
||||
FC_DECLARE_EXCEPTION( canceled_exception, canceled_exception_code, "Canceled" );
|
||||
/**
|
||||
* @brief used inplace of assert() to report violations of pre conditions.
|
||||
*/
|
||||
FC_DECLARE_EXCEPTION( assert_exception, "Assert Exception" );
|
||||
FC_DECLARE_EXCEPTION( eof_exception, "End Of File" );
|
||||
|
||||
FC_DECLARE_EXCEPTION( db_in_use_exception, "Database already in use" );
|
||||
FC_DECLARE_EXCEPTION( assert_exception, assert_exception_code, "Assert Exception" );
|
||||
FC_DECLARE_EXCEPTION( eof_exception, eof_exception_code, "End Of File" );
|
||||
|
||||
std::string except_str();
|
||||
|
||||
|
||||
} // namespace fc
|
||||
|
||||
/**
|
||||
|
|
@ -199,7 +276,7 @@ namespace fc
|
|||
*/
|
||||
#define FC_ASSERT( TEST, ... ) \
|
||||
FC_EXPAND_MACRO( \
|
||||
do { if( !(TEST) ) { FC_THROW_EXCEPTION( assert_exception, #TEST ": " __VA_ARGS__ ); } } while(0); \
|
||||
do { if( !(TEST) ) { FC_THROW_EXCEPTION( fc::assert_exception, #TEST ": " __VA_ARGS__ ); } } while(0); \
|
||||
)
|
||||
|
||||
#define FC_THROW( FORMAT, ... ) \
|
||||
|
|
@ -208,7 +285,7 @@ do { if( !(TEST) ) { FC_THROW_EXCEPTION( assert_exception, #TEST ": " __VA_ARGS
|
|||
} while(0)
|
||||
|
||||
#define FC_EXCEPTION( EXCEPTION_TYPE, FORMAT, ... ) \
|
||||
fc::EXCEPTION_TYPE( FC_LOG_MESSAGE( error, FORMAT, __VA_ARGS__ ) )
|
||||
EXCEPTION_TYPE( FC_LOG_MESSAGE( error, FORMAT, __VA_ARGS__ ) )
|
||||
/**
|
||||
* @def FC_THROW_EXCEPTION( EXCEPTION, FORMAT, ... )
|
||||
* @param EXCEPTION a class in the Phoenix::Athena::API namespace that inherits
|
||||
|
|
@ -216,7 +293,7 @@ do { if( !(TEST) ) { FC_THROW_EXCEPTION( assert_exception, #TEST ": " __VA_ARGS
|
|||
*/
|
||||
#define FC_THROW_EXCEPTION( EXCEPTION, FORMAT, ... ) \
|
||||
do { \
|
||||
throw fc::EXCEPTION( FC_LOG_MESSAGE( error, FORMAT, __VA_ARGS__ ) ); \
|
||||
throw EXCEPTION( FC_LOG_MESSAGE( error, FORMAT, __VA_ARGS__ ) ); \
|
||||
} while(0)
|
||||
|
||||
|
||||
|
|
@ -239,13 +316,27 @@ do { if( !(TEST) ) { FC_THROW_EXCEPTION( assert_exception, #TEST ": " __VA_ARGS
|
|||
catch( fc::exception& er ) { \
|
||||
FC_RETHROW_EXCEPTION( er, LOG_LEVEL, FORMAT, __VA_ARGS__ ); \
|
||||
} catch( const std::exception& e ) { \
|
||||
fc::std_exception fce( \
|
||||
FC_LOG_MESSAGE( LOG_LEVEL, "what: ${what} - " FORMAT,__VA_ARGS__("what",e.what())), \
|
||||
std::current_exception(), \
|
||||
fc::exception fce( \
|
||||
FC_LOG_MESSAGE( LOG_LEVEL, "${what}" FORMAT,__VA_ARGS__("what",e.what())), \
|
||||
fc::std_exception_code,\
|
||||
typeid(e).name(), \
|
||||
e.what() ) ; throw fce;\
|
||||
} catch( ... ) { \
|
||||
throw fc::unhandled_exception( \
|
||||
FC_LOG_MESSAGE( LOG_LEVEL, FORMAT,__VA_ARGS__), \
|
||||
std::current_exception() ); \
|
||||
}
|
||||
|
||||
#define FC_CAPTURE_AND_RETHROW( SEQ ) \
|
||||
catch( fc::exception& er ) { \
|
||||
FC_RETHROW_EXCEPTION( er, fc::log_level::warn, "", FC_FORMAT_ARG_PARAMS(SEQ) ); \
|
||||
} catch( const std::exception& e ) { \
|
||||
fc::exception fce( \
|
||||
FC_LOG_MESSAGE( fc::log_level::warn, "${what}",FC_FORMAT_ARG_PARAMS(SEQ)("what",e.what())), \
|
||||
fc::std_exception_code,\
|
||||
typeid(e).name(), \
|
||||
e.what() ) ; throw fce;\
|
||||
} catch( ... ) { \
|
||||
throw fc::unhandled_exception( \
|
||||
FC_LOG_MESSAGE( fc::log_level::warn, "",FC_FORMAT_ARG_PARAMS(SEQ)), \
|
||||
std::current_exception() ); \
|
||||
}
|
||||
|
|
|
|||
|
|
@ -136,4 +136,8 @@ namespace fc
|
|||
|
||||
#define idump( SEQ ) \
|
||||
ilog( FC_FORMAT(SEQ), FC_FORMAT_ARG_PARAMS(SEQ) )
|
||||
#define wdump( SEQ ) \
|
||||
wlog( FC_FORMAT(SEQ), FC_FORMAT_ARG_PARAMS(SEQ) )
|
||||
#define edump( SEQ ) \
|
||||
elog( FC_FORMAT(SEQ), FC_FORMAT_ARG_PARAMS(SEQ) )
|
||||
|
||||
|
|
|
|||
|
|
@ -6,144 +6,34 @@
|
|||
|
||||
namespace fc
|
||||
{
|
||||
FC_REGISTER_EXCEPTIONS( (timeout_exception)
|
||||
(file_not_found_exception)
|
||||
(parse_error_exception)
|
||||
(invalid_arg_exception)
|
||||
(invalid_operation_exception)
|
||||
(key_not_found_exception)
|
||||
(bad_cast_exception)
|
||||
(out_of_range_exception)
|
||||
(canceled_exception)
|
||||
(assert_exception)
|
||||
(eof_exception)
|
||||
)
|
||||
|
||||
namespace detail
|
||||
{
|
||||
enum exception_code
|
||||
{
|
||||
unspecified_exception_code = 0, ///< for exceptions we threw that don't have an assigned code
|
||||
unhandled_exception_code = 1, ///< for unhandled 3rd party exceptions
|
||||
timeout_exception_code = 2, ///< timeout exceptions
|
||||
file_not_found_exception_code = 3,
|
||||
parse_error_exception_code = 4,
|
||||
invalid_arg_exception_code = 5,
|
||||
key_not_found_exception_code = 6,
|
||||
bad_cast_exception_code = 7,
|
||||
out_of_range_exception_code = 8,
|
||||
canceled_exception_code = 9,
|
||||
assert_exception_code = 10,
|
||||
eof_exception_code = 11,
|
||||
db_in_use_exception_code = 12,
|
||||
std_exception_code = 14,
|
||||
invalid_operation_exception_code = 15
|
||||
};
|
||||
|
||||
void to_variant( detail::exception_code e, variant& v )
|
||||
{
|
||||
switch( e )
|
||||
{
|
||||
case unhandled_exception_code:
|
||||
v = "unhandled";
|
||||
break;
|
||||
case timeout_exception_code:
|
||||
v = "timeout";
|
||||
break;
|
||||
case key_not_found_exception_code:
|
||||
v = "invalid_key";
|
||||
break;
|
||||
case bad_cast_exception_code:
|
||||
v = "bad_cast";
|
||||
break;
|
||||
case file_not_found_exception_code:
|
||||
v = "file_not_found";
|
||||
break;
|
||||
case parse_error_exception_code:
|
||||
v = "parse_error";
|
||||
break;
|
||||
case invalid_arg_exception_code:
|
||||
v = "invalid_arg";
|
||||
break;
|
||||
case out_of_range_exception_code:
|
||||
v = "out_of_range";
|
||||
break;
|
||||
case canceled_exception_code:
|
||||
v = "canceled";
|
||||
break;
|
||||
case assert_exception_code:
|
||||
v = "assert";
|
||||
break;
|
||||
case std_exception_code:
|
||||
v = "std";
|
||||
break;
|
||||
case eof_exception_code:
|
||||
v = "eof";
|
||||
break;
|
||||
case db_in_use_exception_code:
|
||||
v = "db_in_use";
|
||||
break;
|
||||
case invalid_operation_exception_code:
|
||||
v = "invalid_operation";
|
||||
break;
|
||||
case unspecified_exception_code:
|
||||
default:
|
||||
v = "unspecified";
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
void from_variant( const variant& e, detail::exception_code& ll )
|
||||
{
|
||||
string v = e.as_string();
|
||||
if( v == "unspecified" ) ll = unspecified_exception_code;
|
||||
else if( v == "unhandled" ) ll = unhandled_exception_code;
|
||||
else if( v == "timeout" ) ll = timeout_exception_code;
|
||||
else if( v == "key_not_found" ) ll = key_not_found_exception_code;
|
||||
else if( v == "bad_cast" ) ll = bad_cast_exception_code;
|
||||
else if( v == "file_not_found" ) ll = file_not_found_exception_code;
|
||||
else if( v == "parse_error" ) ll = parse_error_exception_code;
|
||||
else if( v == "invalid_arg" ) ll = invalid_arg_exception_code;
|
||||
else if( v == "out_of_range" ) ll = out_of_range_exception_code;
|
||||
else if( v == "canceled" ) ll = canceled_exception_code;
|
||||
else if( v == "assert" ) ll = assert_exception_code;
|
||||
else if( v == "std" ) ll = std_exception_code;
|
||||
else if( v == "eof" ) ll = eof_exception_code;
|
||||
else if( v == "db_in_use") ll = db_in_use_exception_code;
|
||||
else if( v == "invalid_operation") ll = invalid_operation_exception_code;
|
||||
else FC_THROW_EXCEPTION( bad_cast_exception,
|
||||
"Invalid Error Report _code '${code}'",
|
||||
("code", v) );
|
||||
}
|
||||
|
||||
class exception_impl
|
||||
{
|
||||
public:
|
||||
exception_code _ecode;
|
||||
std::string _name;
|
||||
std::string _what;
|
||||
int64_t _code;
|
||||
log_messages _elog;
|
||||
variant _props;
|
||||
};
|
||||
}
|
||||
|
||||
std_exception::std_exception( log_message&& m, std::exception_ptr e, const char* w )
|
||||
:unhandled_exception( fc::move(m), e )
|
||||
{
|
||||
my->_ecode = detail::std_exception_code;
|
||||
_what = w;
|
||||
}
|
||||
std_exception::std_exception( const exception& e )
|
||||
:unhandled_exception(e)
|
||||
{
|
||||
from_variant( my->_props );
|
||||
}
|
||||
|
||||
std_exception::std_exception( log_messages m )
|
||||
:unhandled_exception(fc::move(m) )
|
||||
{
|
||||
my->_ecode = detail::std_exception_code;
|
||||
}
|
||||
|
||||
void std_exception::from_variant( const variant& v )
|
||||
{
|
||||
_what = v.get_object()["what"].as_string();
|
||||
}
|
||||
void std_exception::to_variant( variant& v )
|
||||
{
|
||||
v = variant_object( "what", _what );
|
||||
}
|
||||
|
||||
|
||||
unhandled_exception::unhandled_exception( log_message&& m, std::exception_ptr e )
|
||||
:exception( fc::move(m) )
|
||||
{
|
||||
my->_ecode = detail::unhandled_exception_code;
|
||||
_inner = e;
|
||||
}
|
||||
unhandled_exception::unhandled_exception( const exception& r )
|
||||
|
|
@ -152,15 +42,16 @@ namespace fc
|
|||
}
|
||||
unhandled_exception::unhandled_exception( log_messages m )
|
||||
:exception()
|
||||
{ my->_elog = fc::move(m);
|
||||
my->_ecode = detail::unhandled_exception_code;
|
||||
}
|
||||
{ my->_elog = fc::move(m); }
|
||||
|
||||
std::exception_ptr unhandled_exception::get_inner_exception()const { return _inner; }
|
||||
|
||||
NO_RETURN void unhandled_exception::dynamic_rethrow_exception()const
|
||||
{
|
||||
if( !(_inner == std::exception_ptr()) ) std::rethrow_exception( _inner );
|
||||
else { fc::exception::dynamic_rethrow_exception(); }
|
||||
}
|
||||
|
||||
std::shared_ptr<exception> unhandled_exception::dynamic_copy_exception()const
|
||||
{
|
||||
auto e = std::make_shared<unhandled_exception>( *this );
|
||||
|
|
@ -168,69 +59,64 @@ namespace fc
|
|||
return e;
|
||||
}
|
||||
|
||||
#define FC_EXCEPTION_IMPL( TYPE ) \
|
||||
TYPE::TYPE( log_message&& m ) \
|
||||
:exception( fc::move(m) ) { my->_ecode = detail::TYPE ##_code; } \
|
||||
TYPE::TYPE(){ my->_ecode = detail::TYPE ##_code; } \
|
||||
TYPE::TYPE(const TYPE& t):exception(t){} \
|
||||
TYPE::TYPE( log_messages m ) \
|
||||
:exception() { my->_elog = fc::move(m); my->_ecode = detail::TYPE ##_code; }
|
||||
|
||||
FC_EXCEPTION_IMPL(timeout_exception)
|
||||
FC_EXCEPTION_IMPL(file_not_found_exception)
|
||||
FC_EXCEPTION_IMPL(parse_error_exception)
|
||||
FC_EXCEPTION_IMPL(invalid_arg_exception)
|
||||
FC_EXCEPTION_IMPL(key_not_found_exception)
|
||||
FC_EXCEPTION_IMPL(bad_cast_exception)
|
||||
FC_EXCEPTION_IMPL(out_of_range_exception)
|
||||
FC_EXCEPTION_IMPL(invalid_operation_exception);
|
||||
FC_EXCEPTION_IMPL(canceled_exception)
|
||||
FC_EXCEPTION_IMPL(assert_exception)
|
||||
FC_EXCEPTION_IMPL(eof_exception)
|
||||
FC_EXCEPTION_IMPL(db_in_use_exception)
|
||||
|
||||
|
||||
|
||||
exception::exception()
|
||||
exception::exception( int64_t code,
|
||||
const std::string& name_value,
|
||||
const std::string& what_value )
|
||||
:my( new detail::exception_impl() )
|
||||
{
|
||||
my->_ecode = detail::unspecified_exception_code;
|
||||
my->_code = code;
|
||||
my->_what = what_value;
|
||||
my->_name = name_value;
|
||||
}
|
||||
|
||||
exception::exception( log_message&& msg)
|
||||
exception::exception( log_message&& msg,
|
||||
int64_t code,
|
||||
const std::string& name_value,
|
||||
const std::string& what_value )
|
||||
:my( new detail::exception_impl() )
|
||||
{
|
||||
my->_ecode = detail::unspecified_exception_code;
|
||||
my->_code = code;
|
||||
my->_what = what_value;
|
||||
my->_name = name_value;
|
||||
my->_elog.push_back( fc::move( msg ) );
|
||||
}
|
||||
exception::exception( const exception& c )
|
||||
:my( new detail::exception_impl(*c.my) )
|
||||
{
|
||||
}
|
||||
{ }
|
||||
exception::exception( exception&& c )
|
||||
:my( fc::move(c.my) ){}
|
||||
|
||||
exception::~exception(){}
|
||||
const char* exception::name()const throw() { return my->_name.c_str(); }
|
||||
const char* exception::what()const throw() { return my->_what.c_str(); }
|
||||
int64_t exception::code()const throw() { return my->_code; }
|
||||
|
||||
exception::~exception(){}
|
||||
|
||||
void to_variant( const exception& e, variant& v )
|
||||
{
|
||||
v = mutable_variant_object( "stack", e.my->_elog )
|
||||
( "type", e.my->_ecode)
|
||||
( "props", e.my->_props );
|
||||
v = mutable_variant_object( "code", e.code() )
|
||||
( "name", e.name() )
|
||||
( "message", e.what() )
|
||||
( "stack", e.get_log() );
|
||||
|
||||
}
|
||||
void from_variant( const variant& v, exception& ll )
|
||||
{
|
||||
auto obj = v.get_object();
|
||||
ll.my->_elog = obj["stack"].as<log_messages>();
|
||||
ll.my->_ecode = obj["type"].as<detail::exception_code>();
|
||||
ll.my->_props = obj["props"];
|
||||
if( obj.contains( "stack" ) )
|
||||
ll.my->_elog = obj["stack"].as<log_messages>();
|
||||
if( obj.contains( "code" ) )
|
||||
ll.my->_code = obj["code"].as_int64();
|
||||
if( obj.contains( "name" ) )
|
||||
ll.my->_name = obj["name"].as_string();
|
||||
if( obj.contains( "message" ) )
|
||||
ll.my->_what = obj["message"].as_string();
|
||||
}
|
||||
|
||||
const log_messages& exception::get_log()const { return my->_elog; }
|
||||
void exception::append_log( log_message m )
|
||||
void exception::append_log( log_message m )
|
||||
{
|
||||
my->_elog.push_back( fc::move(m) );
|
||||
my->_elog.emplace_back( fc::move(m) );
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -241,7 +127,7 @@ namespace fc
|
|||
string exception::to_detail_string( log_level ll )const
|
||||
{
|
||||
fc::stringstream ss;
|
||||
ss << variant(my->_ecode).as_string() <<"\n";
|
||||
ss << variant(my->_code).as_string() <<"\n";
|
||||
for( auto itr = my->_elog.begin(); itr != my->_elog.end(); )
|
||||
{
|
||||
ss << itr->get_message() <<"\n"; //fc::format_string( itr->get_format(), itr->get_data() ) <<"\n";
|
||||
|
|
@ -259,7 +145,7 @@ namespace fc
|
|||
string exception::to_string( log_level ll )const
|
||||
{
|
||||
fc::stringstream ss;
|
||||
ss << what() << "(" << variant(my->_ecode).as_string() <<")\n";
|
||||
ss << what() << "(" << variant(my->_code).as_string() <<")\n";
|
||||
for( auto itr = my->_elog.begin(); itr != my->_elog.end(); ++itr )
|
||||
{
|
||||
ss << fc::format_string( itr->get_format(), itr->get_data() ) <<"\n";
|
||||
|
|
@ -268,6 +154,13 @@ namespace fc
|
|||
return ss.str();
|
||||
}
|
||||
|
||||
void NO_RETURN exception_factory::rethrow( const exception& e )const
|
||||
{
|
||||
auto itr = _registered_exceptions.find( e.code() );
|
||||
if( itr != _registered_exceptions.end() )
|
||||
itr->second->rethrow( e );
|
||||
throw e;
|
||||
}
|
||||
/**
|
||||
* Rethrows the exception restoring the proper type based upon
|
||||
* the error code. This is used to propagate exception types
|
||||
|
|
@ -275,89 +168,30 @@ namespace fc
|
|||
*/
|
||||
NO_RETURN void exception::dynamic_rethrow_exception()const
|
||||
{
|
||||
switch( my->_ecode )
|
||||
{
|
||||
case detail::unhandled_exception_code:
|
||||
throw unhandled_exception( my->_elog );
|
||||
case detail::timeout_exception_code:
|
||||
throw timeout_exception( my->_elog );
|
||||
case detail::key_not_found_exception_code:
|
||||
throw key_not_found_exception( my->_elog );
|
||||
case detail::bad_cast_exception_code:
|
||||
throw bad_cast_exception( my->_elog );
|
||||
case detail::parse_error_exception_code:
|
||||
throw parse_error_exception( my->_elog );
|
||||
case detail::canceled_exception_code:
|
||||
throw canceled_exception( my->_elog);
|
||||
case detail::assert_exception_code:
|
||||
throw assert_exception( my->_elog );
|
||||
case detail::file_not_found_exception_code:
|
||||
throw file_not_found_exception( my->_elog );
|
||||
case detail::invalid_arg_exception_code:
|
||||
throw invalid_arg_exception( my->_elog );
|
||||
case detail::out_of_range_exception_code:
|
||||
throw out_of_range_exception( my->_elog );
|
||||
case detail::eof_exception_code:
|
||||
throw eof_exception( my->_elog );
|
||||
case detail::db_in_use_exception_code:
|
||||
throw db_in_use_exception( my->_elog );
|
||||
case detail::invalid_operation_exception_code:
|
||||
throw invalid_operation_exception( my->_elog );
|
||||
case detail::std_exception_code:
|
||||
throw std_exception( *this );
|
||||
case detail::unspecified_exception_code:
|
||||
default:
|
||||
throw fc::exception(*this);
|
||||
}
|
||||
exception_factory::instance().rethrow( *this );
|
||||
}
|
||||
|
||||
exception_ptr exception::dynamic_copy_exception()const
|
||||
{
|
||||
switch( my->_ecode )
|
||||
{
|
||||
case detail::unhandled_exception_code:
|
||||
return std::make_shared<unhandled_exception>( my->_elog );
|
||||
case detail::timeout_exception_code:
|
||||
return std::make_shared<timeout_exception>( my->_elog );
|
||||
case detail::key_not_found_exception_code:
|
||||
return std::make_shared<key_not_found_exception>( my->_elog );
|
||||
case detail::bad_cast_exception_code:
|
||||
return std::make_shared<bad_cast_exception>( my->_elog );
|
||||
case detail::parse_error_exception_code:
|
||||
return std::make_shared<parse_error_exception>( my->_elog );
|
||||
case detail::canceled_exception_code:
|
||||
return std::make_shared<canceled_exception>( my->_elog);
|
||||
case detail::assert_exception_code:
|
||||
return std::make_shared<assert_exception>( my->_elog );
|
||||
case detail::file_not_found_exception_code:
|
||||
return std::make_shared<file_not_found_exception>( my->_elog );
|
||||
case detail::invalid_arg_exception_code:
|
||||
return std::make_shared<invalid_arg_exception>( my->_elog );
|
||||
case detail::out_of_range_exception_code:
|
||||
return std::make_shared<out_of_range_exception>( my->_elog );
|
||||
case detail::eof_exception_code:
|
||||
return std::make_shared<eof_exception>( my->_elog );
|
||||
case detail::db_in_use_exception_code:
|
||||
return std::make_shared<db_in_use_exception>( my->_elog );
|
||||
case detail::invalid_operation_exception_code:
|
||||
return std::make_shared<invalid_operation_exception>( my->_elog );
|
||||
case detail::std_exception_code:
|
||||
return std::make_shared<std_exception>( *this );
|
||||
case detail::unspecified_exception_code:
|
||||
default:
|
||||
return std::make_shared<exception>(*this);
|
||||
}
|
||||
return std::make_shared<exception>(*this);
|
||||
}
|
||||
|
||||
fc::string except_str()
|
||||
{
|
||||
return boost::current_exception_diagnostic_information();
|
||||
}
|
||||
|
||||
void throw_bad_enum_cast( int64_t i, const char* e )
|
||||
{
|
||||
FC_THROW_EXCEPTION( bad_cast_exception, "invalid index '${key}' in enum '${enum}'", ("key",i)("enum",e) );
|
||||
FC_THROW_EXCEPTION( bad_cast_exception,
|
||||
"invalid index '${key}' in enum '${enum}'",
|
||||
("key",i)("enum",e) );
|
||||
}
|
||||
void throw_bad_enum_cast( const char* k, const char* e )
|
||||
{
|
||||
FC_THROW_EXCEPTION( bad_cast_exception, "invalid name '${key}' in enum '${enum}'", ("key",k)("enum",e) );
|
||||
FC_THROW_EXCEPTION( bad_cast_exception,
|
||||
"invalid name '${key}' in enum '${enum}'",
|
||||
("key",k)("enum",e) );
|
||||
}
|
||||
|
||||
} // fc
|
||||
|
|
|
|||
Loading…
Reference in a new issue