Remove unnecessary copies from AsyncInvoke

Currently, the way the AsyncInvoke is implemented, the lambda invoked is copied multiple times. This causes two problems: (1) a reduced performance where captured variables are copied unnecessarily, (2) lambdas with non-copyable captures are not possible to invoke.

This cl attempts to address both points.

Change-Id: I8d907287d6e4851330d469f184760d165fa8bc08
Bug: webrtc:9028
Reviewed-on: https://webrtc-review.googlesource.com/61346
Commit-Queue: Tommi <tommi@webrtc.org>
Reviewed-by: Tommi <tommi@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#22471}
diff --git a/rtc_base/asyncinvoker-inl.h b/rtc_base/asyncinvoker-inl.h
index 073d5bf..0d546b1 100644
--- a/rtc_base/asyncinvoker-inl.h
+++ b/rtc_base/asyncinvoker-inl.h
@@ -49,13 +49,13 @@
 class FireAndForgetAsyncClosure : public AsyncClosure {
  public:
   explicit FireAndForgetAsyncClosure(AsyncInvoker* invoker,
-                                     const FunctorT& functor)
-      : AsyncClosure(invoker), functor_(functor) {}
+                                     FunctorT&& functor)
+      : AsyncClosure(invoker), functor_(std::forward<FunctorT>(functor)) {}
   virtual void Execute() {
     functor_();
   }
  private:
-  FunctorT functor_;
+  typename std::decay<FunctorT>::type functor_;
 };
 
 }  // namespace rtc
diff --git a/rtc_base/asyncinvoker.h b/rtc_base/asyncinvoker.h
index 523e9a9..74e8689 100644
--- a/rtc_base/asyncinvoker.h
+++ b/rtc_base/asyncinvoker.h
@@ -97,10 +97,11 @@
   template <class ReturnT, class FunctorT>
   void AsyncInvoke(const Location& posted_from,
                    Thread* thread,
-                   const FunctorT& functor,
+                   FunctorT&& functor,
                    uint32_t id = 0) {
     std::unique_ptr<AsyncClosure> closure(
-        new FireAndForgetAsyncClosure<FunctorT>(this, functor));
+        new FireAndForgetAsyncClosure<FunctorT>(
+            this, std::forward<FunctorT>(functor)));
     DoInvoke(posted_from, thread, std::move(closure), id);
   }
 
@@ -109,11 +110,12 @@
   template <class ReturnT, class FunctorT>
   void AsyncInvokeDelayed(const Location& posted_from,
                           Thread* thread,
-                          const FunctorT& functor,
+                          FunctorT&& functor,
                           uint32_t delay_ms,
                           uint32_t id = 0) {
     std::unique_ptr<AsyncClosure> closure(
-        new FireAndForgetAsyncClosure<FunctorT>(this, functor));
+        new FireAndForgetAsyncClosure<FunctorT>(
+            this, std::forward<FunctorT>(functor)));
     DoInvokeDelayed(posted_from, thread, std::move(closure), delay_ms, id);
   }
 
@@ -188,12 +190,13 @@
   // immediately. Returns false if the thread has died.
   template <class ReturnT, class FunctorT>
   bool AsyncInvoke(const Location& posted_from,
-                   const FunctorT& functor,
+                   FunctorT&& functor,
                    uint32_t id = 0) {
     CritScope cs(&crit_);
     if (thread_ == nullptr)
       return false;
-    invoker_.AsyncInvoke<ReturnT, FunctorT>(posted_from, thread_, functor, id);
+    invoker_.AsyncInvoke<ReturnT, FunctorT>(
+        posted_from, thread_, std::forward<FunctorT>(functor), id);
     return true;
   }
 
@@ -201,14 +204,14 @@
   // completion. Returns immediately. Returns false if the thread has died.
   template <class ReturnT, class FunctorT>
   bool AsyncInvokeDelayed(const Location& posted_from,
-                          const FunctorT& functor,
+                          FunctorT&& functor,
                           uint32_t delay_ms,
                           uint32_t id = 0) {
     CritScope cs(&crit_);
     if (thread_ == nullptr)
       return false;
-    invoker_.AsyncInvokeDelayed<ReturnT, FunctorT>(posted_from, thread_,
-                                                   functor, delay_ms, id);
+    invoker_.AsyncInvokeDelayed<ReturnT, FunctorT>(
+        posted_from, thread_, std::forward<FunctorT>(functor), delay_ms, id);
     return true;
   }
 
