Reduced copying in `defer`, `dispatch` and `Future`.

This reduces number of copies made for each parameter in
a piece of code like this:

```
future.then(defer(pid, &SomeProcess::someMethod, param1, param2));
```

For the objects that do not support move semantics
(e.g., protobuf messages), number of copies is reduced from 8-10 to 6.
If move semantics is supported, then number of copies is reduced from
6-7 to 1 if parameter is passed with `std::move`, or 2 otherwise.

Review: https://reviews.apache.org/r/60003/


Project: http://git-wip-us.apache.org/repos/asf/mesos/repo
Commit: http://git-wip-us.apache.org/repos/asf/mesos/commit/f8e4f11e
Tree: http://git-wip-us.apache.org/repos/asf/mesos/tree/f8e4f11e
Diff: http://git-wip-us.apache.org/repos/asf/mesos/diff/f8e4f11e

Branch: refs/heads/master
Commit: f8e4f11e796b2b0d9bd101a7eb6f106e72cbaee1
Parents: 2ce2a0a
Author: Dmitry Zhuk <dz...@twopensource.com>
Authored: Mon Aug 7 11:01:04 2017 -0700
Committer: Michael Park <mp...@apache.org>
Committed: Tue Aug 8 13:33:15 2017 -0700

----------------------------------------------------------------------
 3rdparty/libprocess/include/process/defer.hpp   |  81 +++++---
 .../libprocess/include/process/deferred.hpp     | 184 ++++++++++---------
 .../libprocess/include/process/dispatch.hpp     |  84 +++++----
 3rdparty/libprocess/include/process/future.hpp  |  45 ++---
 3rdparty/libprocess/include/process/http.hpp    |   3 +-
 3rdparty/libprocess/src/tests/benchmarks.cpp    |  86 +++++++++
 6 files changed, 318 insertions(+), 165 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/f8e4f11e/3rdparty/libprocess/include/process/defer.hpp
----------------------------------------------------------------------
diff --git a/3rdparty/libprocess/include/process/defer.hpp 
b/3rdparty/libprocess/include/process/defer.hpp
index 7f3369e..9457080 100644
--- a/3rdparty/libprocess/include/process/defer.hpp
+++ b/3rdparty/libprocess/include/process/defer.hpp
@@ -58,20 +58,31 @@ Deferred<void()> defer(const Process<T>* process, void 
(T::*method)())
 // libc++) we can't use std::bind with a std::function so we have to
 // explicitly use the std::function<R(P...)>::operator() (see
 // 
http://stackoverflow.com/questions/20097616/stdbind-to-a-stdfunction-crashes-with-clang).
+
+// This assumes that type and variable base names are `A` and `a` respectively.
+#define FORWARD(Z, N, DATA) std::forward<A ## N>(a ## N)
+
 #define TEMPLATE(Z, N, DATA)                                            \
   template <typename T,                                                 \
             ENUM_PARAMS(N, typename P),                                 \
             ENUM_PARAMS(N, typename A)>                                 \
   auto defer(const PID<T>& pid,                                         \
              void (T::*method)(ENUM_PARAMS(N, P)),                      \
-             ENUM_BINARY_PARAMS(N, A, a))                               \
-    -> _Deferred<decltype(std::bind(&std::function<void(ENUM_PARAMS(N, 
P))>::operator(), std::function<void(ENUM_PARAMS(N, P))>(), ENUM_PARAMS(N, 
a)))> /* NOLINT(whitespace/line_length) */ \
+             ENUM_BINARY_PARAMS(N, A, &&a))                             \
+    -> _Deferred<decltype(                                              \
+         std::bind(                                                     \
+           &std::function<void(ENUM_PARAMS(N, P))>::operator(),         \
+           std::function<void(ENUM_PARAMS(N, P))>(),                    \
+           ENUM(N, FORWARD, _)))>                                       \
   {                                                                     \
     std::function<void(ENUM_PARAMS(N, P))> f(                           \
         [=](ENUM_BINARY_PARAMS(N, P, p)) {                              \
           dispatch(pid, method, ENUM_PARAMS(N, p));                     \
         });                                                             \
-    return std::bind(&std::function<void(ENUM_PARAMS(N, P))>::operator(), 
std::move(f), ENUM_PARAMS(N, a)); /* NOLINT(whitespace/line_length) */ \
+    return std::bind(                                                   \
+        &std::function<void(ENUM_PARAMS(N, P))>::operator(),            \
+        std::move(f),                                                   \
+        ENUM(N, FORWARD, _));                                           \
   }                                                                     \
                                                                         \
   template <typename T,                                                 \
@@ -79,10 +90,10 @@ Deferred<void()> defer(const Process<T>* process, void 
(T::*method)())
             ENUM_PARAMS(N, typename A)>                                 \
   auto defer(const Process<T>& process,                                 \
              void (T::*method)(ENUM_PARAMS(N, P)),                      \
-             ENUM_BINARY_PARAMS(N, A, a))                               \
-    -> decltype(defer(process.self(), method, ENUM_PARAMS(N, a)))       \
+             ENUM_BINARY_PARAMS(N, A, &&a))                             \
+    -> decltype(defer(process.self(), method, ENUM(N, FORWARD, _)))     \
   {                                                                     \
-    return defer(process.self(), method, ENUM_PARAMS(N, a));            \
+    return defer(process.self(), method, ENUM(N, FORWARD, _));          \
   }                                                                     \
                                                                         \
   template <typename T,                                                 \
@@ -90,10 +101,10 @@ Deferred<void()> defer(const Process<T>* process, void 
(T::*method)())
             ENUM_PARAMS(N, typename A)>                                 \
   auto defer(const Process<T>* process,                                 \
              void (T::*method)(ENUM_PARAMS(N, P)),                      \
-             ENUM_BINARY_PARAMS(N, A, a))                               \
-    -> decltype(defer(process->self(), method, ENUM_PARAMS(N, a)))      \
+             ENUM_BINARY_PARAMS(N, A, &&a))                             \
+    -> decltype(defer(process->self(), method, ENUM(N, FORWARD, _)))    \
   {                                                                     \
-    return defer(process->self(), method, ENUM_PARAMS(N, a));           \
+    return defer(process->self(), method, ENUM(N, FORWARD, _));         \
   }
 
   REPEAT_FROM_TO(1, 12, TEMPLATE, _) // Args A0 -> A10.
