Repository: mesos Updated Branches: refs/heads/master 62b472731 -> 6839897c5
Added `CallableOnce` support in `defer`. This allows `defer` result to be converted to `CallableOnce`, ensuring that bound arguments are moved, when call is made, and avoiding making copies of bound arguments. Review: https://reviews.apache.org/r/63637/ Project: http://git-wip-us.apache.org/repos/asf/mesos/repo Commit: http://git-wip-us.apache.org/repos/asf/mesos/commit/09b72e9b Tree: http://git-wip-us.apache.org/repos/asf/mesos/tree/09b72e9b Diff: http://git-wip-us.apache.org/repos/asf/mesos/diff/09b72e9b Branch: refs/heads/master Commit: 09b72e9bbf87793ce84df5d5f9d5f292c60fa5ee Parents: 62b4727 Author: Dmitry Zhuk <dz...@twopensource.com> Authored: Tue Dec 5 11:20:41 2017 -0800 Committer: Michael Park <mp...@apache.org> Committed: Tue Dec 5 11:20:41 2017 -0800 ---------------------------------------------------------------------- .../libprocess/include/process/deferred.hpp | 86 ++++++++++++++++++++ 3rdparty/libprocess/src/tests/process_tests.cpp | 28 +++++++ 2 files changed, 114 insertions(+) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/mesos/blob/09b72e9b/3rdparty/libprocess/include/process/deferred.hpp ---------------------------------------------------------------------- diff --git a/3rdparty/libprocess/include/process/deferred.hpp b/3rdparty/libprocess/include/process/deferred.hpp index 8beb2b3..eb6c5be 100644 --- a/3rdparty/libprocess/include/process/deferred.hpp +++ b/3rdparty/libprocess/include/process/deferred.hpp @@ -105,6 +105,22 @@ struct _Deferred }); } + operator lambda::CallableOnce<void()>() && + { + if (pid.isNone()) { + return lambda::CallableOnce<void()>(std::forward<F>(f)); + } + + Option<UPID> pid_ = pid; + + return lambda::CallableOnce<void()>( + lambda::partial( + [pid_](typename std::decay<F>::type&& f_) { + dispatch(pid_.get(), std::move(f_)); + }, + std::forward<F>(f))); + } + template <typename R> operator Deferred<R()>() && { @@ -137,6 +153,29 @@ struct _Deferred }); } + template <typename R> + operator lambda::CallableOnce<R()>() && + { + if (pid.isNone()) { + return lambda::CallableOnce<R()>(std::forward<F>(f)); + } + + Option<UPID> pid_ = pid; + + return lambda::CallableOnce<R()>( + lambda::partial( + [pid_](typename std::decay<F>::type&& f_) { + return dispatch(pid_.get(), std::move(f_)); + }, + std::forward<F>(f))); + } + +// Expands to lambda::_$(N+1). N is zero-based, and placeholders are one-based. +#define PLACEHOLDER(Z, N, DATA) CAT(lambda::_, INC(N)) + +// This assumes type and variable base names are `P` and `p` respectively. +#define FORWARD(Z, N, DATA) std::forward<P ## N>(p ## N) + // Due to a bug (http://gcc.gnu.org/bugzilla/show_bug.cgi?id=41933) // with variadic templates and lambdas, we still need to do // preprocessor expansions. In addition, due to a bug with clang (or @@ -180,6 +219,28 @@ struct _Deferred }); \ dispatch(pid_.get(), f__); \ }); \ + } \ + \ + template <ENUM_PARAMS(N, typename P)> \ + operator lambda::CallableOnce<void(ENUM_PARAMS(N, P))>() && \ + { \ + if (pid.isNone()) { \ + return lambda::CallableOnce<void(ENUM_PARAMS(N, P))>( \ + std::forward<F>(f)); \ + } \ + \ + Option<UPID> pid_ = pid; \ + \ + return lambda::CallableOnce<void(ENUM_PARAMS(N, P))>( \ + lambda::partial( \ + [pid_](typename std::decay<F>::type&& f_, \ + ENUM_BINARY_PARAMS(N, P, &&p)) { \ + lambda::CallableOnce<void()> f__( \ + lambda::partial(std::move(f_), ENUM(N, FORWARD, _))); \ + dispatch(pid_.get(), std::move(f__)); \ + }, \ + std::forward<F>(f), \ + ENUM(N, PLACEHOLDER, _))); \ } REPEAT_FROM_TO(1, 3, TEMPLATE, _) // Args A0 -> A1. @@ -222,11 +283,36 @@ struct _Deferred }); \ return dispatch(pid_.get(), f__); \ }); \ + } \ + \ + template <typename R, ENUM_PARAMS(N, typename P)> \ + operator lambda::CallableOnce<R(ENUM_PARAMS(N, P))>() && \ + { \ + if (pid.isNone()) { \ + return lambda::CallableOnce<R(ENUM_PARAMS(N, P))>( \ + std::forward<F>(f)); \ + } \ + \ + Option<UPID> pid_ = pid; \ + \ + return lambda::CallableOnce<R(ENUM_PARAMS(N, P))>( \ + lambda::partial( \ + [pid_](typename std::decay<F>::type&& f_, \ + ENUM_BINARY_PARAMS(N, P, &&p)) { \ + lambda::CallableOnce<R()> f__( \ + lambda::partial(std::move(f_), ENUM(N, FORWARD, _))); \ + return dispatch(pid_.get(), std::move(f__)); \ + }, \ + std::forward<F>(f), \ + ENUM(N, PLACEHOLDER, _))); \ } REPEAT_FROM_TO(1, 3, TEMPLATE, _) // Args A0 -> A1. #undef TEMPLATE +#undef FORWARD +#undef PLACEHOLDER + private: friend class Executor; http://git-wip-us.apache.org/repos/asf/mesos/blob/09b72e9b/3rdparty/libprocess/src/tests/process_tests.cpp ---------------------------------------------------------------------- diff --git a/3rdparty/libprocess/src/tests/process_tests.cpp b/3rdparty/libprocess/src/tests/process_tests.cpp index 4a3e3ca..58741b2 100644 --- a/3rdparty/libprocess/src/tests/process_tests.cpp +++ b/3rdparty/libprocess/src/tests/process_tests.cpp @@ -169,6 +169,9 @@ public: void func5(MoveOnly&& mo) { func5_(mo); } MOCK_METHOD1(func5_, void(const MoveOnly&)); + + bool func6(MoveOnly&& m1, MoveOnly&& m2, bool b) { return func6_(m1, m2, b); } + MOCK_METHOD3(func6_, bool(const MoveOnly&, const MoveOnly&, bool)); }; @@ -223,6 +226,11 @@ TEST(ProcessTest, THREADSAFE_Defer1) EXPECT_CALL(process, func4(_, _)) .WillRepeatedly(ReturnArg<0>()); + EXPECT_CALL(process, func5_(_)); + + EXPECT_CALL(process, func6_(_, _, _)) + .WillRepeatedly(ReturnArg<2>()); + PID<DispatchProcess> pid = spawn(&process); ASSERT_FALSE(!pid); @@ -270,6 +278,26 @@ TEST(ProcessTest, THREADSAFE_Defer1) EXPECT_TRUE(future.get()); } + { + lambda::CallableOnce<void()> func5 = + defer(pid, &DispatchProcess::func5, MoveOnly()); + std::move(func5)(); + } + + { + lambda::CallableOnce<Future<bool>(MoveOnly&&)> func6 = + defer(pid, &DispatchProcess::func6, MoveOnly(), lambda::_1, true); + future = std::move(func6)(MoveOnly()); + EXPECT_TRUE(future.get()); + } + + { + lambda::CallableOnce<Future<bool>(MoveOnly&&)> func6 = + defer(pid, &DispatchProcess::func6, MoveOnly(), lambda::_1, false); + future = std::move(func6)(MoveOnly()); + EXPECT_FALSE(future.get()); + } + // Only take const &! terminate(pid);