X-Git-Url: http://plrg.eecs.uci.edu/git/?a=blobdiff_plain;f=folly%2FExceptionWrapper.h;h=bd5bc11972c5555ace1a269d767e8e1459c0a470;hb=0659842527913025d998860811fe135cc6170044;hp=94f6e82825fb927ba8eb9ffb70eb7035c80009d3;hpb=a62c9841120eb374f8b933d31444a590acee6123;p=folly.git diff --git a/folly/ExceptionWrapper.h b/folly/ExceptionWrapper.h index 94f6e828..bd5bc119 100644 --- a/folly/ExceptionWrapper.h +++ b/folly/ExceptionWrapper.h @@ -1,5 +1,5 @@ /* - * Copyright 2016 Facebook, Inc. + * Copyright 2017 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,11 +16,16 @@ #pragma once -#include #include #include +#include +#include +#include +#include + #include -#include +#include +#include namespace folly { @@ -58,8 +63,9 @@ namespace folly { * can test or extract a pointer to a specific exception type with very little * overhead. * - * Example usage: - * + * \par Example usage: + * \par + * \code * exception_wrapper globalExceptionWrapper; * * // Thread1 @@ -97,25 +103,24 @@ namespace folly { * }) || * LOG(FATAL) << "Unrecognized exception"; * } + * \endcode * */ class exception_wrapper { - protected: - template - struct optimize; + private: + template + using is_exception_ = std::is_base_of; public: exception_wrapper() = default; - // Implicitly construct an exception_wrapper from a qualifying exception. - // See the optimize struct for details. - template ::type>::value> - ::type> + template < + typename Ex, + typename DEx = _t>, + typename = _t::value>>, + typename = decltype(DEx(std::forward(std::declval())))> /* implicit */ exception_wrapper(Ex&& exn) { - typedef typename std::decay::type DEx; - item_ = std::make_shared(std::forward(exn)); - throwfn_ = folly::detail::Thrower::doThrow; + assign_sptr(std::forward(exn)); } // The following two constructors are meant to emulate the behavior of @@ -150,14 +155,7 @@ class exception_wrapper { // If the exception_wrapper does not contain an exception, std::terminate() // is invoked to assure the [[noreturn]] behaviour. - [[noreturn]] void throwException() const { - if (throwfn_) { - throwfn_(item_.get()); - } else if (eptr_) { - std::rethrow_exception(eptr_); - } - std::terminate(); - } + [[noreturn]] void throwException() const; explicit operator bool() const { return item_ || eptr_; @@ -187,95 +185,41 @@ class exception_wrapper { std::exception* getCopied() { return item_.get(); } const std::exception* getCopied() const { return item_.get(); } - fbstring what() const { - if (item_) { - return exceptionStr(*item_); - } else if (eptr_) { - return estr_; - } else { - return fbstring(); - } - } - - fbstring class_name() const { - if (item_) { - auto& i = *item_; - return demangle(typeid(i)); - } else if (eptr_) { - return ename_; - } else { - return fbstring(); - } - } + fbstring what() const; + fbstring class_name() const; template bool is_compatible_with() const { - if (item_) { - return dynamic_cast(item_.get()); - } else if (eptr_) { - try { - std::rethrow_exception(eptr_); - } catch (typename std::decay::type&) { - return true; - } catch (...) { - // fall through - } - } - return false; + return with_exception([](const Ex&) {}); } template bool with_exception(F&& f) { - using arg_type = typename functor_traits::arg_type_decayed; + using arg_type = _t::arg_type>>; return with_exception(std::forward(f)); } template bool with_exception(F&& f) const { - using arg_type = typename functor_traits::arg_type_decayed; - return with_exception(std::forward(f)); + using arg_type = _t::arg_type>>; + return with_exception(std::forward(f)); } // If this exception wrapper wraps an exception of type Ex, with_exception // will call f with the wrapped exception as an argument and return true, and // will otherwise return false. template - typename std::enable_if< - std::is_base_of::type>::value, - bool>::type - with_exception(F f) { - return with_exception1::type>(f, this); + bool with_exception(F f) { + return with_exception1<_t>>(std::forward(f), this); } // Const overload template - typename std::enable_if< - std::is_base_of::type>::value, - bool>::type - with_exception(F f) const { - return with_exception1::type>(f, this); + bool with_exception(F f) const { + return with_exception1<_t>>(std::forward(f), this); } - // Overload for non-exceptions. Always rethrows. - template - typename std::enable_if< - !std::is_base_of::type>::value, - bool>::type - with_exception(F f) const { - try { - if (*this) { - throwException(); - } - } catch (typename std::decay::type& e) { - f(e); - return true; - } catch (...) { - // fall through - } - return false; - } - - std::exception_ptr getExceptionPtr() const { + std::exception_ptr to_exception_ptr() const { if (eptr_) { return eptr_; } @@ -290,20 +234,27 @@ class exception_wrapper { return std::exception_ptr(); } -protected: + private: + template + void assign_sptr(Args&&... args) { + this->item_ = std::make_shared(std::forward(args)...); + this->throwfn_ = Thrower::doThrow; + } + template - struct optimize { - static const bool value = - std::is_base_of::value && - std::is_copy_assignable::value && - !std::is_abstract::value; - }; + _t::value>> assign_eptr( + std::exception_ptr eptr, + Ex& e) { + this->eptr_ = eptr; + this->eobj_ = &const_cast<_t>&>(e); + } template - void assign_eptr(std::exception_ptr eptr, Ex& e) { + _t::value>> assign_eptr( + std::exception_ptr eptr, + Ex& e) { this->eptr_ = eptr; - this->estr_ = exceptionStr(e).toStdString(); - this->ename_ = demangle(typeid(e)).toStdString(); + this->etype_ = &typeid(e); } void assign_eptr(std::exception_ptr eptr) { @@ -314,19 +265,19 @@ protected: // store a copy of the concrete type, and a helper function so we // can rethrow it. std::shared_ptr item_; - void (*throwfn_)(std::exception*){nullptr}; + void (*throwfn_)(std::exception&){nullptr}; // Fallback case: store the library wrapper, which is less efficient // but gets the job done. Also store exceptionPtr() the name of the // exception type, so we can at least get those back out without // having to rethrow. std::exception_ptr eptr_; - std::string estr_; - std::string ename_; + std::exception* eobj_{nullptr}; + const std::type_info* etype_{nullptr}; template friend exception_wrapper make_exception_wrapper(Args&&... args); -private: + private: template struct functor_traits { template @@ -335,26 +286,47 @@ private: struct impl { using arg_type = A; }; template struct impl { using arg_type = A; }; - using functor_decayed = typename std::decay::type; - using functor_op = decltype(&functor_decayed::operator()); + using functor_op = decltype(&_t>::operator()); using arg_type = typename impl::arg_type; - using arg_type_decayed = typename std::decay::type; }; + template + class Thrower { + public: + static void doThrow(std::exception& obj) { + throw static_cast(obj); + } + }; + + template + static _t::value, T*>> + try_dynamic_cast_exception(F* from) { + return dynamic_cast(from); + } + template + static _t::value, T*>> + try_dynamic_cast_exception(F*) { + return nullptr; + } + // What makes this useful is that T can be exception_wrapper* or // const exception_wrapper*, and the compiler will use the // instantiation which works with F. template static bool with_exception1(F f, T* that) { - if (that->item_) { - if (auto ex = dynamic_cast(that->item_.get())) { + using CEx = _t::value, const Ex, Ex>>; + if (is_exception_::value && + (that->item_ || (that->eptr_ && that->eobj_))) { + auto raw = + that->item_ ? that->item_.get() : that->eptr_ ? that->eobj_ : nullptr; + if (auto ex = try_dynamic_cast_exception(raw)) { f(*ex); return true; } } else if (that->eptr_) { try { std::rethrow_exception(that->eptr_); - } catch (Ex& e) { + } catch (CEx& e) { f(e); return true; } catch (...) { @@ -365,18 +337,15 @@ private: } }; -template +template exception_wrapper make_exception_wrapper(Args&&... args) { exception_wrapper ew; - ew.item_ = std::make_shared(std::forward(args)...); - ew.throwfn_ = folly::detail::Thrower::doThrow; + ew.assign_sptr(std::forward(args)...); return ew; } -// For consistency with exceptionStr() functions in String.h -inline fbstring exceptionStr(const exception_wrapper& ew) { - return ew.what(); -} +// For consistency with exceptionStr() functions in ExceptionString.h +fbstring exceptionStr(const exception_wrapper& ew); /* * try_and_catch is a simple replacement for try {} catch(){} that allows you to @@ -418,59 +387,42 @@ inline fbstring exceptionStr(const exception_wrapper& ew) { * }); */ -template -class try_and_catch; - -template -class try_and_catch : - public try_and_catch { - public: - template - explicit try_and_catch(F&& fn) : Base() { - call_fn(fn); - } +namespace try_and_catch_detail { - protected: - typedef try_and_catch Base; +template +using is_wrap_ctor = std::is_constructible; - try_and_catch() : Base() {} +template +inline _t::value, exception_wrapper>> make( + Ex& ex) { + return exception_wrapper(std::current_exception(), ex); +} - template - typename std::enable_if::value>::type - assign_exception(Ex& e, std::exception_ptr eptr) { - exception_wrapper::assign_eptr(eptr, e); - } +template +inline _t::value, exception_wrapper>> make( + Ex& ex) { + return typeid(Ex&) == typeid(ex) + ? exception_wrapper(ex) + : exception_wrapper(std::current_exception(), ex); +} - template - typename std::enable_if::value>::type - assign_exception(Ex& e, std::exception_ptr /*eptr*/) { - this->item_ = std::make_shared(e); - this->throwfn_ = folly::detail::Thrower::doThrow; - } +template +inline exception_wrapper impl(F&& f) { + return (f(), exception_wrapper()); +} - template - void call_fn(F&& fn) { - try { - Base::call_fn(std::move(fn)); - } catch (LastException& e) { - if (typeid(e) == typeid(LastException&)) { - assign_exception(e, std::current_exception()); - } else { - exception_wrapper::assign_eptr(std::current_exception(), e); - } - } +template +inline exception_wrapper impl(F&& f) { + try { + return impl(std::forward(f)); + } catch (Ex& ex) { + return make(ex); } -}; - -template<> -class try_and_catch<> : public exception_wrapper { - public: - try_and_catch() = default; +} +} // try_and_catch_detail - protected: - template - void call_fn(F&& fn) { - fn(); - } -}; +template +exception_wrapper try_and_catch(F&& fn) { + return try_and_catch_detail::impl(std::forward(fn)); } +} // folly