@@ -127,14 +138,21 @@ Deferred<Future<R>()> defer(const Process<T>* process, 
Future<R> (T::*method)())
             ENUM_PARAMS(N, typename A)>                                 \
   auto defer(const PID<T>& pid,                                         \
              Future<R> (T::*method)(ENUM_PARAMS(N, P)),                 \
-             ENUM_BINARY_PARAMS(N, A, a))                               \
-    -> _Deferred<decltype(std::bind(&std::function<Future<R>(ENUM_PARAMS(N, 
P))>::operator(), std::function<Future<R>(ENUM_PARAMS(N, P))>(), ENUM_PARAMS(N, 
a)))> /* NOLINT(whitespace/line_length) */ \
+             ENUM_BINARY_PARAMS(N, A, &&a))                             \
+    -> _Deferred<decltype(                                              \
+         std::bind(                                                     \
+           &std::function<Future<R>(ENUM_PARAMS(N, P))>::operator(),    \
+           std::function<Future<R>(ENUM_PARAMS(N, P))>(),               \
+           ENUM(N, FORWARD, _)))>                                       \
   {                                                                     \
     std::function<Future<R>(ENUM_PARAMS(N, P))> f(                      \
         [=](ENUM_BINARY_PARAMS(N, P, p)) {                              \
           return dispatch(pid, method, ENUM_PARAMS(N, p));              \
         });                                                             \
-    return std::bind(&std::function<Future<R>(ENUM_PARAMS(N, P))>::operator(), 
std::move(f), ENUM_PARAMS(N, a)); /* NOLINT(whitespace/line_length) */ \
+    return std::bind(                                                   \
+        &std::function<Future<R>(ENUM_PARAMS(N, P))>::operator(),       \
+        std::move(f),                                                   \
+        ENUM(N, FORWARD, _));                                           \
   }                                                                     \
                                                                         \
   template <typename R,                                                 \
@@ -143,10 +161,10 @@ Deferred<Future<R>()> defer(const Process<T>* process, 
Future<R> (T::*method)())
             ENUM_PARAMS(N, typename A)>                                 \
   auto defer(const Process<T>& process,                                 \
              Future<R> (T::*method)(ENUM_PARAMS(N, P)),                 \
-             ENUM_BINARY_PARAMS(N, A, a))                               \
-    -> decltype(defer(process.self(), method, ENUM_PARAMS(N, a)))       \
+             ENUM_BINARY_PARAMS(N, A, &&a))                             \
+    -> decltype(defer(process.self(), method, ENUM(N, FORWARD, _)))     \
   {                                                                     \
-    return defer(process.self(), method, ENUM_PARAMS(N, a));            \
+    return defer(process.self(), method, ENUM(N, FORWARD, _));          \
   }                                                                     \
                                                                         \
   template <typename R,                                                 \
@@ -155,10 +173,10 @@ Deferred<Future<R>()> defer(const Process<T>* process, 
Future<R> (T::*method)())
             ENUM_PARAMS(N, typename A)>                                 \
   auto defer(const Process<T>* process,                                 \
              Future<R> (T::*method)(ENUM_PARAMS(N, P)),                 \
-             ENUM_BINARY_PARAMS(N, A, a))                               \
-    -> decltype(defer(process->self(), method, ENUM_PARAMS(N, a)))      \
+             ENUM_BINARY_PARAMS(N, A, &&a))                             \
+    -> decltype(defer(process->self(), method, ENUM(N, FORWARD, _)))    \
   {                                                                     \
-    return defer(process->self(), method, ENUM_PARAMS(N, a));           \
+    return defer(process->self(), method, ENUM(N, FORWARD, _));         \
   }
 
   REPEAT_FROM_TO(1, 12, TEMPLATE, _) // Args A0 -> A10.
@@ -192,14 +210,21 @@ Deferred<Future<R>()> defer(const Process<T>* process, R 
(T::*method)())
             ENUM_PARAMS(N, typename A)>                                 \
   auto defer(const PID<T>& pid,                                         \
              R (T::*method)(ENUM_PARAMS(N, P)),                         \
-             ENUM_BINARY_PARAMS(N, A, a))                               \
-    -> _Deferred<decltype(std::bind(&std::function<Future<R>(ENUM_PARAMS(N, 
P))>::operator(), std::function<Future<R>(ENUM_PARAMS(N, P))>(), ENUM_PARAMS(N, 
a)))> /* NOLINT(whitespace/line_length) */ \
+             ENUM_BINARY_PARAMS(N, A, &&a))                             \
+    -> _Deferred<decltype(                                              \
+         std::bind(                                                     \
+           &std::function<Future<R>(ENUM_PARAMS(N, P))>::operator(),    \
+           std::function<Future<R>(ENUM_PARAMS(N, P))>(),               \
+           ENUM(N, FORWARD, _)))>                                       \
   {                                                                     \
     std::function<Future<R>(ENUM_PARAMS(N, P))> f(                      \
         [=](ENUM_BINARY_PARAMS(N, P, p)) {                              \
           return dispatch(pid, method, ENUM_PARAMS(N, p));              \
         });                                                             \
-    return std::bind(&std::function<Future<R>(ENUM_PARAMS(N, P))>::operator(), 
std::move(f), ENUM_PARAMS(N, a)); /* NOLINT(whitespace/line_length) */ \
+    return std::bind(                                                   \
+        &std::function<Future<R>(ENUM_PARAMS(N, P))>::operator(),       \
+        std::move(f),                                                   \
+        ENUM(N, FORWARD, _));                                           \
   }                                                                     \
                                                                         \
   template <typename R,                                                 \
