expose the class_name in an efficient way
authorMarc Horowitz <mhorowitz@fb.com>
Fri, 5 Sep 2014 23:45:24 +0000 (16:45 -0700)
committerAnton Likhtarov <alikhtarov@fb.com>
Fri, 26 Sep 2014 22:24:40 +0000 (15:24 -0700)
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:

folly/ExceptionWrapper.h
folly/test/ExceptionWrapperTest.cpp

index 953ce4d479b1ec0127e9d2927b7d8226cd79daa6..d14142f0b9ec93d8b8671827748e62feef357b10 100644 (file)
@@ -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>
index 5c99c68405444c347f009295413c6b3e10cb5d54..785ff13db5cdc3fb98fc651df0b3418efa0d59db 100644 (file)
@@ -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 {