Lift the invoke helper in Function.h
[folly.git] / folly / Function.h
index b91de9ca16e4679b705e64f8259de9755a27a423..8cff8d8bb6b519e045c837f67462e10766ba46a6 100644 (file)
 #include <folly/CppAttributes.h>
 #include <folly/Portability.h>
 #include <folly/Traits.h>
+#include <folly/functional/Invoke.h>
 
 namespace folly {
 
@@ -246,22 +247,21 @@ union Data {
   std::aligned_storage<6 * sizeof(void*)>::type tiny;
 };
 
-template <typename Fun, typename FunT = typename std::decay<Fun>::type>
+template <typename Fun, typename = Fun*>
 using IsSmall = Conjunction<
-    std::integral_constant<bool, (sizeof(FunT) <= sizeof(Data::tiny))>,
-    std::is_nothrow_move_constructible<FunT>>;
+    std::integral_constant<bool, (sizeof(Fun) <= sizeof(Data::tiny))>,
+    std::is_nothrow_move_constructible<Fun>>;
 using SmallTag = std::true_type;
 using HeapTag = std::false_type;
 
-template <class T>
+template <typename T>
 struct NotFunction : std::true_type {};
-template <class T>
+template <typename T>
 struct NotFunction<Function<T>> : std::false_type {};
 
-template <typename Fun, typename FunT = typename std::decay<Fun>::type>
-using DecayIfConstructible = typename std::enable_if<
-    Conjunction<NotFunction<FunT>, std::is_constructible<FunT, Fun>>::value,
-    FunT>::type;
+template <typename T>
+using EnableIfNotFunction =
+    typename std::enable_if<NotFunction<T>::value>::type;
 
 struct CoerceTag {};
 
@@ -310,17 +310,16 @@ struct FunctionTraits<ReturnType(Args...)> {
   }
 
   ReturnType operator()(Args... args) {
-    auto& fn = *static_cast<Function<ReturnType(Args...)>*>(this);
+    auto& fn = *static_cast<Function<NonConstSignature>*>(this);
     return fn.call_(fn.data_, static_cast<Args&&>(args)...);
   }
 
   class SharedProxy {
-    std::shared_ptr<Function<ReturnType(Args...)>> sp_;
+    std::shared_ptr<Function<NonConstSignature>> sp_;
 
    public:
-    explicit SharedProxy(Function<ReturnType(Args...)>&& func)
-        : sp_(std::make_shared<Function<ReturnType(Args...)>>(
-              std::move(func))) {}
+    explicit SharedProxy(Function<NonConstSignature>&& func)
+        : sp_(std::make_shared<Function<NonConstSignature>>(std::move(func))) {}
     ReturnType operator()(Args&&... args) const {
       return (*sp_)(static_cast<Args&&>(args)...);
     }
@@ -356,17 +355,16 @@ struct FunctionTraits<ReturnType(Args...) const> {
   }
 
   ReturnType operator()(Args... args) const {
-    auto& fn = *static_cast<const Function<ReturnType(Args...) const>*>(this);
+    auto& fn = *static_cast<const Function<ConstSignature>*>(this);
     return fn.call_(fn.data_, static_cast<Args&&>(args)...);
   }
 
   class SharedProxy {
-    std::shared_ptr<Function<ReturnType(Args...) const>> sp_;
+    std::shared_ptr<Function<ConstSignature>> sp_;
 
    public:
-    explicit SharedProxy(Function<ReturnType(Args...) const>&& func)
-        : sp_(std::make_shared<Function<ReturnType(Args...) const>>(
-              std::move(func))) {}
+    explicit SharedProxy(Function<ConstSignature>&& func)
+        : sp_(std::make_shared<Function<ConstSignature>>(std::move(func))) {}
     ReturnType operator()(Args&&... args) const {
       return (*sp_)(static_cast<Args&&>(args)...);
     }
@@ -408,19 +406,6 @@ bool execBig(Op o, Data* src, Data* dst) {
   return true;
 }
 
-// Invoke helper
-template <typename F, typename... Args>
-inline constexpr auto invoke(F&& f, Args&&... args)
-    -> decltype(std::forward<F>(f)(std::forward<Args>(args)...)) {
-  return std::forward<F>(f)(std::forward<Args>(args)...);
-}
-
-template <typename M, typename C, typename... Args>
-inline constexpr auto invoke(M(C::*d), Args&&... args)
-    -> decltype(std::mem_fn(d)(std::forward<Args>(args)...)) {
-  return std::mem_fn(d)(std::forward<Args>(args)...);
-}
-
 } // namespace function
 } // namespace detail
 
@@ -494,6 +479,12 @@ class Function final : private detail::function::FunctionTraits<FunctionType> {
   // not copyable
   Function(const Function&) = delete;
 
+#if __OBJC__
+  // Delete conversion from Objective-C blocks
+  template <class ReturnType, class... Args>
+  Function(ReturnType (^)(Args...)) = delete;
+#endif
+
   /**
    * Move constructor
    */
@@ -529,10 +520,10 @@ class Function final : private detail::function::FunctionTraits<FunctionType> {
    */
   template <
       typename Fun,
-      typename FunT = detail::function::DecayIfConstructible<Fun>,
+      typename = detail::function::EnableIfNotFunction<Fun>,
       typename = typename Traits::template ResultOf<Fun>>
-  /* implicit */ Function(Fun&& fun) noexcept(
-      IsSmall<Fun>::value && noexcept(FunT(std::declval<Fun>())))
+  /* implicit */ Function(Fun fun) noexcept(
+      IsSmall<Fun>::value && noexcept(Fun(std::declval<Fun>())))
       : Function(static_cast<Fun&&>(fun), IsSmall<Fun>{}) {}
 
   /**
@@ -573,6 +564,12 @@ class Function final : private detail::function::FunctionTraits<FunctionType> {
 
   Function& operator=(const Function&) = delete;
 
+#if __OBJC__
+  // Delete conversion from Objective-C blocks
+  template <class ReturnType, class... Args>
+  Function& operator=(ReturnType (^)(Args...)) = delete;
+#endif
+
   /**
    * Move assignment operator
    *
@@ -580,7 +577,7 @@ class Function final : private detail::function::FunctionTraits<FunctionType> {
    * then `*this` is left in a valid but unspecified state.
    */
   Function& operator=(Function&& that) noexcept {
-    // Q: Why is is safe to destroy and reconstruct this object in place?
+    // Q: Why is it safe to destroy and reconstruct this object in place?
     // A: Two reasons: First, `Function` is a final class, so in doing this
     //    we aren't slicing off any derived parts. And second, the move
     //    operation is guaranteed not to throw so we always leave the object
@@ -603,7 +600,7 @@ class Function final : private detail::function::FunctionTraits<FunctionType> {
    * selected by overload resolution when `fun` is not a compatible function.
    */
   template <typename Fun, typename = decltype(Function(std::declval<Fun>()))>
-  Function& operator=(Fun&& fun) noexcept(
+  Function& operator=(Fun fun) noexcept(
       noexcept(/* implicit */ Function(std::declval<Fun>()))) {
     // Doing this in place is more efficient when we can do so safely.
     if (noexcept(/* implicit */ Function(std::declval<Fun>()))) {
@@ -793,7 +790,7 @@ class FunctionRef<ReturnType(Args...)> final {
   template <typename Fun>
   static ReturnType call(void* object, Args&&... args) {
     using Pointer = _t<std::add_pointer<Fun>>;
-    return static_cast<ReturnType>(detail::function::invoke(
+    return static_cast<ReturnType>(invoke(
         static_cast<Fun&&>(*static_cast<Pointer>(object)),
         static_cast<Args&&>(args)...));
   }