From f0daf647cd1435d8511b0fd8c64b31ed37e8beb8 Mon Sep 17 00:00:00 2001
From: Yedidya Feldblum <yfeldblum@fb.com>
Date: Fri, 12 May 2017 14:14:22 -0700
Subject: [PATCH] exception_wrapper::get_object<>

Summary:
[Folly] `exception_wrapper::get_object<>`.

Returns a pointer to the stored object, if the template type parameter is of the right sort.

Reviewed By: jsedgwick

Differential Revision: D5000720

fbshipit-source-id: 2869439085e8dfb56e6cb439794b03876b7d715c
---
 folly/ExceptionWrapper-inl.h        | 14 ++++++++++++++
 folly/ExceptionWrapper.h            | 12 ++++++++++++
 folly/test/ExceptionWrapperTest.cpp | 22 ++++++++++++++++++++++
 3 files changed, 48 insertions(+)

diff --git a/folly/ExceptionWrapper-inl.h b/folly/ExceptionWrapper-inl.h
index 99cbd9de..aca35f2c 100644
--- a/folly/ExceptionWrapper-inl.h
+++ b/folly/ExceptionWrapper-inl.h
@@ -350,6 +350,20 @@ inline std::exception const* exception_wrapper::get_exception() const noexcept {
   return vptr_->get_exception_(this);
 }
 
