From b50d056347c7bec73b0fe23d923834437f6f0825 Mon Sep 17 00:00:00 2001 From: James Sedgwick Date: Tue, 5 Apr 2016 15:05:33 -0700 Subject: [PATCH] Function::asStdFunction() 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 | 14 ++++++++ folly/Function.h | 10 ++++++ folly/test/FunctionTest.cpp | 72 +++++++++++++++++++++++++++++++++++++ 3 files changed, 96 insertions(+) diff --git a/folly/Function-pre.h b/folly/Function-pre.h index 293efbcb..5e91fbb5 100644 --- a/folly/Function-pre.h +++ b/folly/Function-pre.h @@ -313,6 +313,20 @@ class FunctionTypeTraits::ExecutorMixin { InvokeFunctionPtr const invokePtr; }; +template +struct InvokeFromSharedPtr final { + std::shared_ptr ptr_; + + explicit InvokeFromSharedPtr(std::shared_ptr ptr) + : ptr_(std::move(ptr)) {} + + template + auto operator()(Args&&... args) + -> decltype((*ptr_)(std::forward(args)...)) { + return (*ptr_)(std::forward(args)...); + } +}; + } // namespace function } // namespace detail } // namespace folly diff --git a/folly/Function.h b/folly/Function.h index 1f6238ed..399efd54 100644 --- a/folly/Function.h +++ b/folly/Function.h @@ -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 asStdFunction() && { + return detail::function::InvokeFromSharedPtr( + std::make_shared(std::move(*this))); + } + /** * Constructs a `Function` by moving from one with different template * parameters with regards to const-ness, no-except-movability and internal diff --git a/folly/test/FunctionTest.cpp b/folly/test/FunctionTest.cpp index 6e073f24..f6f40e8c 100644 --- a/folly/test/FunctionTest.cpp +++ b/folly/test/FunctionTest.cpp @@ -1230,3 +1230,75 @@ TEST(Function, ConvertReturnType) { Function cf9 = std::move(f9); EXPECT_EQ(cf9().x, 66); } + +TEST(Function, asStdFunction_void) { + int i = 0; + folly::Function f = [&] { ++i; }; + auto sf = std::move(f).asStdFunction(); + static_assert(std::is_same>::value, + "std::function has wrong type"); + sf(); + EXPECT_EQ(1, i); +} + +TEST(Function, asStdFunction_void_const) { + int i = 0; + folly::Function f = [&] { ++i; }; + auto sf = std::move(f).asStdFunction(); + static_assert(std::is_same>::value, + "std::function has wrong type"); + sf(); + EXPECT_EQ(1, i); +} + +TEST(Function, asStdFunction_return) { + int i = 0; + folly::Function f = [&] { + ++i; + return 42; + }; + auto sf = std::move(f).asStdFunction(); + static_assert(std::is_same>::value, + "std::function has wrong type"); + EXPECT_EQ(42, sf()); + EXPECT_EQ(1, i); +} + +TEST(Function, asStdFunction_return_const) { + int i = 0; + folly::Function f = [&] { + ++i; + return 42; + }; + auto sf = std::move(f).asStdFunction(); + static_assert(std::is_same>::value, + "std::function has wrong type"); + EXPECT_EQ(42, sf()); + EXPECT_EQ(1, i); +} + +TEST(Function, asStdFunction_args) { + int i = 0; + folly::Function f = [&](int x, int y) { + ++i; + return x + y; + }; + auto sf = std::move(f).asStdFunction(); + static_assert(std::is_same>::value, + "std::function has wrong type"); + sf(42, 42); + EXPECT_EQ(1, i); +} + +TEST(Function, asStdFunction_args_const) { + int i = 0; + folly::Function f = [&](int x, int y) { + ++i; + return x + y; + }; + auto sf = std::move(f).asStdFunction(); + static_assert(std::is_same>::value, + "std::function has wrong type"); + sf(42, 42); + EXPECT_EQ(1, i); +} -- 2.34.1