From eaa278a52d9d5878021637a850627b853009c8bd Mon Sep 17 00:00:00 2001 From: Yedidya Feldblum Date: Wed, 4 Jan 2017 13:24:48 -0800 Subject: [PATCH 1/1] 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 --- folly/ExceptionWrapper.cpp | 14 +++++++++----- folly/ExceptionWrapper.h | 32 ++++++++++++++++++++++---------- 2 files changed, 31 insertions(+), 15 deletions(-) diff --git a/folly/ExceptionWrapper.cpp b/folly/ExceptionWrapper.cpp index 3a5c8623..d819c603 100644 --- a/folly/ExceptionWrapper.cpp +++ b/folly/ExceptionWrapper.cpp @@ -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(); } } diff --git a/folly/ExceptionWrapper.h b/folly/ExceptionWrapper.h index b573f23f..6bb39ccc 100644 --- a/folly/ExceptionWrapper.h +++ b/folly/ExceptionWrapper.h @@ -108,6 +108,9 @@ namespace folly { */ class exception_wrapper { private: + template + using is_exception_ = std::is_base_of; + template struct optimize; @@ -250,10 +253,19 @@ class exception_wrapper { } template - void assign_eptr(std::exception_ptr eptr, Ex& e) { + _t::value>> assign_eptr( + std::exception_ptr eptr, + Ex& e) { + this->eptr_ = eptr; + this->eobj_ = &const_cast<_t>&>(e); + } + + template + _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) { @@ -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 friend exception_wrapper make_exception_wrapper(Args&&... args); @@ -297,9 +309,6 @@ class exception_wrapper { } }; - template - using is_exception_ = std::is_base_of; - template static _t::value, T*>> try_dynamic_cast_exception(F* from) { @@ -317,8 +326,11 @@ class exception_wrapper { template static bool with_exception1(F f, T* that) { using CEx = _t::value, const Ex, Ex>>; - if (is_exception_::value && that->item_) { - if (auto ex = try_dynamic_cast_exception(that->item_.get())) { + 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; } -- 2.34.1