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