Commit 98c2c6f1 authored by Yedidya Feldblum's avatar Yedidya Feldblum Committed by Facebook GitHub Bot

implement exception_wrapper::with_exception directly

Summary: Rather than implementing it via `handle`, which is complex. Works now that exact casting can always be done without `catch`.

Reviewed By: luciang

Differential Revision: D27987594

fbshipit-source-id: 9961b55089f58df1b06793390817e497c6da54ae
parent 5ec574fe
...@@ -94,6 +94,16 @@ struct exception_wrapper::arg_type_<Ret (*)(...) noexcept> { ...@@ -94,6 +94,16 @@ struct exception_wrapper::arg_type_<Ret (*)(...) noexcept> {
}; };
#endif #endif
struct exception_wrapper::with_exception_from_fn_ {
template <typename, typename Fn>
using apply = arg_type<Fn>;
};
struct exception_wrapper::with_exception_from_ex_ {
template <typename Ex, typename>
using apply = Ex;
};
template <class Ret, class... Args> template <class Ret, class... Args>
inline Ret exception_wrapper::noop_(Args...) { inline Ret exception_wrapper::noop_(Args...) {
return Ret(); return Ret();
...@@ -598,34 +608,14 @@ inline void exception_wrapper::handle_( ...@@ -598,34 +608,14 @@ inline void exception_wrapper::handle_(
} }
} }
namespace exception_wrapper_detail {
template <class Ex, class Fn>
struct catch_fn {
Fn fn_;
auto operator()(Ex& ex) { return fn_(ex); }
};
template <class Ex, class Fn>
inline catch_fn<Ex, Fn> catch_(Ex*, Fn fn) {
return {std::move(fn)};
}
template <class Fn>
inline Fn catch_(void const*, Fn fn) {
return fn;
}
} // namespace exception_wrapper_detail
template <class Ex, class This, class Fn> template <class Ex, class This, class Fn>
inline bool exception_wrapper::with_exception_(This& this_, Fn fn_) { inline bool exception_wrapper::with_exception_(This& this_, Fn fn_) {
if (!this_) { using from_fn = with_exception_from_fn_;
return false; using from_ex = with_exception_from_ex_;
} using from = conditional_t<std::is_void<Ex>::value, from_fn, from_ex>;
bool handled = true; using type = typename from::template apply<Ex, Fn>;
auto fn = exception_wrapper_detail::catch_( auto ptr = this_.template get_exception<remove_cvref_t<type>>();
static_cast<Ex*>(nullptr), std::move(fn_)); return ptr && (void(fn_(static_cast<type&>(*ptr))), true);
auto&& all = [&](...) { handled = false; };
handle_(IsStdException<arg_type<decltype(fn)>>{}, this_, fn, all);
return handled;
} }
template <class Ex, class Fn> template <class Ex, class Fn>
......
...@@ -173,6 +173,9 @@ class exception_wrapper final { ...@@ -173,6 +173,9 @@ class exception_wrapper final {
template <class Fn> template <class Fn>
using arg_type = _t<arg_type_<Fn>>; using arg_type = _t<arg_type_<Fn>>;
struct with_exception_from_fn_;
struct with_exception_from_ex_;
// exception_wrapper is implemented as a simple variant over four // exception_wrapper is implemented as a simple variant over four
// different representations: // different representations:
// 0. Empty, no exception. // 0. Empty, no exception.
...@@ -538,7 +541,7 @@ class exception_wrapper final { ...@@ -538,7 +541,7 @@ class exception_wrapper final {
//! \code //! \code
//! ew.with_exception<std::runtime_error>([](auto&& e) { /*...*/; }); //! ew.with_exception<std::runtime_error>([](auto&& e) { /*...*/; });
//! \endcode //! \endcode
//! \note The handler may or may not be invoked with an active exception. //! \note The handler is not invoked with an active exception.
//! **Do not try to rethrow the exception with `throw;` from within your //! **Do not try to rethrow the exception with `throw;` from within your
//! handler -- that is, a throw expression with no operand.** This may //! handler -- that is, a throw expression with no operand.** This may
//! cause your process to terminate. (It is perfectly ok to throw from //! cause your process to terminate. (It is perfectly ok to throw from
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment