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 {
if (item_) {
auto& i = *item_;
return demangle(typeid(i));
} else if (eptr_) {
return ename_;
} else if (eptr_ && eobj_) {
return demangle(typeid(*eobj_));
} else if (eptr_ && etype_) {
return demangle(*etype_);
} else {
return fbstring();
}
......@@ -46,10 +48,12 @@ fbstring exception_wrapper::class_name() const {
fbstring exception_wrapper::what() const {
if (item_) {
return exceptionStr(*item_);
} else if (eptr_) {
return estr_;
} else if (eptr_ && eobj_) {
return class_name() + ": " + eobj_->what();
} else if (eptr_ && etype_) {
return class_name();
} else {
return fbstring();
return class_name();
}
}
......
......@@ -108,6 +108,9 @@ namespace folly {
*/
class exception_wrapper {
private:
template <typename T>
using is_exception_ = std::is_base_of<std::exception, T>;
template <typename Ex>
struct optimize;
......@@ -250,10 +253,19 @@ class exception_wrapper {
}
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->estr_ = exceptionStr(e).toStdString();
this->ename_ = demangle(typeid(e)).toStdString();
this->etype_ = &typeid(e);
}
void assign_eptr(std::exception_ptr eptr) {
......@@ -270,8 +282,8 @@ class exception_wrapper {
// 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 <class T, class... Args>
friend exception_wrapper make_exception_wrapper(Args&&... args);
......@@ -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>
static _t<std::enable_if<is_exception_<T>::value, T*>>
try_dynamic_cast_exception(F* from) {
......@@ -317,8 +326,11 @@ class exception_wrapper {
template <class Ex, class F, class T>
static bool with_exception1(F f, T* that) {
using CEx = _t<std::conditional<std::is_const<T>::value, const Ex, Ex>>;
if (is_exception_<Ex>::value && that->item_) {
if (auto ex = try_dynamic_cast_exception<CEx>(that->item_.get())) {
if (is_exception_<Ex>::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<CEx>(raw)) {
f(*ex);
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