@@ -209,10 +234,10 @@ Deferred<Future<R>()> defer(const Process<T>* process, R 
(T::*method)())
   auto                                                                  \
   defer(const Process<T>& process,                                      \
         R (T::*method)(ENUM_PARAMS(N, P)),                              \
-        ENUM_BINARY_PARAMS(N, A, a))                                    \
-    -> decltype(defer(process.self(), method, ENUM_PARAMS(N, a)))       \
+        ENUM_BINARY_PARAMS(N, A, &&a))                                  \
+    -> decltype(defer(process.self(), method, ENUM(N, FORWARD, _)))     \
   {                                                                     \
-    return defer(process.self(), method, ENUM_PARAMS(N, a));            \
+    return defer(process.self(), method, ENUM(N, FORWARD, _));          \
   }                                                                     \
                                                                         \
   template <typename R,                                                 \
@@ -222,15 +247,17 @@ Deferred<Future<R>()> defer(const Process<T>* process, R 
(T::*method)())
   auto                                                                  \
   defer(const Process<T>* process,                                      \
         R (T::*method)(ENUM_PARAMS(N, P)),                              \
-        ENUM_BINARY_PARAMS(N, A, a))                                    \
-    -> decltype(defer(process->self(), method, ENUM_PARAMS(N, a)))      \
+        ENUM_BINARY_PARAMS(N, A, &&a))                                  \
+    -> decltype(defer(process->self(), method, ENUM(N, FORWARD, _)))    \
   {                                                                     \
-    return defer(process->self(), method, ENUM_PARAMS(N, a));           \
+    return defer(process->self(), method, ENUM(N, FORWARD, _));         \
   }
 
   REPEAT_FROM_TO(1, 12, TEMPLATE, _) // Args A0 -> A10.
 #undef TEMPLATE
 
+#undef FORWARD
+
 
 // Now we define defer calls for functors (with and without a PID):
 