@@ -217,7 +220,7 @@
   template <class ReturnT, class FunctorT, class HostT>
   bool AsyncInvoke(const Location& posted_from,
                    const Location& callback_posted_from,
-                   const FunctorT& functor,
+                   FunctorT&& functor,
                    void (HostT::*callback)(ReturnT),
                    HostT* callback_host,
                    uint32_t id = 0) {
@@ -225,8 +228,8 @@
     if (thread_ == nullptr)
       return false;
     invoker_.AsyncInvoke<ReturnT, FunctorT, HostT>(
-        posted_from, callback_posted_from, thread_, functor, callback,
-        callback_host, id);
+        posted_from, callback_posted_from, thread_,
+        std::forward<FunctorT>(functor), callback, callback_host, id);
     return true;
   }
 
@@ -235,7 +238,7 @@
   template <class ReturnT, class FunctorT, class HostT>
   bool AsyncInvoke(const Location& posted_from,
                    const Location& callback_posted_from,
-                   const FunctorT& functor,
+                   FunctorT&& functor,
                    void (HostT::*callback)(),
                    HostT* callback_host,
                    uint32_t id = 0) {
@@ -243,8 +246,8 @@
     if (thread_ == nullptr)
       return false;
     invoker_.AsyncInvoke<ReturnT, FunctorT, HostT>(
-        posted_from, callback_posted_from, thread_, functor, callback,
-        callback_host, id);
+        posted_from, callback_posted_from, thread_,
+        std::forward<FunctorT>(functor), callback, callback_host, id);
     return true;
   }
 
diff --git a/rtc_base/thread_unittest.cc b/rtc_base/thread_unittest.cc
index 5f00064..01022e9 100644
--- a/rtc_base/thread_unittest.cc
+++ b/rtc_base/thread_unittest.cc
@@ -186,6 +186,16 @@
     return 24;
   }
 };
+struct FunctorD {
+ public:
+  explicit FunctorD(AtomicBool* flag) : flag_(flag) {}
+  FunctorD(FunctorD&&) = default;
+  FunctorD& operator=(FunctorD&&) = default;
+  void operator()() { if (flag_) *flag_ = true; }
+ private:
+  AtomicBool* flag_;
+  RTC_DISALLOW_COPY_AND_ASSIGN(FunctorD);
+};
 
 // See: https://code.google.com/p/webrtc/issues/detail?id=2409
 TEST(ThreadTest, DISABLED_Main) {
@@ -441,6 +451,18 @@
   thread->Stop();
 }
 
+TEST_F(AsyncInvokeTest, NonCopyableFunctor) {
+  AsyncInvoker invoker;
+  // Create and start the thread.
+  auto thread = Thread::CreateWithSocketServer();
+  thread->Start();
+  // Try calling functor.
+  AtomicBool called;
+  invoker.AsyncInvoke<void>(RTC_FROM_HERE, thread.get(), FunctorD(&called));
+  EXPECT_TRUE_WAIT(called.get(), kWaitTimeout);
+  thread->Stop();
+}
+
 TEST_F(AsyncInvokeTest, KillInvokerDuringExecute) {
   // Use these events to get in a state where the functor is in the middle of
   // executing, and then to wait for it to finish, ensuring the "EXPECT_FALSE"
@@ -602,6 +624,14 @@
   EXPECT_TRUE_WAIT(called.get(), kWaitTimeout);
 }
 
+TEST_F(GuardedAsyncInvokeTest, NonCopyableFunctor) {
+  GuardedAsyncInvoker invoker;
+  // Try calling functor.
+  AtomicBool called;
+  EXPECT_TRUE(invoker.AsyncInvoke<void>(RTC_FROM_HERE, FunctorD(&called)));
+  EXPECT_TRUE_WAIT(called.get(), kWaitTimeout);
+}
+
 TEST_F(GuardedAsyncInvokeTest, Flush) {
   GuardedAsyncInvoker invoker;
   AtomicBool flag1;