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
if (item_) {
auto& i = *item_;
return demangle(typeid(i));
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();
}
} else {
return fbstring();
}
fbstring exception_wrapper::what() const {
if (item_) {
return exceptionStr(*item_);
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();
*/
class exception_wrapper {
private:
*/
class exception_wrapper {
private:
+ template <typename T>
+ using is_exception_ = std::is_base_of<std::exception, T>;
+
template <typename Ex>
struct optimize;
template <typename Ex>
struct optimize;
- 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->estr_ = exceptionStr(e).toStdString();
- this->ename_ = demangle(typeid(e)).toStdString();
+ this->etype_ = &typeid(e);
}
void assign_eptr(std::exception_ptr eptr) {
}
void assign_eptr(std::exception_ptr eptr) {
// exception type, so we can at least get those back out without
// having to rethrow.
std::exception_ptr eptr_;
// 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);
template <class T, class... Args>
friend exception_wrapper make_exception_wrapper(Args&&... args);
- 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) {
template <typename T, typename F>
static _t<std::enable_if<is_exception_<T>::value, T*>>
try_dynamic_cast_exception(F* from) {
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>>;
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)) {