Commit d7364d7e authored by Marc Horowitz's avatar Marc Horowitz Committed by Anton Likhtarov

expose the class_name in an efficient way

Summary:
Add a class_name method, which doesn't need to throw/catch
regardless how the exception is captured.

Test Plan: exception_wrapper_test

Reviewed By: mshneer@fb.com

Subscribers: njormrod

FB internal diff: D1543596

Tasks: 5025089

Blame Revision:
parent 215076a5
...@@ -143,7 +143,7 @@ class exception_wrapper { ...@@ -143,7 +143,7 @@ class exception_wrapper {
fbstring what() const { fbstring what() const {
if (item_) { if (item_) {
return exceptionStr(*item_.get()); return exceptionStr(*item_);
} else if (eptr_) { } else if (eptr_) {
return estr_; return estr_;
} else { } else {
...@@ -151,10 +151,20 @@ class exception_wrapper { ...@@ -151,10 +151,20 @@ class exception_wrapper {
} }
} }
fbstring class_name() const {
if (item_) {
return demangle(typeid(*item_));
} else if (eptr_) {
return ename_;
} else {
return fbstring();
}
}
template <class Ex> template <class Ex>
bool is_compatible_with() const { bool is_compatible_with() const {
if (item_) { if (item_) {
return dynamic_cast<const Ex*>(getCopied()); return dynamic_cast<const Ex*>(item_.get());
} else if (eptr_) { } else if (eptr_) {
try { try {
std::rethrow_exception(eptr_); std::rethrow_exception(eptr_);
...@@ -197,10 +207,12 @@ protected: ...@@ -197,10 +207,12 @@ protected:
std::shared_ptr<std::exception> item_; std::shared_ptr<std::exception> item_;
void (*throwfn_)(std::exception*); void (*throwfn_)(std::exception*);
// Fallback case: store the library wrapper, which is less efficient // Fallback case: store the library wrapper, which is less efficient
// but gets the job done. Also store the the what() string, so we // but gets the job done. Also store exceptionPtr() the name of the
// can at least get it back out without having to rethrow. // exception type, so we can at least get those back out without
// having to rethrow.
std::exception_ptr eptr_; std::exception_ptr eptr_;
std::string estr_; std::string estr_;
std::string ename_;
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);
...@@ -212,7 +224,7 @@ private: ...@@ -212,7 +224,7 @@ private:
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) {
if (that->item_) { if (that->item_) {
if (auto ex = dynamic_cast<Ex*>(that->getCopied())) { if (auto ex = dynamic_cast<Ex*>(that->item_.get())) {
f(*ex); f(*ex);
return true; return true;
} }
...@@ -298,17 +310,10 @@ class try_and_catch<LastException, Exceptions...> : ...@@ -298,17 +310,10 @@ class try_and_catch<LastException, Exceptions...> :
try_and_catch() : Base() {} try_and_catch() : Base() {}
template <typename Ex> template <typename Ex>
typename std::enable_if<std::is_base_of<std::exception, Ex>::value>::type void assign_eptr(Ex& e) {
assign_eptr(Ex& e) {
this->eptr_ = std::current_exception();
this->estr_ = exceptionStr(e).toStdString();
}
template <typename Ex>
typename std::enable_if<!std::is_base_of<std::exception, Ex>::value>::type
assign_eptr(Ex& e) {
this->eptr_ = std::current_exception(); this->eptr_ = std::current_exception();
this->estr_ = exceptionStr(e).toStdString(); this->estr_ = exceptionStr(e).toStdString();
this->ename_ = demangle(typeid(e)).toStdString();
} }
template <typename Ex> template <typename Ex>
......
...@@ -38,11 +38,15 @@ TEST(ExceptionWrapper, throw_test) { ...@@ -38,11 +38,15 @@ TEST(ExceptionWrapper, throw_test) {
} }
} }
TEST(ExceptionWrapper, boolean) { TEST(ExceptionWrapper, members) {
auto ew = exception_wrapper(); auto ew = exception_wrapper();
EXPECT_FALSE(bool(ew)); EXPECT_FALSE(bool(ew));
EXPECT_EQ(ew.what(), "");
EXPECT_EQ(ew.class_name(), "");
ew = make_exception_wrapper<std::runtime_error>("payload"); ew = make_exception_wrapper<std::runtime_error>("payload");
EXPECT_TRUE(bool(ew)); EXPECT_TRUE(bool(ew));
EXPECT_EQ(ew.what(), "std::runtime_error: payload");
EXPECT_EQ(ew.class_name(), "std::runtime_error");
} }
TEST(ExceptionWrapper, equals) { TEST(ExceptionWrapper, equals) {
...@@ -91,6 +95,7 @@ TEST(ExceptionWrapper, try_and_catch_test) { ...@@ -91,6 +95,7 @@ TEST(ExceptionWrapper, try_and_catch_test) {
EXPECT_TRUE(bool(ew)); EXPECT_TRUE(bool(ew));
EXPECT_TRUE(ew.getCopied()); EXPECT_TRUE(ew.getCopied());
EXPECT_EQ(ew.what(), "std::runtime_error: payload"); EXPECT_EQ(ew.what(), "std::runtime_error: payload");
EXPECT_EQ(ew.class_name(), "std::runtime_error");
auto rep = ew.is_compatible_with<std::runtime_error>(); auto rep = ew.is_compatible_with<std::runtime_error>();
EXPECT_TRUE(rep); EXPECT_TRUE(rep);
...@@ -111,7 +116,8 @@ TEST(ExceptionWrapper, try_and_catch_test) { ...@@ -111,7 +116,8 @@ TEST(ExceptionWrapper, try_and_catch_test) {
throw std::exception(); throw std::exception();
}); });
EXPECT_TRUE(bool(ew3)); EXPECT_TRUE(bool(ew3));
EXPECT_NE(ew3.what(), expected); EXPECT_EQ(ew3.what(), "std::exception: std::exception");
EXPECT_EQ(ew3.class_name(), "std::exception");
rep = ew3.is_compatible_with<std::runtime_error>(); rep = ew3.is_compatible_with<std::runtime_error>();
EXPECT_FALSE(rep); EXPECT_FALSE(rep);
...@@ -154,6 +160,7 @@ TEST(ExceptionWrapper, with_exception_test) { ...@@ -154,6 +160,7 @@ TEST(ExceptionWrapper, with_exception_test) {
}); });
EXPECT_TRUE(bool(ew)); EXPECT_TRUE(bool(ew));
EXPECT_EQ(ew.what(), "IntException: int == 23"); EXPECT_EQ(ew.what(), "IntException: int == 23");
EXPECT_EQ(ew.class_name(), "IntException");
ew.with_exception<IntException>([&](const IntException& ie) { ew.with_exception<IntException>([&](const IntException& ie) {
EXPECT_EQ(ie.getInt(), expected); EXPECT_EQ(ie.getInt(), expected);
}); });
...@@ -166,6 +173,7 @@ TEST(ExceptionWrapper, with_exception_test) { ...@@ -166,6 +173,7 @@ TEST(ExceptionWrapper, with_exception_test) {
}); });
EXPECT_TRUE(bool(ew2)); EXPECT_TRUE(bool(ew2));
EXPECT_EQ(ew2.what(), "IntException: int == 23"); EXPECT_EQ(ew2.what(), "IntException: int == 23");
EXPECT_EQ(ew2.class_name(), "IntException");
ew2.with_exception<AbstractIntException>([&](AbstractIntException& ie) { ew2.with_exception<AbstractIntException>([&](AbstractIntException& ie) {
EXPECT_EQ(ie.getInt(), expected); EXPECT_EQ(ie.getInt(), expected);
EXPECT_EQ(typeid(ie), typeid(IntException)); EXPECT_EQ(typeid(ie), typeid(IntException));
...@@ -197,6 +205,7 @@ TEST(ExceptionWrapper, non_std_exception_test) { ...@@ -197,6 +205,7 @@ TEST(ExceptionWrapper, non_std_exception_test) {
EXPECT_TRUE(bool(ew)); EXPECT_TRUE(bool(ew));
EXPECT_FALSE(ew.is_compatible_with<std::exception>()); EXPECT_FALSE(ew.is_compatible_with<std::exception>());
EXPECT_EQ(ew.what(), "int"); EXPECT_EQ(ew.what(), "int");
EXPECT_EQ(ew.class_name(), "int");
// non-std::exception types are supported, but the only way to // non-std::exception types are supported, but the only way to
// access their value is to explicity rethrow and catch it. // access their value is to explicity rethrow and catch it.
try { try {
......
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