Reimplement folly::Function to improve compile times.
[folly.git] / folly / ExceptionWrapper.h
index a99e84d95a8f35e9deb95665275efe28130fa47a..22857a0b9b543259f504e52dc9283b9bf023db52 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2015 Facebook, Inc.
+ * Copyright 2016 Facebook, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-#ifndef FOLLY_EXCEPTIONWRAPPER_H
-#define FOLLY_EXCEPTIONWRAPPER_H
+#pragma once
 
 #include <cassert>
 #include <exception>
@@ -88,16 +87,15 @@ namespace folly {
  *
  * // Thread2: Exceptions are bad!
  * void processResult() {
- *   auto ep = globalExceptionWrapper.get();
- *   if (!ep.with_exception<FacePlantException>([&](
- *     FacePlantException& faceplant) {
- *       LOG(ERROR) << "FACEPLANT";
- *     })) {
- *     ep.with_exception<FailWhaleException>([&](
- *       FailWhaleException& failwhale) {
+ *   globalExceptionWrapper.with_exception(
+ *       [&](FacePlantException& faceplant) {
+ *         LOG(ERROR) << "FACEPLANT";
+ *       }) ||
+ *   globalExceptionWrapper.with_exception(
+ *       [&](FailWhaleException& failwhale) {
  *         LOG(ERROR) << "FAILWHALE!";
- *       });
- *   }
+ *       }) ||
+ *   LOG(FATAL) << "Unrecognized exception";
  * }
  *
  */
@@ -112,10 +110,12 @@ class exception_wrapper {
   // Implicitly construct an exception_wrapper from a qualifying exception.
   // See the optimize struct for details.
   template <typename Ex, typename =
-    typename std::enable_if<optimize<Ex>::value>::type>
+    typename std::enable_if<optimize<typename std::decay<Ex>::type>::value>
+    ::type>
   /* implicit */ exception_wrapper(Ex&& exn) {
-    item_ = std::make_shared<Ex>(std::forward<Ex>(exn));
-    throwfn_ = folly::detail::Thrower<Ex>::doThrow;
+    typedef typename std::decay<Ex>::type DEx;
+    item_ = std::make_shared<DEx>(std::forward<Ex>(exn));
+    throwfn_ = folly::detail::Thrower<DEx>::doThrow;
   }
 
   // The following two constructors are meant to emulate the behavior of
@@ -212,8 +212,8 @@ class exception_wrapper {
     } else if (eptr_) {
       try {
         std::rethrow_exception(eptr_);
-      } catch (std::exception& e) {
-        return dynamic_cast<const Ex*>(&e);
+      } catch (typename std::decay<Ex>::type&) {
+        return true;
       } catch (...) {
         // fall through
       }
@@ -221,6 +221,18 @@ class exception_wrapper {
     return false;
   }
 
+  template <class F>
+  bool with_exception(F&& f) {
+    using arg_type = typename functor_traits<F>::arg_type_decayed;
+    return with_exception<arg_type>(std::forward<F>(f));
+  }
+
+  template <class F>
+  bool with_exception(F&& f) const {
+    using arg_type = typename functor_traits<F>::arg_type_decayed;
+    return with_exception<const arg_type>(std::forward<F>(f));
+  }
+
   // If this exception wrapper wraps an exception of type Ex, with_exception
   // will call f with the wrapped exception as an argument and return true, and
   // will otherwise return false.
@@ -308,6 +320,20 @@ protected:
   friend exception_wrapper make_exception_wrapper(Args&&... args);
 
 private:
+  template <typename F>
+  struct functor_traits {
+    template <typename T>
+    struct impl;
+    template <typename C, typename R, typename A>
+    struct impl<R(C::*)(A)> { using arg_type = A; };
+    template <typename C, typename R, typename A>
+    struct impl<R(C::*)(A) const> { using arg_type = A; };
+    using functor_decayed = typename std::decay<F>::type;
+    using functor_op = decltype(&functor_decayed::operator());
+    using arg_type = typename impl<functor_op>::arg_type;
+    using arg_type_decayed = typename std::decay<arg_type>::type;
+  };
+
   // 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.
@@ -321,11 +347,9 @@ private:
     } 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 (Ex& e) {
+        f(e);
+        return true;
       } catch (...) {
         // fall through
       }
@@ -412,7 +436,7 @@ class try_and_catch<LastException, Exceptions...> :
 
   template <typename Ex>
   typename std::enable_if<exception_wrapper::optimize<Ex>::value>::type
-  assign_exception(Ex& e, std::exception_ptr eptr) {
+  assign_exception(Ex& e, std::exception_ptr /*eptr*/) {
     this->item_ = std::make_shared<Ex>(e);
     this->throwfn_ = folly::detail::Thrower<Ex>::doThrow;
   }
@@ -443,4 +467,3 @@ class try_and_catch<> : public exception_wrapper {
   }
 };
 }
-#endif