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);

Reply via email to