+template <typename Ex>
+inline Ex* exception_wrapper::get_object() noexcept {
+  Ex* object{nullptr};
+  with_exception([&](Ex& ex) { object = &ex; });
+  return object;
+}
+
+template <typename Ex>
+inline Ex const* exception_wrapper::get_object() const noexcept {
+  Ex const* object{nullptr};
+  with_exception([&](Ex const& ex) { object = &ex; });
+  return object;
+}
+
 inline std::exception_ptr const& exception_wrapper::to_exception_ptr()
     noexcept {
   // Computing an exception_ptr is expensive so cache the result.
diff --git a/folly/ExceptionWrapper.h b/folly/ExceptionWrapper.h
index a1adfecd..82dfde72 100644
--- a/folly/ExceptionWrapper.h
+++ b/folly/ExceptionWrapper.h
@@ -457,6 +457,18 @@ class exception_wrapper final {
   //! \overload
   std::exception const* get_exception() const noexcept;
 
+  //! \returns a pointer to the `Ex` held by `*this`, if it holds an object
+  //!     whose type `From` permits `std::is_convertible<From*, Ex*>`;
+  //!     otherwise, returns `nullptr`.
+  //! \note This function does not mutate the `exception_wrapper` object.
+  //! \note This function may cause an exception to be thrown and immediately
+  //!     caught internally, affecting runtime performance.
+  template <typename Ex>
+  Ex* get_object() noexcept;
+  //! \overload
+  template <typename Ex>
+  Ex const* get_object() const noexcept;
+
   //! \return A `std::exception_ptr` that references either the exception held
   //!     by `*this`, or a copy of same.
   //! \note This function may need to throw an exception to complete the action.
diff --git a/folly/test/ExceptionWrapperTest.cpp b/folly/test/ExceptionWrapperTest.cpp
index 67f14c5e..fde0e8a9 100644
--- a/folly/test/ExceptionWrapperTest.cpp
+++ b/folly/test/ExceptionWrapperTest.cpp
@@ -215,6 +215,8 @@ TEST(ExceptionWrapper, with_exception_ptr_empty) {
   EXPECT_EQ(exception_wrapper::none(), ew.type());
   EXPECT_FALSE(bool(ew));
   EXPECT_EQ(nullptr, ew.get_exception());
+  EXPECT_EQ(nullptr, ew.get_object<std::exception>());
+  EXPECT_EQ(nullptr, ew.get_object<int>());
   EXPECT_FALSE(ew.has_exception_ptr());
   EXPECT_EQ(nullptr, ew.to_exception_ptr());
   EXPECT_FALSE(ew.has_exception_ptr());
@@ -230,6 +232,8 @@ TEST(ExceptionWrapper, with_shared_ptr_test) {
   EXPECT_TRUE(bool(ew));
   EXPECT_EQ(typeid(std::runtime_error), ew.type());
   EXPECT_NE(nullptr, ew.get_exception());
+  EXPECT_NE(nullptr, ew.get_object<std::exception>());
+  EXPECT_EQ(nullptr, ew.get_object<int>());
   EXPECT_FALSE(ew.has_exception_ptr());
   EXPECT_NE(nullptr, ew.to_exception_ptr());
   EXPECT_TRUE(ew.has_exception_ptr());
@@ -244,6 +248,8 @@ TEST(ExceptionWrapper, with_shared_ptr_test) {
   EXPECT_FALSE(bool(ew));
   EXPECT_EQ(exception_wrapper::none(), ew.type());
   EXPECT_EQ(nullptr, ew.get_exception());
+  EXPECT_EQ(nullptr, ew.get_object<std::exception>());
+  EXPECT_EQ(nullptr, ew.get_object<int>());
   EXPECT_EQ(nullptr, ew.to_exception_ptr());
   EXPECT_EQ("", ew.class_name());
   EXPECT_EQ("", ew.what());
@@ -258,6 +264,8 @@ TEST(ExceptionWrapper, with_exception_ptr_exn_test) {
   EXPECT_TRUE(bool(ew));
   EXPECT_EQ(typeid(std::runtime_error), ew.type());
   EXPECT_NE(nullptr, ew.get_exception());
+  EXPECT_NE(nullptr, ew.get_object<std::exception>());
+  EXPECT_EQ(nullptr, ew.get_object<int>());
   EXPECT_TRUE(ew.has_exception_ptr());
   EXPECT_EQ(ep, ew.to_exception_ptr());
   EXPECT_TRUE(ew.has_exception_ptr());
@@ -272,6 +280,8 @@ TEST(ExceptionWrapper, with_exception_ptr_exn_test) {
   EXPECT_FALSE(bool(ew));
   EXPECT_EQ(exception_wrapper::none(), ew.type());
   EXPECT_EQ(nullptr, ew.get_exception());
+  EXPECT_EQ(nullptr, ew.get_object<std::exception>());
+  EXPECT_EQ(nullptr, ew.get_object<int>());
   EXPECT_EQ(nullptr, ew.to_exception_ptr());
   EXPECT_EQ("", ew.class_name());
   EXPECT_EQ("", ew.what());
@@ -285,6 +295,8 @@ TEST(ExceptionWrapper, with_exception_ptr_any_test) {
   auto ew = exception_wrapper(ep, from_eptr<int>(ep));
   EXPECT_TRUE(bool(ew));
   EXPECT_EQ(nullptr, ew.get_exception());
+  EXPECT_EQ(nullptr, ew.get_object<std::exception>());
+  EXPECT_NE(nullptr, ew.get_object<int>());
   EXPECT_TRUE(ew.has_exception_ptr());
   EXPECT_EQ(ep, ew.to_exception_ptr());
   EXPECT_TRUE(ew.has_exception_ptr());
@@ -298,6 +310,8 @@ TEST(ExceptionWrapper, with_exception_ptr_any_test) {
   exception_wrapper(std::move(ew));
   EXPECT_FALSE(bool(ew));
   EXPECT_EQ(nullptr, ew.get_exception());
+  EXPECT_EQ(nullptr, ew.get_object<std::exception>());
+  EXPECT_EQ(nullptr, ew.get_object<int>());
   EXPECT_EQ(nullptr, ew.to_exception_ptr());
   EXPECT_FALSE(ew.has_exception_ptr());
   EXPECT_EQ("", ew.class_name());
@@ -311,6 +325,8 @@ TEST(ExceptionWrapper, with_non_std_exception_test) {
   auto ew = exception_wrapper(folly::in_place, 42);
   EXPECT_TRUE(bool(ew));
   EXPECT_EQ(nullptr, ew.get_exception());
+  EXPECT_EQ(nullptr, ew.get_object<std::exception>());
+  EXPECT_NE(nullptr, ew.get_object<int>());
   EXPECT_FALSE(ew.has_exception_ptr());
   EXPECT_EQ("int", ew.class_name());
   EXPECT_EQ("int", ew.what());
@@ -326,6 +342,8 @@ TEST(ExceptionWrapper, with_non_std_exception_test) {
   exception_wrapper(std::move(ew));
   EXPECT_FALSE(bool(ew));
   EXPECT_EQ(nullptr, ew.get_exception());
+  EXPECT_EQ(nullptr, ew.get_object<std::exception>());
+  EXPECT_EQ(nullptr, ew.get_object<int>());
   EXPECT_EQ(nullptr, ew.to_exception_ptr());
   EXPECT_FALSE(ew.has_exception_ptr());
   EXPECT_EQ("", ew.class_name());
@@ -340,6 +358,8 @@ TEST(ExceptionWrapper, with_exception_ptr_any_nil_test) {
   auto ew = exception_wrapper(ep); // concrete type is erased
   EXPECT_TRUE(bool(ew));
   EXPECT_EQ(nullptr, ew.get_exception());
+  EXPECT_EQ(nullptr, ew.get_object<std::exception>());
+  EXPECT_NE(nullptr, ew.get_object<int>());
   EXPECT_EQ(ep, ew.to_exception_ptr());
   EXPECT_EQ("<unknown exception>", ew.class_name()); // because concrete type is
   // erased
@@ -352,6 +372,8 @@ TEST(ExceptionWrapper, with_exception_ptr_any_nil_test) {
   exception_wrapper(std::move(ew));
   EXPECT_FALSE(bool(ew));
   EXPECT_EQ(nullptr, ew.get_exception());
+  EXPECT_EQ(nullptr, ew.get_object<std::exception>());
+  EXPECT_EQ(nullptr, ew.get_object<int>());
   EXPECT_EQ(nullptr, ew.to_exception_ptr());
   EXPECT_EQ("", ew.class_name());
   EXPECT_EQ("", ew.what());
-- 
2.34.1