Commit eaa278a5 authored by Yedidya Feldblum's avatar Yedidya Feldblum Committed by Facebook Github Bot

Keep the std::exception* or std::type_info* in folly::exception_wrapper

Summary:
[Folly] Keep the `std::exception*` or `std::type_info*` in `folly::exception_wrapper`.

In the case of construction with a `std::exception_ptr`. Instead of keeping a pair of `std::string`s, strictly losing information (not that we use any more information, but theoretically we could).

Of note:
* Shrinks the size of `folly::exception_wrapper`, in all cases, to 48 bytes. Down from 32 bytes + 2 S bytes on 64-bit architectures, where S is the size in bytes of `std::string`. In particular, `libstdc++`'s implementation is 32 bytes, while `libc++`'s and Folly's implementations are 24 bytes on 64-bit architectures, for total original sizes of 96 bytes or 80 bytes.
* Allows to avoid rethrowing in `with_exception` in the case of an instance constructed with an `std::exception_ptr` plus an `std::exception&`.

Reviewed By: ericniebler

Differential Revision: D4369935

fbshipit-source-id: 35155e0b271959a4878fe077fc911b17767a2358
parent dc938550
...@@ -36,8 +36,10 @@ fbstring exception_wrapper::class_name() const { ...@@ -36,8 +36,10 @@ fbstring exception_wrapper::class_name() const {
if (item_) { if (item_) {
auto& i = *item_; auto& i = *item_;
return demangle(typeid(i)); return demangle(typeid(i));
} else if (eptr_) { } else if (eptr_ && eobj_) {
return ename_; return demangle(typeid(*eobj_));
} else if (eptr_ && etype_) {
return demangle(*etype_);
} else { } else {
return fbstring(); return fbstring();
} }
...@@ -46,10 +48,12 @@ fbstring exception_wrapper::class_name() const { ...@@ -46,10 +48,12 @@ fbstring exception_wrapper::class_name() const {
fbstring exception_wrapper::what() const { fbstring exception_wrapper::what() const {
if (item_) { if (item_) {
return exceptionStr(*item_); return exceptionStr(*item_);
} else if (eptr_) { } else if (eptr_ && eobj_) {
return estr_; return class_name() + ": " + eobj_->what();
} else if (eptr_ && etype_) {
return class_name();
} else { } else {
return fbstring(); return class_name();
} }
} }
......
...@@ -108,6 +108,9 @@ namespace folly { ...@@ -108,6 +108,9 @@ namespace folly {
*/ */
class exception_wrapper { class exception_wrapper {
private: private:
template <typename T>
using is_exception_ = std::is_base_of<std::exception, T>;
template <typename Ex> template <typename Ex>
struct optimize; struct optimize;
...@@ -250,10 +253,19 @@ class exception_wrapper { ...@@ -250,10 +253,19 @@ class exception_wrapper {
} }
template <typename Ex> template <typename Ex>
void assign_eptr(std::exception_ptr eptr, Ex& e) { _t<std::enable_if<is_exception_<Ex>::value>> assign_eptr(
std::exception_ptr eptr,
Ex& e) {
this->eptr_ = eptr;
this->eobj_ = &const_cast<_t<std::remove_const<Ex>>&>(e);
}
template <typename Ex>
_t<std::enable_if<!is_exception_<Ex>::value>> assign_eptr(
std::exception_ptr eptr,
Ex& e) {
this->eptr_ = eptr; this->eptr_ = eptr;
this->estr_ = exceptionStr(e).toStdString(); this->etype_ = &typeid(e);
this->ename_ = demangle(typeid(e)).toStdString();
} }
void assign_eptr(std::exception_ptr eptr) { void assign_eptr(std::exception_ptr eptr) {
...@@ -270,8 +282,8 @@ class exception_wrapper { ...@@ -270,8 +282,8 @@ class exception_wrapper {
// exception type, so we can at least get those back out without // exception type, so we can at least get those back out without
// having to rethrow. // having to rethrow.
std::exception_ptr eptr_; std::exception_ptr eptr_;
std::string estr_; std::exception* eobj_{nullptr};
std::string ename_; const std::type_info* etype_{nullptr};
template <class T, class... Args> template <class T, class... Args>
friend exception_wrapper make_exception_wrapper(Args&&... args); friend exception_wrapper make_exception_wrapper(Args&&... args);
...@@ -297,9 +309,6 @@ class exception_wrapper { ...@@ -297,9 +309,6 @@ class exception_wrapper {
} }
}; };
template <typename T>
using is_exception_ = std::is_base_of<std::exception, T>;
template <typename T, typename F> template <typename T, typename F>
static _t<std::enable_if<is_exception_<T>::value, T*>> static _t<std::enable_if<is_exception_<T>::value, T*>>
try_dynamic_cast_exception(F* from) { try_dynamic_cast_exception(F* from) {
...@@ -317,8 +326,11 @@ class exception_wrapper { ...@@ -317,8 +326,11 @@ class exception_wrapper {
template <class Ex, class F, class T> template <class Ex, class F, class T>
static bool with_exception1(F f, T* that) { static bool with_exception1(F f, T* that) {
using CEx = _t<std::conditional<std::is_const<T>::value, const Ex, Ex>>; using CEx = _t<std::conditional<std::is_const<T>::value, const Ex, Ex>>;
if (is_exception_<Ex>::value && that->item_) { if (is_exception_<Ex>::value &&
if (auto ex = try_dynamic_cast_exception<CEx>(that->item_.get())) { (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<CEx>(raw)) {
f(*ex); f(*ex);
return true; return true;
} }
......
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