Function::asStdFunction()
authorJames Sedgwick <jsedgwick@fb.com>
Tue, 5 Apr 2016 22:05:33 +0000 (15:05 -0700)
committerFacebook Github Bot 9 <facebook-github-bot-9-bot@fb.com>
Tue, 5 Apr 2016 22:22:44 +0000 (15:22 -0700)
Summary:This is an ugly but occassionally useful hack to accomodate cases
where we want to propagate folly::Function but run into the brick wall that is
std::function

@override-unit-failures

Reviewed By: spacedentist

Differential Revision: D3118432

fb-gh-sync-id: 80ed56494dfcf60e0f266013d880107acabc7dcf
fbshipit-source-id: 80ed56494dfcf60e0f266013d880107acabc7dcf

folly/Function-pre.h
folly/Function.h
folly/test/FunctionTest.cpp

index 293efbcb891fddf90efb19ae929c254e0a5119c4..5e91fbb5f59250cda2c3ec110d14b4855f8043b8 100644 (file)
@@ -313,6 +313,20 @@ class FunctionTypeTraits<R(Args...) const>::ExecutorMixin {
   InvokeFunctionPtr const invokePtr;
 };
 
+template <class Function>
+struct InvokeFromSharedPtr final {
+  std::shared_ptr<Function> ptr_;
+
+  explicit InvokeFromSharedPtr(std::shared_ptr<Function> ptr)
+      : ptr_(std::move(ptr)) {}
+
+  template <typename... Args>
+  auto operator()(Args&&... args)
+      -> decltype((*ptr_)(std::forward<Args>(args)...)) {
+    return (*ptr_)(std::forward<Args>(args)...);
+  }
+};
+
 } // namespace function
 } // namespace detail
 } // namespace folly
index 1f6238edf825c14aad14c0f5420d62631640822f..399efd54c17c2298f8296d30ba4ce432ad645c6c 100644 (file)
@@ -303,6 +303,16 @@ class Function final
    */
   Function& operator=(Function&& rhs) noexcept(hasNoExceptMoveCtor());
 
+  /**
+   * Construct a std::function by moving in the contents of this `Function`.
+   * Note that the returned std::function will share its state (i.e. captured
+   * data) across all copies you make of it, so be very careful when copying.
+   */
+  std::function<typename Traits::NonConstFunctionType> asStdFunction() && {
+    return detail::function::InvokeFromSharedPtr<Function>(
+        std::make_shared<Function>(std::move(*this)));
+  }
+
   /**
    * Constructs a `Function` by moving from one with different template
    * parameters with regards to const-ness, no-except-movability and internal
index 6e073f24503b88145a4cb06a4af57c32cc26d5e0..f6f40e8caeaf0739eb9913d6e6ccf2ad5f538c20 100644 (file)
@@ -1230,3 +1230,75 @@ TEST(Function, ConvertReturnType) {
   Function<CBase()> cf9 = std::move(f9);
   EXPECT_EQ(cf9().x, 66);
 }
+
+TEST(Function, asStdFunction_void) {
+  int i = 0;
+  folly::Function<void()> f = [&] { ++i; };
+  auto sf = std::move(f).asStdFunction();
+  static_assert(std::is_same<decltype(sf), std::function<void()>>::value,
+      "std::function has wrong type");
+  sf();
+  EXPECT_EQ(1, i);
+}
+
+TEST(Function, asStdFunction_void_const) {
+  int i = 0;
+  folly::Function<void() const> f = [&] { ++i; };
+  auto sf = std::move(f).asStdFunction();
+  static_assert(std::is_same<decltype(sf), std::function<void()>>::value,
+      "std::function has wrong type");
+  sf();
+  EXPECT_EQ(1, i);
+}
+
+TEST(Function, asStdFunction_return) {
+  int i = 0;
+  folly::Function<int()> f = [&] {
+    ++i;
+    return 42;
+  };
+  auto sf = std::move(f).asStdFunction();
+  static_assert(std::is_same<decltype(sf), std::function<int()>>::value,
+      "std::function has wrong type");
+  EXPECT_EQ(42, sf());
+  EXPECT_EQ(1, i);
+}
+
+TEST(Function, asStdFunction_return_const) {
+  int i = 0;
+  folly::Function<int() const> f = [&] {
+    ++i;
+    return 42;
+  };
+  auto sf = std::move(f).asStdFunction();
+  static_assert(std::is_same<decltype(sf), std::function<int()>>::value,
+      "std::function has wrong type");
+  EXPECT_EQ(42, sf());
+  EXPECT_EQ(1, i);
+}
+
+TEST(Function, asStdFunction_args) {
+  int i = 0;
+  folly::Function<void(int, int)> f = [&](int x, int y) {
+    ++i;
+    return x + y;
+  };
+  auto sf = std::move(f).asStdFunction();
+  static_assert(std::is_same<decltype(sf), std::function<void(int, int)>>::value,
+      "std::function has wrong type");
+  sf(42, 42);
+  EXPECT_EQ(1, i);
+}
+
+TEST(Function, asStdFunction_args_const) {
+  int i = 0;
+  folly::Function<void(int, int) const> f = [&](int x, int y) {
+    ++i;
+    return x + y;
+  };
+  auto sf = std::move(f).asStdFunction();
+  static_assert(std::is_same<decltype(sf), std::function<void(int, int)>>::value,
+      "std::function has wrong type");
+  sf(42, 42);
+  EXPECT_EQ(1, i);
+}