588 lines
17 KiB
C++
588 lines
17 KiB
C++
//Copyright (c) 2006-2009 Emil Dotchevski and Reverge Studios, Inc.
|
|
//Copyright (c) 2019 Dario Menendez, Banco Santander
|
|
|
|
//Distributed under the Boost Software License, Version 1.0. (See accompanying
|
|
//file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
|
|
|
#ifndef BOOST_EXCEPTION_618474C2DE1511DEB74A388C56D89593
|
|
#define BOOST_EXCEPTION_618474C2DE1511DEB74A388C56D89593
|
|
|
|
#include <boost/config.hpp>
|
|
#include <boost/exception/exception.hpp>
|
|
#include <boost/exception/info.hpp>
|
|
#include <boost/exception/diagnostic_information.hpp>
|
|
#ifndef BOOST_NO_EXCEPTIONS
|
|
# include <boost/exception/detail/clone_current_exception.hpp>
|
|
#endif
|
|
#include <boost/exception/detail/type_info.hpp>
|
|
#ifndef BOOST_NO_RTTI
|
|
#include <boost/core/demangle.hpp>
|
|
#endif
|
|
#include <boost/shared_ptr.hpp>
|
|
#include <boost/make_shared.hpp>
|
|
#include <stdexcept>
|
|
#include <new>
|
|
#include <ios>
|
|
#include <stdlib.h>
|
|
|
|
#ifndef BOOST_EXCEPTION_ENABLE_WARNINGS
|
|
#if __GNUC__*100+__GNUC_MINOR__>301
|
|
#pragma GCC system_header
|
|
#endif
|
|
#ifdef __clang__
|
|
#pragma clang system_header
|
|
#endif
|
|
#ifdef _MSC_VER
|
|
#pragma warning(push,1)
|
|
#endif
|
|
#endif
|
|
|
|
namespace
|
|
boost
|
|
{
|
|
class exception_ptr;
|
|
namespace exception_detail { void rethrow_exception_( exception_ptr const & ); }
|
|
|
|
class
|
|
exception_ptr
|
|
{
|
|
typedef boost::shared_ptr<exception_detail::clone_base const> impl;
|
|
impl ptr_;
|
|
friend void exception_detail::rethrow_exception_( exception_ptr const & );
|
|
typedef exception_detail::clone_base const * (impl::*unspecified_bool_type)() const;
|
|
public:
|
|
exception_ptr()
|
|
{
|
|
}
|
|
explicit
|
|
exception_ptr( impl const & ptr ):
|
|
ptr_(ptr)
|
|
{
|
|
}
|
|
bool
|
|
operator==( exception_ptr const & other ) const
|
|
{
|
|
return ptr_==other.ptr_;
|
|
}
|
|
bool
|
|
operator!=( exception_ptr const & other ) const
|
|
{
|
|
return ptr_!=other.ptr_;
|
|
}
|
|
operator unspecified_bool_type() const
|
|
{
|
|
return ptr_?&impl::get:0;
|
|
}
|
|
};
|
|
|
|
template <class E>
|
|
inline
|
|
exception_ptr
|
|
copy_exception( E const & e )
|
|
{
|
|
E cp = e;
|
|
exception_detail::copy_boost_exception(&cp, &e);
|
|
return exception_ptr(boost::make_shared<wrapexcept<E> >(cp));
|
|
}
|
|
|
|
template <class T>
|
|
inline
|
|
exception_ptr
|
|
make_exception_ptr( T const & e )
|
|
{
|
|
return boost::copy_exception(e);
|
|
}
|
|
|
|
#ifndef BOOST_NO_RTTI
|
|
typedef error_info<struct tag_original_exception_type,std::type_info const *> original_exception_type;
|
|
|
|
inline
|
|
std::string
|
|
to_string( original_exception_type const & x )
|
|
{
|
|
return core::demangle(x.value()->name());
|
|
}
|
|
#endif
|
|
|
|
#ifndef BOOST_NO_EXCEPTIONS
|
|
namespace
|
|
exception_detail
|
|
{
|
|
struct
|
|
bad_alloc_:
|
|
boost::exception,
|
|
std::bad_alloc
|
|
{
|
|
~bad_alloc_() BOOST_NOEXCEPT_OR_NOTHROW { }
|
|
};
|
|
|
|
struct
|
|
bad_exception_:
|
|
boost::exception,
|
|
std::bad_exception
|
|
{
|
|
~bad_exception_() BOOST_NOEXCEPT_OR_NOTHROW { }
|
|
};
|
|
|
|
template <class Exception>
|
|
exception_ptr
|
|
get_static_exception_object()
|
|
{
|
|
Exception ba;
|
|
exception_detail::clone_impl<Exception> c(ba);
|
|
#ifndef BOOST_EXCEPTION_DISABLE
|
|
c <<
|
|
throw_function(BOOST_CURRENT_FUNCTION) <<
|
|
throw_file(__FILE__) <<
|
|
throw_line(__LINE__);
|
|
#endif
|
|
static exception_ptr ep(shared_ptr<exception_detail::clone_base const>(new exception_detail::clone_impl<Exception>(c)));
|
|
return ep;
|
|
}
|
|
|
|
template <class Exception>
|
|
struct
|
|
exception_ptr_static_exception_object
|
|
{
|
|
static exception_ptr const e;
|
|
};
|
|
|
|
template <class Exception>
|
|
exception_ptr const
|
|
exception_ptr_static_exception_object<Exception>::
|
|
e = get_static_exception_object<Exception>();
|
|
}
|
|
|
|
#if defined(__GNUC__)
|
|
# if (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4)
|
|
# pragma GCC visibility push (default)
|
|
# endif
|
|
#endif
|
|
class
|
|
unknown_exception:
|
|
public boost::exception,
|
|
public std::exception
|
|
{
|
|
public:
|
|
|
|
unknown_exception()
|
|
{
|
|
}
|
|
|
|
explicit
|
|
unknown_exception( std::exception const & e )
|
|
{
|
|
add_original_type(e);
|
|
}
|
|
|
|
explicit
|
|
unknown_exception( boost::exception const & e ):
|
|
boost::exception(e)
|
|
{
|
|
add_original_type(e);
|
|
}
|
|
|
|
~unknown_exception() BOOST_NOEXCEPT_OR_NOTHROW
|
|
{
|
|
}
|
|
|
|
private:
|
|
|
|
template <class E>
|
|
void
|
|
add_original_type( E const & e )
|
|
{
|
|
#ifndef BOOST_NO_RTTI
|
|
(*this) << original_exception_type(&typeid(e));
|
|
#endif
|
|
}
|
|
};
|
|
#if defined(__GNUC__)
|
|
# if (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4)
|
|
# pragma GCC visibility pop
|
|
# endif
|
|
#endif
|
|
|
|
namespace
|
|
exception_detail
|
|
{
|
|
template <class T>
|
|
class
|
|
current_exception_std_exception_wrapper:
|
|
public T,
|
|
public boost::exception
|
|
{
|
|
public:
|
|
|
|
explicit
|
|
current_exception_std_exception_wrapper( T const & e1 ):
|
|
T(e1)
|
|
{
|
|
add_original_type(e1);
|
|
}
|
|
|
|
current_exception_std_exception_wrapper( T const & e1, boost::exception const & e2 ):
|
|
T(e1),
|
|
boost::exception(e2)
|
|
{
|
|
add_original_type(e1);
|
|
}
|
|
|
|
~current_exception_std_exception_wrapper() BOOST_NOEXCEPT_OR_NOTHROW
|
|
{
|
|
}
|
|
|
|
private:
|
|
|
|
template <class E>
|
|
void
|
|
add_original_type( E const & e )
|
|
{
|
|
#ifndef BOOST_NO_RTTI
|
|
(*this) << original_exception_type(&typeid(e));
|
|
#endif
|
|
}
|
|
};
|
|
|
|
#ifdef BOOST_NO_RTTI
|
|
template <class T>
|
|
boost::exception const *
|
|
get_boost_exception( T const * )
|
|
{
|
|
try
|
|
{
|
|
throw;
|
|
}
|
|
catch(
|
|
boost::exception & x )
|
|
{
|
|
return &x;
|
|
}
|
|
catch(...)
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
#else
|
|
template <class T>
|
|
boost::exception const *
|
|
get_boost_exception( T const * x )
|
|
{
|
|
return dynamic_cast<boost::exception const *>(x);
|
|
}
|
|
#endif
|
|
|
|
template <class T>
|
|
inline
|
|
exception_ptr
|
|
current_exception_std_exception( T const & e1 )
|
|
{
|
|
if( boost::exception const * e2 = get_boost_exception(&e1) )
|
|
return boost::copy_exception(current_exception_std_exception_wrapper<T>(e1,*e2));
|
|
else
|
|
return boost::copy_exception(current_exception_std_exception_wrapper<T>(e1));
|
|
}
|
|
|
|
inline
|
|
exception_ptr
|
|
current_exception_unknown_exception()
|
|
{
|
|
return boost::copy_exception(unknown_exception());
|
|
}
|
|
|
|
inline
|
|
exception_ptr
|
|
current_exception_unknown_boost_exception( boost::exception const & e )
|
|
{
|
|
return boost::copy_exception(unknown_exception(e));
|
|
}
|
|
|
|
inline
|
|
exception_ptr
|
|
current_exception_unknown_std_exception( std::exception const & e )
|
|
{
|
|
if( boost::exception const * be = get_boost_exception(&e) )
|
|
return current_exception_unknown_boost_exception(*be);
|
|
else
|
|
return boost::copy_exception(unknown_exception(e));
|
|
}
|
|
|
|
#ifndef BOOST_NO_CXX11_HDR_EXCEPTION
|
|
struct
|
|
std_exception_ptr_wrapper
|
|
{
|
|
std::exception_ptr p;
|
|
explicit std_exception_ptr_wrapper( std::exception_ptr const & ptr ) BOOST_NOEXCEPT:
|
|
p(ptr)
|
|
{
|
|
}
|
|
#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
|
|
explicit std_exception_ptr_wrapper( std::exception_ptr && ptr ) BOOST_NOEXCEPT:
|
|
p(static_cast<std::exception_ptr &&>(ptr))
|
|
{
|
|
}
|
|
#endif
|
|
};
|
|
#endif
|
|
|
|
inline
|
|
exception_ptr
|
|
current_exception_impl()
|
|
{
|
|
exception_detail::clone_base const * e=0;
|
|
switch(
|
|
exception_detail::clone_current_exception(e) )
|
|
{
|
|
case exception_detail::clone_current_exception_result::
|
|
success:
|
|
{
|
|
BOOST_ASSERT(e!=0);
|
|
return exception_ptr(shared_ptr<exception_detail::clone_base const>(e));
|
|
}
|
|
case exception_detail::clone_current_exception_result::
|
|
bad_alloc:
|
|
{
|
|
BOOST_ASSERT(!e);
|
|
return exception_detail::exception_ptr_static_exception_object<bad_alloc_>::e;
|
|
}
|
|
case exception_detail::clone_current_exception_result::
|
|
bad_exception:
|
|
{
|
|
BOOST_ASSERT(!e);
|
|
return exception_detail::exception_ptr_static_exception_object<bad_exception_>::e;
|
|
}
|
|
default:
|
|
BOOST_ASSERT(0);
|
|
case exception_detail::clone_current_exception_result::
|
|
not_supported:
|
|
{
|
|
BOOST_ASSERT(!e);
|
|
try
|
|
{
|
|
throw;
|
|
}
|
|
catch(
|
|
exception_detail::clone_base & e )
|
|
{
|
|
return exception_ptr(shared_ptr<exception_detail::clone_base const>(e.clone()));
|
|
}
|
|
catch(
|
|
std::domain_error & e )
|
|
{
|
|
return exception_detail::current_exception_std_exception(e);
|
|
}
|
|
catch(
|
|
std::invalid_argument & e )
|
|
{
|
|
return exception_detail::current_exception_std_exception(e);
|
|
}
|
|
catch(
|
|
std::length_error & e )
|
|
{
|
|
return exception_detail::current_exception_std_exception(e);
|
|
}
|
|
catch(
|
|
std::out_of_range & e )
|
|
{
|
|
return exception_detail::current_exception_std_exception(e);
|
|
}
|
|
catch(
|
|
std::logic_error & e )
|
|
{
|
|
return exception_detail::current_exception_std_exception(e);
|
|
}
|
|
catch(
|
|
std::range_error & e )
|
|
{
|
|
return exception_detail::current_exception_std_exception(e);
|
|
}
|
|
catch(
|
|
std::overflow_error & e )
|
|
{
|
|
return exception_detail::current_exception_std_exception(e);
|
|
}
|
|
catch(
|
|
std::underflow_error & e )
|
|
{
|
|
return exception_detail::current_exception_std_exception(e);
|
|
}
|
|
catch(
|
|
std::ios_base::failure & e )
|
|
{
|
|
return exception_detail::current_exception_std_exception(e);
|
|
}
|
|
catch(
|
|
std::runtime_error & e )
|
|
{
|
|
return exception_detail::current_exception_std_exception(e);
|
|
}
|
|
catch(
|
|
std::bad_alloc & e )
|
|
{
|
|
return exception_detail::current_exception_std_exception(e);
|
|
}
|
|
#ifndef BOOST_NO_TYPEID
|
|
catch(
|
|
std::bad_cast & e )
|
|
{
|
|
return exception_detail::current_exception_std_exception(e);
|
|
}
|
|
catch(
|
|
std::bad_typeid & e )
|
|
{
|
|
return exception_detail::current_exception_std_exception(e);
|
|
}
|
|
#endif
|
|
catch(
|
|
std::bad_exception & e )
|
|
{
|
|
return exception_detail::current_exception_std_exception(e);
|
|
}
|
|
#ifdef BOOST_NO_CXX11_HDR_EXCEPTION
|
|
// this case can be handled losslesly with std::current_exception() (see below)
|
|
catch(
|
|
std::exception & e )
|
|
{
|
|
return exception_detail::current_exception_unknown_std_exception(e);
|
|
}
|
|
#endif
|
|
catch(
|
|
boost::exception & e )
|
|
{
|
|
return exception_detail::current_exception_unknown_boost_exception(e);
|
|
}
|
|
catch(
|
|
... )
|
|
{
|
|
#ifndef BOOST_NO_CXX11_HDR_EXCEPTION
|
|
try
|
|
{
|
|
// wrap the std::exception_ptr in a clone-enabled Boost.Exception object
|
|
exception_detail::clone_base const & base =
|
|
boost::enable_current_exception(std_exception_ptr_wrapper(std::current_exception()));
|
|
return exception_ptr(shared_ptr<exception_detail::clone_base const>(base.clone()));
|
|
}
|
|
catch(
|
|
...)
|
|
{
|
|
return exception_detail::current_exception_unknown_exception();
|
|
}
|
|
#else
|
|
return exception_detail::current_exception_unknown_exception();
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
inline
|
|
exception_ptr
|
|
current_exception()
|
|
{
|
|
exception_ptr ret;
|
|
try
|
|
{
|
|
ret=exception_detail::current_exception_impl();
|
|
}
|
|
catch(
|
|
std::bad_alloc & )
|
|
{
|
|
ret=exception_detail::exception_ptr_static_exception_object<exception_detail::bad_alloc_>::e;
|
|
}
|
|
catch(
|
|
... )
|
|
{
|
|
ret=exception_detail::exception_ptr_static_exception_object<exception_detail::bad_exception_>::e;
|
|
}
|
|
BOOST_ASSERT(ret);
|
|
return ret;
|
|
}
|
|
#endif // ifndef BOOST_NO_EXCEPTIONS
|
|
|
|
namespace
|
|
exception_detail
|
|
{
|
|
inline
|
|
void
|
|
rethrow_exception_( exception_ptr const & p )
|
|
{
|
|
BOOST_ASSERT(p);
|
|
#if defined( BOOST_NO_CXX11_HDR_EXCEPTION ) || defined( BOOST_NO_EXCEPTIONS )
|
|
p.ptr_->rethrow();
|
|
#else
|
|
try
|
|
{
|
|
p.ptr_->rethrow();
|
|
}
|
|
catch(
|
|
std_exception_ptr_wrapper const & wrp)
|
|
{
|
|
// if an std::exception_ptr was wrapped above then rethrow it
|
|
std::rethrow_exception(wrp.p);
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
|
|
BOOST_NORETURN
|
|
inline
|
|
void
|
|
rethrow_exception( exception_ptr const & p )
|
|
{
|
|
exception_detail::rethrow_exception_(p);
|
|
BOOST_ASSERT(0);
|
|
#if defined(UNDER_CE)
|
|
// some CE platforms don't define ::abort()
|
|
exit(-1);
|
|
#else
|
|
abort();
|
|
#endif
|
|
}
|
|
|
|
inline
|
|
std::string
|
|
diagnostic_information( exception_ptr const & p, bool verbose=true )
|
|
{
|
|
if( p )
|
|
#ifdef BOOST_NO_EXCEPTIONS
|
|
return "<unavailable> due to BOOST_NO_EXCEPTIONS";
|
|
#else
|
|
try
|
|
{
|
|
rethrow_exception(p);
|
|
}
|
|
catch(
|
|
... )
|
|
{
|
|
return current_exception_diagnostic_information(verbose);
|
|
}
|
|
#endif
|
|
return "<empty>";
|
|
}
|
|
|
|
inline
|
|
std::string
|
|
to_string( exception_ptr const & p )
|
|
{
|
|
std::string s='\n'+diagnostic_information(p);
|
|
std::string padding(" ");
|
|
std::string r;
|
|
bool f=false;
|
|
for( std::string::const_iterator i=s.begin(),e=s.end(); i!=e; ++i )
|
|
{
|
|
if( f )
|
|
r+=padding;
|
|
char c=*i;
|
|
r+=c;
|
|
f=(c=='\n');
|
|
}
|
|
return r;
|
|
}
|
|
}
|
|
|
|
#if defined(_MSC_VER) && !defined(BOOST_EXCEPTION_ENABLE_WARNINGS)
|
|
#pragma warning(pop)
|
|
#endif
|
|
#endif
|