http://git-wip-us.apache.org/repos/asf/mesos/blob/f8e4f11e/3rdparty/libprocess/include/process/deferred.hpp
----------------------------------------------------------------------
diff --git a/3rdparty/libprocess/include/process/deferred.hpp 
b/3rdparty/libprocess/include/process/deferred.hpp
index e446621..af65ead 100644
--- a/3rdparty/libprocess/include/process/deferred.hpp
+++ b/3rdparty/libprocess/include/process/deferred.hpp
@@ -63,7 +63,9 @@ private:
 template <typename F>
 struct _Deferred
 {
-  operator Deferred<void()>() const
+  // We expect that conversion operators are invoked on rvalues only,
+  // as _Deferred is supposed to be used directly as a result of defer call.
+  operator Deferred<void()>() &&
   {
     // The 'pid' differentiates an already dispatched functor versus
     // one which still needs to be dispatched (which is done
@@ -74,13 +76,13 @@ struct _Deferred
     // arguments which will just be dropped when invoking the
     // underlying bound function).
     if (pid.isNone()) {
-      return std::function<void()>(f);
+      return std::function<void()>(std::forward<F>(f));
     }
 
     // We need to explicitly copy the members otherwise we'll
     // implicitly copy 'this' which might not exist at invocation.
     Option<UPID> pid_ = pid;
-    F f_ = f;
+    F&& f_ = std::forward<F>(f);
 
     return std::function<void()>(
         [=]() {
@@ -88,14 +90,14 @@ struct _Deferred
         });
   }
 
-  operator std::function<void()>() const
+  operator std::function<void()>() &&
   {
     if (pid.isNone()) {
-      return std::function<void()>(f);
+      return std::function<void()>(std::forward<F>(f));
     }
 
     Option<UPID> pid_ = pid;
-    F f_ = f;
+    F&& f_ = std::forward<F>(f);
 
     return std::function<void()>(
         [=]() {
@@ -104,14 +106,14 @@ struct _Deferred
   }
 
   template <typename R>
-  operator Deferred<R()>() const
+  operator Deferred<R()>() &&
   {
     if (pid.isNone()) {
-      return std::function<R()>(f);
+      return std::function<R()>(std::forward<F>(f));
     }
 
     Option<UPID> pid_ = pid;
-    F f_ = f;
+    F&& f_ = std::forward<F>(f);
 
     return std::function<R()>(
         [=]() {
@@ -120,14 +122,14 @@ struct _Deferred
   }
 
   template <typename R>
-  operator std::function<R()>() const
+  operator std::function<R()>() &&
   {
     if (pid.isNone()) {
-      return std::function<R()>(f);
+      return std::function<R()>(std::forward<F>(f));
     }
 
     Option<UPID> pid_ = pid;
-    F f_ = f;
+    F&& f_ = std::forward<F>(f);
 
     return std::function<R()>(
         [=]() {
@@ -141,43 +143,43 @@ struct _Deferred
   // libc++) we can't use std::bind with a std::function so we have to
   // explicitly use the std::function<R(P...)>::operator() (see
   // 
http://stackoverflow.com/questions/20097616/stdbind-to-a-stdfunction-crashes-with-clang).
-#define TEMPLATE(Z, N, DATA)                                            \
-  template <ENUM_PARAMS(N, typename P)>                                 \
-  operator Deferred<void(ENUM_PARAMS(N, P))>() const                    \
-  {                                                                     \
-    if (pid.isNone()) {                                                 \
-      return std::function<void(ENUM_PARAMS(N, P))>(f);                 \
-    }                                                                   \
-                                                                        \
-    Option<UPID> pid_ = pid;                                            \
-    F f_ = f;                                                           \
-                                                                        \
-    return std::function<void(ENUM_PARAMS(N, P))>(                      \
-        [=](ENUM_BINARY_PARAMS(N, P, p)) {                              \
-          std::function<void()> f__([=]() {                             \
-            f_(ENUM_PARAMS(N, p));                                      \
-          });                                                           \
-          dispatch(pid_.get(), f__);                                    \
-        });                                                             \
-  }                                                                     \
-                                                                        \
-  template <ENUM_PARAMS(N, typename P)>                                 \
-  operator std::function<void(ENUM_PARAMS(N, P))>() const               \
-  {                                                                     \
-    if (pid.isNone()) {                                                 \
-      return std::function<void(ENUM_PARAMS(N, P))>(f);                 \
-    }                                                                   \
-                                                                        \
-    Option<UPID> pid_ = pid;                                            \
-    F f_ = f;                                                           \
-                                                                        \
-    return std::function<void(ENUM_PARAMS(N, P))>(                      \
-        [=](ENUM_BINARY_PARAMS(N, P, p)) {                              \
-          std::function<void()> f__([=]() {                             \
-            f_(ENUM_PARAMS(N, p));                                      \
-          });                                                           \
-          dispatch(pid_.get(), f__);                                    \
-        });                                                             \
+#define TEMPLATE(Z, N, DATA)                                             \
+  template <ENUM_PARAMS(N, typename P)>                                  \
+  operator Deferred<void(ENUM_PARAMS(N, P))>() &&                        \
+  {                                                                      \
+    if (pid.isNone()) {                                                  \
+      return std::function<void(ENUM_PARAMS(N, P))>(std::forward<F>(f)); \
+    }                                                                    \
+                                                                         \
+    Option<UPID> pid_ = pid;                                             \
+    F&& f_ = std::forward<F>(f);                                         \
+                                                                         \
+    return std::function<void(ENUM_PARAMS(N, P))>(                       \
+        [=](ENUM_BINARY_PARAMS(N, P, p)) {                               \
+          std::function<void()> f__([=]() {                              \
+            f_(ENUM_PARAMS(N, p));                                       \
+          });                                                            \
+          dispatch(pid_.get(), f__);                                     \
+        });                                                              \
+  }                                                                      \
+                                                                         \
+  template <ENUM_PARAMS(N, typename P)>                                  \
+  operator std::function<void(ENUM_PARAMS(N, P))>() &&                   \
+  {                                                                      \
+    if (pid.isNone()) {                                                  \
+      return std::function<void(ENUM_PARAMS(N, P))>(std::forward<F>(f)); \
+    }                                                                    \
+                                                                         \
+    Option<UPID> pid_ = pid;                                             \
+    F&& f_ = std::forward<F>(f);                                         \
+                                                                         \
+    return std::function<void(ENUM_PARAMS(N, P))>(                       \
+        [=](ENUM_BINARY_PARAMS(N, P, p)) {                               \
+          std::function<void()> f__([=]() {                              \
+            f_(ENUM_PARAMS(N, p));                                       \
+          });                                                            \
+          dispatch(pid_.get(), f__);                                     \
+        });                                                              \
   }
 
   REPEAT_FROM_TO(1, 12, TEMPLATE, _) // Args A0 -> A10.
@@ -185,14 +187,14 @@ struct _Deferred
 
 #define TEMPLATE(Z, N, DATA)                                            \
   template <typename R, ENUM_PARAMS(N, typename P)>                     \
-  operator Deferred<R(ENUM_PARAMS(N, P))>() const                       \
+  operator Deferred<R(ENUM_PARAMS(N, P))>() &&                          \
   {                                                                     \
     if (pid.isNone()) {                                                 \
-      return std::function<R(ENUM_PARAMS(N, P))>(f);                    \
+      return std::function<R(ENUM_PARAMS(N, P))>(std::forward<F>(f));   \
     }                                                                   \
                                                                         \
     Option<UPID> pid_ = pid;                                            \
-    F f_ = f;                                                           \
+    F&& f_ = std::forward<F>(f);                                        \
                                                                         \
     return std::function<R(ENUM_PARAMS(N, P))>(                         \
         [=](ENUM_BINARY_PARAMS(N, P, p)) {                              \
@@ -204,14 +206,14 @@ struct _Deferred
   }                                                                     \
                                                                         \
   template <typename R, ENUM_PARAMS(N, typename P)>                     \
-  operator std::function<R(ENUM_PARAMS(N, P))>() const                  \
+  operator std::function<R(ENUM_PARAMS(N, P))>() &&                     \
   {                                                                     \
     if (pid.isNone()) {                                                 \
-      return std::function<R(ENUM_PARAMS(N, P))>(f);                    \
+      return std::function<R(ENUM_PARAMS(N, P))>(std::forward<F>(f));   \
     }                                                                   \
                                                                         \
     Option<UPID> pid_ = pid;                                            \
-    F f_ = f;                                                           \
+    F&& f_ = std::forward<F>(f);                                        \
                                                                         \
     return std::function<R(ENUM_PARAMS(N, P))>(                         \
         [=](ENUM_BINARY_PARAMS(N, P, p)) {                              \
@@ -231,47 +233,63 @@ private:
   template <typename G>
   friend _Deferred<G> defer(const UPID& pid, G&& g);
 
-#define TEMPLATE(Z, N, DATA)                                            \
-  template <typename T,                                                 \
-            ENUM_PARAMS(N, typename P),                                 \
-            ENUM_PARAMS(N, typename A)>                                 \
-  friend auto defer(const PID<T>& pid,                                  \
-             void (T::*method)(ENUM_PARAMS(N, P)),                      \
-             ENUM_BINARY_PARAMS(N, A, a))                               \
-    -> _Deferred<decltype(std::bind(&std::function<void(ENUM_PARAMS(N, 
P))>::operator(), std::function<void(ENUM_PARAMS(N, P))>(), ENUM_PARAMS(N, 
a)))>; // NOLINT(whitespace/line_length)
+// This assumes type and variable base names are `A` and `a` respectively.
+#define FORWARD(Z, N, DATA) std::forward<A ## N>(a ## N)
+
+#define TEMPLATE(Z, N, DATA)                                             \
+  template <typename T,                                                  \
+            ENUM_PARAMS(N, typename P),                                  \
+            ENUM_PARAMS(N, typename A)>                                  \
+  friend auto defer(const PID<T>& pid,                                   \
+                    void (T::*method)(ENUM_PARAMS(N, P)),                \
+                    ENUM_BINARY_PARAMS(N, A, &&a))                       \
+    -> _Deferred<decltype(                                               \
+           std::bind(                                                    \
+               &std::function<void(ENUM_PARAMS(N, P))>::operator(),      \
+               std::function<void(ENUM_PARAMS(N, P))>(),                 \
+               ENUM(N, FORWARD, _)))>;
 
   REPEAT_FROM_TO(1, 12, TEMPLATE, _) // Args A0 -> A10.
 #undef TEMPLATE
 
-#define TEMPLATE(Z, N, DATA)                                            \
-  template <typename R,                                                 \
-            typename T,                                                 \
-            ENUM_PARAMS(N, typename P),                                 \
-            ENUM_PARAMS(N, typename A)>                                 \
-  friend auto defer(const PID<T>& pid,                                  \
-             Future<R> (T::*method)(ENUM_PARAMS(N, P)),                 \
-             ENUM_BINARY_PARAMS(N, A, a))                               \
-    -> _Deferred<decltype(std::bind(&std::function<Future<R>(ENUM_PARAMS(N, 
P))>::operator(), std::function<Future<R>(ENUM_PARAMS(N, P))>(), ENUM_PARAMS(N, 
a)))>; // NOLINT(whitespace/line_length)
+#define TEMPLATE(Z, N, DATA)                                             \
+  template <typename R,                                                  \
+            typename T,                                                  \
+            ENUM_PARAMS(N, typename P),                                  \
+            ENUM_PARAMS(N, typename A)>                                  \
+  friend auto defer(const PID<T>& pid,                                   \
+                    Future<R> (T::*method)(ENUM_PARAMS(N, P)),           \
+                    ENUM_BINARY_PARAMS(N, A, &&a))                       \
+    -> _Deferred<decltype(                                               \
+           std::bind(                                                    \
+               &std::function<Future<R>(ENUM_PARAMS(N, P))>::operator(), \
+               std::function<Future<R>(ENUM_PARAMS(N, P))>(),            \
+               ENUM(N, FORWARD, _)))>;
 
   REPEAT_FROM_TO(1, 12, TEMPLATE, _) // Args A0 -> A10.
 #undef TEMPLATE
 
-#define TEMPLATE(Z, N, DATA)                                            \
-  template <typename R,                                                 \
-            typename T,                                                 \
-            ENUM_PARAMS(N, typename P),                                 \
-            ENUM_PARAMS(N, typename A)>                                 \
-  friend auto defer(const PID<T>& pid,                                  \
-             R (T::*method)(ENUM_PARAMS(N, P)),                         \
-             ENUM_BINARY_PARAMS(N, A, a))                               \
-    -> _Deferred<decltype(std::bind(&std::function<Future<R>(ENUM_PARAMS(N, 
P))>::operator(), std::function<Future<R>(ENUM_PARAMS(N, P))>(), ENUM_PARAMS(N, 
a)))>; // NOLINT(whitespace/line_length)
+#define TEMPLATE(Z, N, DATA)                                             \
+  template <typename R,                                                  \
+            typename T,                                                  \
+            ENUM_PARAMS(N, typename P),                                  \
+            ENUM_PARAMS(N, typename A)>                                  \
+  friend auto defer(const PID<T>& pid,                                   \
+                    R (T::*method)(ENUM_PARAMS(N, P)),                   \
+                    ENUM_BINARY_PARAMS(N, A, &&a))                       \
+    -> _Deferred<decltype(                                               \
+         std::bind(                                                      \
+           &std::function<Future<R>(ENUM_PARAMS(N, P))>::operator(),     \
+           std::function<Future<R>(ENUM_PARAMS(N, P))>(),                \
+           ENUM(N, FORWARD, _)))>;
 
   REPEAT_FROM_TO(1, 12, TEMPLATE, _) // Args A0 -> A10.
 #undef TEMPLATE
+#undef FORWARD
 
-  _Deferred(const UPID& pid, F f) : pid(pid), f(f) {}
+  _Deferred(const UPID& pid, F&& f) : pid(pid), f(std::forward<F>(f)) {}
 
-  /*implicit*/ _Deferred(F f) : f(f) {}
+  /*implicit*/ _Deferred(F&& f) : f(std::forward<F>(f)) {}
 
   Option<UPID> pid;
   F f;

http://git-wip-us.apache.org/repos/asf/mesos/blob/f8e4f11e/3rdparty/libprocess/include/process/dispatch.hpp
----------------------------------------------------------------------
diff --git a/3rdparty/libprocess/include/process/dispatch.hpp 
b/3rdparty/libprocess/include/process/dispatch.hpp
index 3a07938..096cae0 100644
--- a/3rdparty/libprocess/include/process/dispatch.hpp
+++ b/3rdparty/libprocess/include/process/dispatch.hpp
@@ -19,6 +19,7 @@
 
 #include <process/process.hpp>
 
+#include <stout/lambda.hpp>
 #include <stout/preprocessor.hpp>
 #include <stout/result_of.hpp>
 
@@ -183,6 +184,11 @@ void dispatch(const Process<T>* process, void 
(T::*method)())
 // 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.
+
+// The following assumes base names for type and variable are `A` and `a`.
+#define FORWARD(Z, N, DATA) std::forward<A ## N>(a ## N)
+#define DECL(Z, N, DATA) typename std::decay<A ## N>::type& a ## N
+
 #define TEMPLATE(Z, N, DATA)                                            \
   template <typename T,                                                 \
             ENUM_PARAMS(N, typename P),                                 \
@@ -190,16 +196,19 @@ void dispatch(const Process<T>* process, void 
(T::*method)())
   void dispatch(                                                        \
       const PID<T>& pid,                                                \
       void (T::*method)(ENUM_PARAMS(N, P)),                             \
-      ENUM_BINARY_PARAMS(N, A, a))                                      \
+      ENUM_BINARY_PARAMS(N, A, &&a))                                    \
   {                                                                     \
     std::shared_ptr<std::function<void(ProcessBase*)>> f(               \
         new std::function<void(ProcessBase*)>(                          \
-            [=](ProcessBase* process) {                                 \
-              assert(process != nullptr);                               \
-              T* t = dynamic_cast<T*>(process);                         \
-              assert(t != nullptr);                                     \
-              (t->*method)(ENUM_PARAMS(N, a));                          \
-            }));                                                        \
+            std::bind([method](ENUM(N, DECL, _),                        \
+                               ProcessBase* process) {                  \
+                        assert(process != nullptr);                     \
+                        T* t = dynamic_cast<T*>(process);               \
+                        assert(t != nullptr);                           \
+                        (t->*method)(ENUM_PARAMS(N, a));                \
+                      },                                                \
+                      ENUM(N, FORWARD, _),                              \
+                      lambda::_1)));                                    \
                                                                         \
     internal::dispatch(pid, f, &typeid(method));                        \
   }                                                                     \
@@ -210,9 +219,9 @@ void dispatch(const Process<T>* process, void 
(T::*method)())
   void dispatch(                                                        \
       const Process<T>& process,                                        \
       void (T::*method)(ENUM_PARAMS(N, P)),                             \
-      ENUM_BINARY_PARAMS(N, A, a))                                      \
+      ENUM_BINARY_PARAMS(N, A, &&a))                                    \
   {                                                                     \
-    dispatch(process.self(), method, ENUM_PARAMS(N, a));                \
+    dispatch(process.self(), method, ENUM(N, FORWARD, _));              \
   }                                                                     \
                                                                         \
   template <typename T,                                                 \
@@ -221,9 +230,9 @@ void dispatch(const Process<T>* process, void 
(T::*method)())
   void dispatch(                                                        \
       const Process<T>* process,                                        \
       void (T::*method)(ENUM_PARAMS(N, P)),                             \
-      ENUM_BINARY_PARAMS(N, A, a))                                      \
+      ENUM_BINARY_PARAMS(N, A, &&a))                                    \
   {                                                                     \
-    dispatch(process->self(), method, ENUM_PARAMS(N, a));               \
+    dispatch(process->self(), method, ENUM(N, FORWARD, _));             \
   }
 
   REPEAT_FROM_TO(1, 12, TEMPLATE, _) // Args A0 -> A10.
@@ -271,18 +280,22 @@ Future<R> dispatch(const Process<T>* process, Future<R> 
(T::*method)())
   Future<R> dispatch(                                                   \
       const PID<T>& pid,                                                \
       Future<R> (T::*method)(ENUM_PARAMS(N, P)),                        \
-      ENUM_BINARY_PARAMS(N, A, a))                                      \
+      ENUM_BINARY_PARAMS(N, A, &&a))                                    \
   {                                                                     \
     std::shared_ptr<Promise<R>> promise(new Promise<R>());              \
                                                                         \
     std::shared_ptr<std::function<void(ProcessBase*)>> f(               \
         new std::function<void(ProcessBase*)>(                          \
-            [=](ProcessBase* process) {                                 \
-              assert(process != nullptr);                               \
-              T* t = dynamic_cast<T*>(process);                         \
-              assert(t != nullptr);                                     \
-              promise->associate((t->*method)(ENUM_PARAMS(N, a)));      \
-            }));                                                        \
+            std::bind([promise, method](ENUM(N, DECL, _),               \
+                                        ProcessBase* process) {         \
+                        assert(process != nullptr);                     \
+                        T* t = dynamic_cast<T*>(process);               \
+                        assert(t != nullptr);                           \
+                        promise->associate(                             \
+                            (t->*method)(ENUM_PARAMS(N, a)));           \
+                      },                                                \
+                      ENUM(N, FORWARD, _),                              \
+                      lambda::_1)));                                    \
                                                                         \
     internal::dispatch(pid, f, &typeid(method));                        \
                                                                         \
@@ -296,9 +309,9 @@ Future<R> dispatch(const Process<T>* process, Future<R> 
(T::*method)())
   Future<R> dispatch(                                                   \
       const Process<T>& process,                                        \
       Future<R> (T::*method)(ENUM_PARAMS(N, P)),                        \
-      ENUM_BINARY_PARAMS(N, A, a))                                      \
+      ENUM_BINARY_PARAMS(N, A, &&a))                                    \
   {                                                                     \
-    return dispatch(process.self(), method, ENUM_PARAMS(N, a));         \
+    return dispatch(process.self(), method, ENUM(N, FORWARD, _));       \
   }                                                                     \
                                                                         \
   template <typename R,                                                 \
@@ -308,9 +321,9 @@ Future<R> dispatch(const Process<T>* process, Future<R> 
(T::*method)())
   Future<R> dispatch(                                                   \
       const Process<T>* process,                                        \
       Future<R> (T::*method)(ENUM_PARAMS(N, P)),                        \
-      ENUM_BINARY_PARAMS(N, A, a))                                      \
+      ENUM_BINARY_PARAMS(N, A, &&a))                                    \
   {                                                                     \
-    return dispatch(process->self(), method, ENUM_PARAMS(N, a));        \
+    return dispatch(process->self(), method, ENUM(N, FORWARD, _));      \
   }
 
   REPEAT_FROM_TO(1, 12, TEMPLATE, _) // Args A0 -> A10.
@@ -358,18 +371,21 @@ Future<R> dispatch(const Process<T>* process, R 
(T::*method)())
   Future<R> dispatch(                                                   \
       const PID<T>& pid,                                                \
       R (T::*method)(ENUM_PARAMS(N, P)),                                \
-      ENUM_BINARY_PARAMS(N, A, a))                                      \
+      ENUM_BINARY_PARAMS(N, A, &&a))                                    \
   {                                                                     \
     std::shared_ptr<Promise<R>> promise(new Promise<R>());              \
                                                                         \
     std::shared_ptr<std::function<void(ProcessBase*)>> f(               \
         new std::function<void(ProcessBase*)>(                          \
-            [=](ProcessBase* process) {                                 \
-              assert(process != nullptr);                               \
-              T* t = dynamic_cast<T*>(process);                         \
-              assert(t != nullptr);                                     \
-              promise->set((t->*method)(ENUM_PARAMS(N, a)));            \
-            }));                                                        \
+            std::bind([promise, method](ENUM(N, DECL, _),               \
+                                        ProcessBase* process) {         \
+                        assert(process != nullptr);                     \
+                        T* t = dynamic_cast<T*>(process);               \
+                        assert(t != nullptr);                           \
+                        promise->set((t->*method)(ENUM_PARAMS(N, a)));  \
+                      },                                                \
+                      ENUM(N, FORWARD, _),                              \
+                      lambda::_1)));                                    \
                                                                         \
     internal::dispatch(pid, f, &typeid(method));                        \
                                                                         \
@@ -383,9 +399,9 @@ Future<R> dispatch(const Process<T>* process, R 
(T::*method)())
   Future<R> dispatch(                                                   \
       const Process<T>& process,                                        \
       R (T::*method)(ENUM_PARAMS(N, P)),                                \
-      ENUM_BINARY_PARAMS(N, A, a))                                      \
+      ENUM_BINARY_PARAMS(N, A, &&a))                                    \
   {                                                                     \
-    return dispatch(process.self(), method, ENUM_PARAMS(N, a));         \
+    return dispatch(process.self(), method, ENUM(N, FORWARD, _));       \
   }                                                                     \
                                                                         \
   template <typename R,                                                 \
@@ -395,14 +411,16 @@ Future<R> dispatch(const Process<T>* process, R 
(T::*method)())
   Future<R> dispatch(                                                   \
       const Process<T>* process,                                        \
       R (T::*method)(ENUM_PARAMS(N, P)),                                \
-      ENUM_BINARY_PARAMS(N, A, a))                                      \
+      ENUM_BINARY_PARAMS(N, A, &&a))                                    \
   {                                                                     \
-    return dispatch(process->self(), method, ENUM_PARAMS(N, a));        \
+    return dispatch(process->self(), method, ENUM(N, FORWARD, _));      \
   }
 
   REPEAT_FROM_TO(1, 12, TEMPLATE, _) // Args A0 -> A10.
 #undef TEMPLATE
 
+#undef DECL
+#undef FORWARD
 
 // We use partial specialization of
 //   - internal::Dispatch<void> vs

http://git-wip-us.apache.org/repos/asf/mesos/blob/f8e4f11e/3rdparty/libprocess/include/process/future.hpp
----------------------------------------------------------------------
diff --git a/3rdparty/libprocess/include/process/future.hpp 
b/3rdparty/libprocess/include/process/future.hpp
index cce9505..2f5f0a2 100644
--- a/3rdparty/libprocess/include/process/future.hpp
+++ b/3rdparty/libprocess/include/process/future.hpp
@@ -175,32 +175,34 @@ public:
   template <typename F>
   const Future<T>& onDiscard(_Deferred<F>&& deferred) const
   {
-    return onDiscard(deferred.operator std::function<void()>());
+    return onDiscard(std::move(deferred).operator std::function<void()>());
   }
 
   template <typename F>
   const Future<T>& onReady(_Deferred<F>&& deferred) const
   {
-    return onReady(deferred.operator std::function<void(const T&)>());
+    return onReady(
+        std::move(deferred).operator std::function<void(const T&)>());
   }
 
   template <typename F>
   const Future<T>& onFailed(_Deferred<F>&& deferred) const
   {
     return onFailed(
-        deferred.operator std::function<void(const std::string&)>());
+        std::move(deferred).operator std::function<void(const 
std::string&)>());
   }
 
   template <typename F>
   const Future<T>& onDiscarded(_Deferred<F>&& deferred) const
   {
-    return onDiscarded(deferred.operator std::function<void()>());
+    return onDiscarded(std::move(deferred).operator std::function<void()>());
   }
 
   template <typename F>
   const Future<T>& onAny(_Deferred<F>&& deferred) const
   {
-    return onAny(deferred.operator std::function<void(const Future<T>&)>());
+    return onAny(
+        std::move(deferred).operator std::function<void(const Future<T>&)>());
   }
 
 private:
