Fix SimpleBarrier
[folly.git] / folly / ExceptionWrapper.h
index 3b44e53f2d7709c6a773090e82bd5d8bfe1af3cb..a44d3dd790206523a10f39a88964294dfcae379d 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2014 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.
  * limitations under the License.
  */
 
-#ifndef FOLLY_EXCEPTIONWRAPPER_H
-#define FOLLY_EXCEPTIONWRAPPER_H
+#pragma once
 
-#include <cassert>
 #include <exception>
 #include <memory>
-#include <folly/String.h>
+#include <string>
+#include <type_traits>
+#include <utility>
+
+#include <folly/ExceptionString.h>
+#include <folly/FBString.h>
 #include <folly/detail/ExceptionWrapper.h>
 
 namespace folly {
@@ -88,16 +91,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 +114,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
@@ -148,13 +152,9 @@ class exception_wrapper {
     assign_eptr(eptr);
   }
 
-  void throwException() const {
-    if (throwfn_) {
-      throwfn_(item_.get());
-    } else if (eptr_) {
-      std::rethrow_exception(eptr_);
-    }
-  }
+  // If the exception_wrapper does not contain an exception, std::terminate()
+  // is invoked to assure the [[noreturn]] behaviour.
+  [[noreturn]] void throwException() const;
 
   explicit operator bool() const {
     return item_ || eptr_;
@@ -184,26 +184,8 @@ class exception_wrapper {
   std::exception* getCopied() { return item_.get(); }
   const std::exception* getCopied() const { return item_.get(); }
 
-  fbstring what() const {
-    if (item_) {
-      return exceptionStr(*item_);
-    } else if (eptr_) {
-      return estr_;
-    } else {
-      return fbstring();
-    }
-  }
-
-  fbstring class_name() const {
-    if (item_) {
-      auto& i = *item_;
-      return demangle(typeid(i));
-    } else if (eptr_) {
-      return ename_;
-    } else {
-      return fbstring();
-    }
-  }
+  fbstring what() const;
+  fbstring class_name() const;
 
   template <class Ex>
   bool is_compatible_with() const {
@@ -212,8 +194,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 +203,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.
@@ -248,7 +242,9 @@ class exception_wrapper {
     bool>::type
   with_exception(F f) const {
     try {
-      throwException();
+      if (*this) {
+        throwException();
+      }
     } catch (typename std::decay<Ex>::type& e) {
       f(e);
       return true;
@@ -264,7 +260,9 @@ class exception_wrapper {
     }
 
     try {
-      throwException();
+      if (*this) {
+        throwException();
+      }
     } catch (...) {
       return std::current_exception();
     }
@@ -308,6 +306,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 +333,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
       }
@@ -342,6 +352,9 @@ exception_wrapper make_exception_wrapper(Args&&... args) {
   return ew;
 }
 
+// For consistency with exceptionStr() functions in String.h
+fbstring exceptionStr(const exception_wrapper& ew);
+
 /*
  * try_and_catch is a simple replacement for try {} catch(){} that allows you to
  * specify which derived exceptions you would like to catch and store in an
@@ -407,7 +420,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;
   }
@@ -429,7 +442,7 @@ class try_and_catch<LastException, Exceptions...> :
 template<>
 class try_and_catch<> : public exception_wrapper {
  public:
-  try_and_catch() {}
+  try_and_catch() = default;
 
  protected:
   template <typename F>
@@ -437,5 +450,5 @@ class try_and_catch<> : public exception_wrapper {
     fn();
   }
 };
-}
-#endif
+
+} // folly