Commit 9d4d4b00 authored by Marc Horowitz's avatar Marc Horowitz Committed by Dave Watson

make with_exception() const work in all cases

Summary:
Abstract the with_exception() logic into a static template
function which will work with a const or non-const object.

Test Plan: exception_wrapper_test

Reviewed By: vloh@fb.com

Subscribers: njormrod

FB internal diff: D1549175

Tasks: 5127267
parent 28f7ed4f
...@@ -169,29 +169,12 @@ class exception_wrapper { ...@@ -169,29 +169,12 @@ class exception_wrapper {
template <class Ex, class F> template <class Ex, class F>
bool with_exception(F f) { bool with_exception(F f) {
if (item_) { return with_exception1<Ex>(f, this);
if (auto ex = dynamic_cast<Ex*>(getCopied())) {
f(*ex);
return true;
}
} else if (eptr_) {
try {
std::rethrow_exception(eptr_);
} catch (std::exception& e) {
if (auto ex = dynamic_cast<Ex*>(&e)) {
f(*ex);
return true;
}
} catch (...) {
// fall through
}
}
return false;
} }
template <class Ex, class F> template <class Ex, class F>
bool with_exception(F f) const { bool with_exception(F f) const {
return with_exception<const Ex>(f); return with_exception1<const Ex>(f, this);
} }
std::exception_ptr getExceptionPtr() const { std::exception_ptr getExceptionPtr() const {
...@@ -207,7 +190,7 @@ class exception_wrapper { ...@@ -207,7 +190,7 @@ class exception_wrapper {
return std::exception_ptr(); return std::exception_ptr();
} }
protected: protected:
// Optimized case: if we know what type the exception is, we can // Optimized case: if we know what type the exception is, we can
// store a copy of the concrete type, and a helper function so we // store a copy of the concrete type, and a helper function so we
// can rethrow it. // can rethrow it.
...@@ -221,6 +204,32 @@ class exception_wrapper { ...@@ -221,6 +204,32 @@ class exception_wrapper {
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);
private:
// What makes this useful is that T can be exception_wrapper* or
// const exception_wrapper*, and the compiler will use the
// instantiation which works with F.
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())) {
f(*ex);
return true;
}
} else if (that->eptr_) {
try {
std::rethrow_exception(that->eptr_);
} catch (std::exception& e) {
if (auto ex = dynamic_cast<Ex*>(&e)) {
f(*ex);
return true;
}
} catch (...) {
// fall through
}
}
return false;
}
}; };
template <class T, class... Args> template <class T, class... Args>
......
...@@ -170,6 +170,21 @@ TEST(ExceptionWrapper, with_exception_test) { ...@@ -170,6 +170,21 @@ TEST(ExceptionWrapper, with_exception_test) {
EXPECT_EQ(ie.getInt(), expected); EXPECT_EQ(ie.getInt(), expected);
EXPECT_EQ(typeid(ie), typeid(IntException)); EXPECT_EQ(typeid(ie), typeid(IntException));
}); });
// Test with const this. If this compiles and does not crash due to
// infinite loop when it runs, it succeeds.
const exception_wrapper& cew = ew;
cew.with_exception<IntException>([&](const IntException& ie) {
SUCCEED();
});
// This won't even compile. You can't use a function which takes a
// non-const reference with a const exception_wrapper.
/*
cew.with_exception<IntException>([&](IntException& ie) {
SUCCEED();
});
*/
} }
TEST(ExceptionWrapper, non_std_exception_test) { TEST(ExceptionWrapper, non_std_exception_test) {
......
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