@@ -334,21 +336,22 @@ public:
   // and associates the result of the callback with the future that is
   // returned to the caller (which may be of a different type).
   template <typename X>
-  Future<X> then(const lambda::function<Future<X>(const T&)>& f) const;
+  Future<X> then(lambda::function<Future<X>(const T&)> f) const;
 
   template <typename X>
-  Future<X> then(const lambda::function<X(const T&)>& f) const;
+  Future<X> then(lambda::function<X(const T&)> f) const;
 
   template <typename X>
-  Future<X> then(const lambda::function<Future<X>()>& f) const
+  Future<X> then(lambda::function<Future<X>()> f) const
   {
-    return then(lambda::function<Future<X>(const T&)>(lambda::bind(f)));
+    return then(
+        lambda::function<Future<X>(const T&)>(lambda::bind(std::move(f))));
   }
 
   template <typename X>
-  Future<X> then(const lambda::function<X()>& f) const
+  Future<X> then(lambda::function<X()> f) const
   {
-    return then(lambda::function<X(const T&)>(lambda::bind(f)));
+    return then(lambda::function<X(const T&)>(lambda::bind(std::move(f))));
   }
 
 private:
@@ -360,7 +363,7 @@ private:
   {
     // note the then<X> is necessary to not have an infinite loop with
     // then(F&& f)
-    return then<X>(f.operator std::function<Future<X>(const T&)>());
+    return then<X>(std::move(f).operator std::function<Future<X>(const T&)>());
   }
 
   // Refer to the less preferred version of `onReady` for why these SFINAE
@@ -373,13 +376,13 @@ private:
               F>::type()>::type>::type>
   Future<X> then(_Deferred<F>&& f, LessPrefer) const
   {
-    return then<X>(f.operator std::function<Future<X>()>());
+    return then<X>(std::move(f).operator std::function<Future<X>()>());
   }
 
   template <typename F, typename X = typename internal::unwrap<typename 
result_of<F(const T&)>::type>::type> // NOLINT(whitespace/line_length)
   Future<X> then(F&& f, Prefer) const
   {
-    return then<X>(std::function<Future<X>(const T&)>(f));
+    return then<X>(std::function<Future<X>(const T&)>(std::forward<F>(f)));
   }
 
   // Refer to the less preferred version of `onReady` for why these SFINAE
@@ -392,7 +395,7 @@ private:
               F>::type()>::type>::type>
   Future<X> then(F&& f, LessPrefer) const
   {
-    return then<X>(std::function<Future<X>()>(f));
+    return then<X>(std::function<Future<X>()>(std::forward<F>(f)));
   }
 
 public:
@@ -1396,14 +1399,14 @@ void after(
 
 template <typename T>
 template <typename X>
-Future<X> Future<T>::then(const lambda::function<Future<X>(const T&)>& f) const
+Future<X> Future<T>::then(lambda::function<Future<X>(const T&)> f) const
 {
   std::shared_ptr<Promise<X>> promise(new Promise<X>());
 
   lambda::function<void(const Future<T>&)> thenf =
-    lambda::bind(&internal::thenf<T, X>, f, promise, lambda::_1);
+    lambda::bind(&internal::thenf<T, X>, std::move(f), promise, lambda::_1);
 
-  onAny(thenf);
+  onAny(std::move(thenf));
 
   // Propagate discarding up the chain. To avoid cyclic dependencies,
   // we keep a weak future in the callback.
@@ -1416,14 +1419,14 @@ Future<X> Future<T>::then(const 
lambda::function<Future<X>(const T&)>& f) const
 
 template <typename T>
 template <typename X>
-Future<X> Future<T>::then(const lambda::function<X(const T&)>& f) const
+Future<X> Future<T>::then(lambda::function<X(const T&)> f) const
 {
   std::shared_ptr<Promise<X>> promise(new Promise<X>());
 
   lambda::function<void(const Future<T>&)> then =
-    lambda::bind(&internal::then<T, X>, f, promise, lambda::_1);
+    lambda::bind(&internal::then<T, X>, std::move(f), promise, lambda::_1);
 
-  onAny(then);
+  onAny(std::move(then));
 
   // Propagate discarding up the chain. To avoid cyclic dependencies,
   // we keep a weak future in the callback.

http://git-wip-us.apache.org/repos/asf/mesos/blob/f8e4f11e/3rdparty/libprocess/include/process/http.hpp
----------------------------------------------------------------------
diff --git a/3rdparty/libprocess/include/process/http.hpp 
b/3rdparty/libprocess/include/process/http.hpp
index f637999..ba1b086 100644
--- a/3rdparty/libprocess/include/process/http.hpp
+++ b/3rdparty/libprocess/include/process/http.hpp
@@ -1017,7 +1017,8 @@ Future<Nothing> serve(
 template <typename F>
 Future<Nothing> serve(const network::Socket& s, F&& f)
 {
-  return internal::serve(s, std::function<Future<Response>(const 
Request&)>(f));
+  return internal::serve(
+      s, std::function<Future<Response>(const Request&)>(std::forward<F>(f)));
 }
 
 

http://git-wip-us.apache.org/repos/asf/mesos/blob/f8e4f11e/3rdparty/libprocess/src/tests/benchmarks.cpp
----------------------------------------------------------------------
diff --git a/3rdparty/libprocess/src/tests/benchmarks.cpp 
b/3rdparty/libprocess/src/tests/benchmarks.cpp
index 245ff77..a691705 100644
--- a/3rdparty/libprocess/src/tests/benchmarks.cpp
+++ b/3rdparty/libprocess/src/tests/benchmarks.cpp
@@ -488,3 +488,89 @@ TEST(ProcessTest, Process_BENCHMARK_ThroughputPerformance)
     wait(destination->self());
   }
 }
+
+
+class DispatchProcess : public Process<DispatchProcess>
+{
+public:
+  struct Movable
+  {
+    std::vector<int> data;
+  };
+
+  // This simulates protobuf objects, which do not support moves.
+  struct Copyable
+  {
+    std::vector<int> data;
+
+    Copyable(std::vector<int>&& data) : data(std::move(data)) {}
+    Copyable(const Copyable& that) = default;
+    Copyable& operator=(const Copyable&) = default;
+  };
+
+  DispatchProcess(Promise<Nothing> *promise, long repeat)
+    : promise(promise), repeat(repeat) {}
+
+  template <typename T>
+  Future<Nothing> handler(const T& data)
+  {
+    count++;
+    if (count >= repeat) {
+      promise->set(Nothing());
+      return Nothing();
+    }
+
+    dispatch(self(), &Self::_handler).then(
+        defer(self(), &Self::handler<T>, data));
+
+    return Nothing();
+  }
+
+  template <typename T>
+  static void run(const string& name, long repeats)
+  {
+    Promise<Nothing> promise;
+
+    Owned<DispatchProcess> process(new DispatchProcess(&promise, repeats));
+    spawn(*process);
+
+    T data{std::vector<int>(10240, 42)};
+
+    Stopwatch watch;
+    watch.start();
+
+    dispatch(process.get(), &DispatchProcess::handler<T>, data);
+
+    AWAIT_READY(promise.future());
+
+    cout << name <<  " elapsed: " << watch.elapsed() << endl;
+
+    terminate(process.get());
+    wait(process.get());
+  }
+
+private:
+  Future<Nothing> _handler()
+  {
+    return Nothing();
+  }
+
+  Promise<Nothing> *promise;
+  long repeat;
+  long count = 0;
+};
+
+
+TEST(ProcessTest, Process_BENCHMARK_DispatchDefer)
+{
+  constexpr long repeats = 100000;
+
+  // Test performance separately for objects which support std::move,
+  // and which don't (e.g. like protobufs).
+  // Note: DispatchProcess::handler code is not fully optimized,
+  // to take advantage of std::move support, e.g. parameter is passed
+  // by const reference, so some copying is unavoidable, however
+  // this resembles how most of the handlers are currently implemented.
+  DispatchProcess::run<DispatchProcess::Movable>("Movable", repeats);
+  DispatchProcess::run<DispatchProcess::Copyable>("Copyable", repeats);
+}

Reply via email to