UntypedFunction: Add unit tests and fix a few issues

Bug: webrtc:11943
Change-Id: I1f3c0495612148546ec399a800f97fe88b439c83
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/184260
Commit-Queue: Karl Wiberg <kwiberg@webrtc.org>
Reviewed-by: Mirko Bonadei <mbonadei@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#32116}
diff --git a/BUILD.gn b/BUILD.gn
index 443a4ff..af3a690 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -538,6 +538,7 @@
       "call:fake_network_pipe_unittests",
       "p2p:libstunprober_unittests",
       "p2p:rtc_p2p_unittests",
+      "rtc_base:function_unittest",
       "rtc_base:rtc_base_approved_unittests",
       "rtc_base:rtc_base_unittests",
       "rtc_base:rtc_json_unittests",
diff --git a/rtc_base/BUILD.gn b/rtc_base/BUILD.gn
index 1d4a28d..105bbc3 100644
--- a/rtc_base/BUILD.gn
+++ b/rtc_base/BUILD.gn
@@ -1158,6 +1158,15 @@
     ]
   }
 
+  rtc_library("function_unittest") {
+    testonly = true
+    sources = [ "function_unittest.cc" ]
+    deps = [
+      ":function",
+      "../test:test_support",
+    ]
+  }
+
   rtc_library("rtc_base_nonparallel_tests") {
     testonly = true
 
diff --git a/rtc_base/function.h b/rtc_base/function.h
index 67fcd59..cbc5f7d 100644
--- a/rtc_base/function.h
+++ b/rtc_base/function.h
@@ -102,9 +102,10 @@
     } else {
       // The callable is either nontrivial or too large, so we can't keep it
       // in the inline storage; use the heap instead.
+      webrtc_function_impl::VoidUnion vu;
+      vu.void_ptr = new F_deref(std::forward<F>(f));
       return UntypedFunction(
-          webrtc_function_impl::VoidUnion{.void_ptr =
-                                              new F_deref(std::forward<F>(f))},
+          vu,
           reinterpret_cast<webrtc_function_impl::FunVoid*>(
               webrtc_function_impl::CallHelpers<
                   Signature>::template CallVoidPtr<F_deref>),
@@ -123,8 +124,10 @@
   // the result is an empty UntypedFunction.
   template <typename Signature>
   static UntypedFunction Create(Signature* f) {
+    webrtc_function_impl::VoidUnion vu;
+    vu.fun_ptr = reinterpret_cast<webrtc_function_impl::FunVoid*>(f);
     return UntypedFunction(
-        reinterpret_cast<webrtc_function_impl::FunVoid*>(f),
+        vu,
         f ? reinterpret_cast<webrtc_function_impl::FunVoid*>(
                 webrtc_function_impl::CallHelpers<Signature>::CallFunPtr)
           : nullptr,
@@ -134,6 +137,18 @@
   // Default constructor. Creates an empty UntypedFunction.
   UntypedFunction() : call_(nullptr), delete_(nullptr) {}
 
+  // Nullptr constructor and assignment. Creates an empty UntypedFunction.
+  UntypedFunction(std::nullptr_t)  // NOLINT(runtime/explicit)
+      : call_(nullptr), delete_(nullptr) {}
+  UntypedFunction& operator=(std::nullptr_t) {
+    call_ = nullptr;
+    if (delete_) {
+      delete_(&f_);
+      delete_ = nullptr;
+    }
+    return *this;
+  }
+
   // Not copyable.
   UntypedFunction(const UntypedFunction&) = delete;
   UntypedFunction& operator=(const UntypedFunction&) = delete;
@@ -144,6 +159,9 @@
     other.delete_ = nullptr;
   }
   UntypedFunction& operator=(UntypedFunction&& other) {
+    if (delete_) {
+      delete_(&f_);
+    }
     f_ = other.f_;
     call_ = other.call_;
     delete_ = other.delete_;
@@ -169,7 +187,7 @@
 
   template <typename Signature, typename... ArgT>
   typename webrtc_function_impl::CallHelpers<Signature>::return_type Call(
-      ArgT... args) {
+      ArgT&&... args) {
     return webrtc_function_impl::CallHelpers<Signature>::DoCall(
         call_, &f_, std::forward<ArgT>(args)...);
   }
diff --git a/rtc_base/function_unittest.cc b/rtc_base/function_unittest.cc
new file mode 100644
index 0000000..7a3d658
--- /dev/null
+++ b/rtc_base/function_unittest.cc
@@ -0,0 +1,307 @@
+/*
+ *  Copyright (c) 2020 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "rtc_base/function.h"
+
+#include <memory>
+#include <vector>
+
+#include "test/gmock.h"
+#include "test/gtest.h"
+
+namespace webrtc {
+namespace {
+
+using ::testing::Pointee;
+
+TEST(UntypedFunction, Empty1) {
+  UntypedFunction uf;
+  EXPECT_FALSE(uf);
+  EXPECT_TRUE(uf.IsTriviallyDestructible());
+}
+
+TEST(UntypedFunction, Empty2) {
+  UntypedFunction uf = nullptr;
+  EXPECT_FALSE(uf);
+  EXPECT_TRUE(uf.IsTriviallyDestructible());
+}
+
+TEST(UntypedFunction, Empty3) {
+  UntypedFunction uf = UntypedFunction::Create<int(int)>(nullptr);
+  EXPECT_FALSE(uf);
+  EXPECT_TRUE(uf.IsTriviallyDestructible());
+}
+
+TEST(UntypedFunction, CallTrivialWithInt) {
+  auto uf = UntypedFunction::Create<int(int)>([](int x) { return x + 5; });
+  EXPECT_TRUE(uf);
+  EXPECT_TRUE(uf.IsTriviallyDestructible());
+  EXPECT_EQ(uf.Call<int(int)>(17), 22);
+}
+
+TEST(UntypedFunction, CallTrivialWithPointer) {
+  auto uf = UntypedFunction::Create<int(int*)>([](int* x) { return *x; });
+  EXPECT_TRUE(uf);
+  EXPECT_TRUE(uf.IsTriviallyDestructible());
+  int x = 12;
+  EXPECT_EQ(uf.Call<int(int*)>(&x), 12);
+}
+
+TEST(UntypedFunction, CallTrivialWithReference) {
+  auto uf = UntypedFunction::Create<void(int&)>([](int& x) { x = 3; });
+  EXPECT_TRUE(uf);
+  EXPECT_TRUE(uf.IsTriviallyDestructible());
+  int x = 12;
+  uf.Call<void(int&)>(x);
+  EXPECT_EQ(x, 3);
+}
+
+TEST(UntypedFunction, CallTrivialWithRvalueReference) {
+  auto uf = UntypedFunction::Create<int(int&&)>([](int&& x) { return x - 2; });
+  EXPECT_TRUE(uf);
+  EXPECT_TRUE(uf.IsTriviallyDestructible());
+  EXPECT_EQ(uf.Call<int(int&&)>(34), 32);
+}
+
+TEST(UntypedFunction, CallNontrivialWithInt) {
+  std::vector<int> list;
+  auto uf = UntypedFunction::Create<int(int)>([list](int x) mutable {
+    list.push_back(x);
+    return list.size();
+  });
+  EXPECT_TRUE(uf);
+  EXPECT_FALSE(uf.IsTriviallyDestructible());
+  EXPECT_EQ(uf.Call<int(int)>(17), 1);
+  EXPECT_EQ(uf.Call<int(int)>(17), 2);
+}
+
+TEST(UntypedFunction, CallNontrivialWithPointer) {
+  std::vector<int> list;
+  auto uf = UntypedFunction::Create<int*(int*)>([list](int* x) mutable {
+    list.push_back(*x);
+    return list.data();
+  });
+  EXPECT_TRUE(uf);
+  EXPECT_FALSE(uf.IsTriviallyDestructible());
+  int x = 12;
+  EXPECT_THAT(uf.Call<int*(int*)>(&x), Pointee(12));
+}
+
+TEST(UntypedFunction, CallNontrivialWithReference) {
+  std::vector<int> list = {34, 35, 36};
+  auto uf =
+      UntypedFunction::Create<void(int&)>([list](int& x) { x = list[1]; });
+  EXPECT_TRUE(uf);
+  EXPECT_FALSE(uf.IsTriviallyDestructible());
+  int x = 12;
+  uf.Call<void(int&)>(x);
+  EXPECT_EQ(x, 35);
+}
+
+TEST(UntypedFunction, CallNontrivialWithRvalueReference) {
+  std::vector<int> list;
+  auto uf = UntypedFunction::Create<int(int&&)>([list](int&& x) mutable {
+    list.push_back(x);
+    return list.size();
+  });
+  EXPECT_TRUE(uf);
+  EXPECT_FALSE(uf.IsTriviallyDestructible());
+  EXPECT_EQ(uf.Call<int(int&&)>(34), 1);
+  EXPECT_EQ(uf.Call<int(int&&)>(34), 2);
+}
+
+int AddFive(int x) {
+  return x + 5;
+}
+int DereferencePointer(int* x) {
+  return *x;
+}
+void AssignThree(int& x) {
+  x = 3;
+}
+int SubtractTwo(int&& x) {
+  return x - 2;
+}
+
+TEST(UntypedFunction, CallFunctionPointerWithInt) {
+  auto uf = UntypedFunction::Create<int(int)>(AddFive);
+  EXPECT_TRUE(uf);
+  EXPECT_TRUE(uf.IsTriviallyDestructible());
+  EXPECT_EQ(uf.Call<int(int)>(17), 22);
+}
+
+TEST(UntypedFunction, CallFunctionPointerWithPointer) {
+  auto uf = UntypedFunction::Create<int(int*)>(DereferencePointer);
+  EXPECT_TRUE(uf);
+  EXPECT_TRUE(uf.IsTriviallyDestructible());
+  int x = 12;
+  EXPECT_EQ(uf.Call<int(int*)>(&x), 12);
+}
+
+TEST(UntypedFunction, CallFunctionPointerWithReference) {
+  auto uf = UntypedFunction::Create<void(int&)>(AssignThree);
+  EXPECT_TRUE(uf);
+  EXPECT_TRUE(uf.IsTriviallyDestructible());
+  int x = 12;
+  uf.Call<void(int&)>(x);
+  EXPECT_EQ(x, 3);
+}
+
+TEST(UntypedFunction, CallFunctionPointerWithRvalueReference) {
+  auto uf = UntypedFunction::Create<int(int&&)>(SubtractTwo);
+  EXPECT_TRUE(uf);
+  EXPECT_TRUE(uf.IsTriviallyDestructible());
+  EXPECT_EQ(uf.Call<int(int&&)>(34), 32);
+}
+
+TEST(UntypedFunction, CallTrivialWithNoArgs) {
+  int arr[] = {1, 2, 3};
+  auto uf = UntypedFunction::Create<int()>([arr] { return arr[1]; });
+  EXPECT_TRUE(uf);
+  EXPECT_TRUE(uf.IsTriviallyDestructible());
+  EXPECT_EQ(uf.Call<int()>(), 2);
+}
+
+TEST(UntypedFunction, CallLargeTrivialWithNoArgs) {
+  int arr[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0};
+  auto uf = UntypedFunction::Create<int()>([arr] { return arr[4]; });
+  EXPECT_TRUE(uf);
+  EXPECT_FALSE(uf.IsTriviallyDestructible());
+  EXPECT_EQ(uf.Call<int()>(), 5);
+}
+
+TEST(UntypedFunction, MoveonlyReturnValue) {
+  auto uf = UntypedFunction::Create<std::unique_ptr<int>()>(
+      [] { return std::make_unique<int>(567); });
+  EXPECT_THAT(uf.Call<std::unique_ptr<int>()>(), Pointee(567));
+}
+
+TEST(UntypedFunction, MoveonlyArgument) {
+  auto uf = UntypedFunction::Create<int(std::unique_ptr<int>)>(
+      [](std::unique_ptr<int> x) { return *x + 19; });
+  EXPECT_EQ(uf.Call<int(std::unique_ptr<int>)>(std::make_unique<int>(40)), 59);
+}
+
+TEST(UntypedFunction, MoveOnlyCallable) {
+  auto uf = UntypedFunction::Create<int()>(
+      [x = std::make_unique<int>(17)] { return ++*x; });
+  EXPECT_TRUE(uf);
+  EXPECT_FALSE(uf.IsTriviallyDestructible());
+  EXPECT_EQ(uf.Call<int()>(), 18);
+  EXPECT_EQ(uf.Call<int()>(), 19);
+  UntypedFunction uf2 = std::move(uf);
+  EXPECT_TRUE(uf);
+  EXPECT_TRUE(uf.IsTriviallyDestructible());
+  EXPECT_FALSE(uf2.IsTriviallyDestructible());
+  EXPECT_EQ(uf.Call<int()>(), 20);
+  EXPECT_EQ(uf.Call<int()>(), 21);
+}
+
+class Destroyer {
+ public:
+  explicit Destroyer(int& destroy_count) : destroy_count_(&destroy_count) {}
+  ~Destroyer() { ++*destroy_count_; }
+  int operator()() { return 72; }
+  int* destroy_count_;
+};
+
+TEST(UntypedFunction, CallableIsDestroyed) {
+  int destroy_count = 0;
+  {
+    auto uf = UntypedFunction::Create<int()>(Destroyer(destroy_count));
+    // Destruction count is 1 here, because the temporary we created above was
+    // destroyed.
+    EXPECT_EQ(destroy_count, 1);
+    {
+      auto uf2 = std::move(uf);
+      EXPECT_EQ(destroy_count, 1);
+    }
+    // `uf2` was destroyed.
+    EXPECT_EQ(destroy_count, 2);
+  }
+  // `uf` was destroyed, but it didn't contain a Destroyer since we moved it to
+  // `uf2` above.
+  EXPECT_EQ(destroy_count, 2);
+}
+
+TEST(UntypedFunction, MoveAssign) {
+  int destroy_count = 0;
+  auto uf = UntypedFunction::Create<int()>(Destroyer(destroy_count));
+  EXPECT_TRUE(uf);
+  EXPECT_FALSE(uf.IsTriviallyDestructible());
+  // Destruction count is 1 here, because the temporary we created above was
+  // destroyed.
+  EXPECT_EQ(destroy_count, 1);
+  UntypedFunction uf2 = nullptr;
+  EXPECT_FALSE(uf2);
+  EXPECT_TRUE(uf2.IsTriviallyDestructible());
+
+  uf2 = std::move(uf);
+  EXPECT_TRUE(uf.IsTriviallyDestructible());
+  EXPECT_TRUE(uf2);
+  EXPECT_FALSE(uf2.IsTriviallyDestructible());
+  EXPECT_EQ(destroy_count, 1);  // The callable was not destroyed.
+  EXPECT_EQ(uf2.Call<int()>(), 72);
+
+  UntypedFunction uf3 = nullptr;
+  uf2 = std::move(uf3);
+  EXPECT_FALSE(uf2);
+  EXPECT_TRUE(uf2.IsTriviallyDestructible());
+  EXPECT_EQ(destroy_count, 2);  // The callable was destroyed by the assignment.
+}
+
+TEST(UntypedFunction, NullptrAssign) {
+  int destroy_count = 0;
+  auto uf = UntypedFunction::Create<int()>(Destroyer(destroy_count));
+  EXPECT_TRUE(uf);
+  EXPECT_FALSE(uf.IsTriviallyDestructible());
+  // Destruction count is 1 here, because the temporary we created above was
+  // destroyed.
+  EXPECT_EQ(destroy_count, 1);
+
+  uf = nullptr;
+  EXPECT_FALSE(uf);
+  EXPECT_TRUE(uf.IsTriviallyDestructible());
+  EXPECT_EQ(destroy_count, 2);  // The callable was destroyed by the assignment.
+}
+
+TEST(UntypedFunction, Swap) {
+  int x = 13;
+  auto uf = UntypedFunction::Create<int()>([x]() mutable { return ++x; });
+  EXPECT_TRUE(uf);
+  EXPECT_TRUE(uf.IsTriviallyDestructible());
+  auto y = std::make_unique<int>(113);
+  auto uf2 =
+      UntypedFunction::Create<int()>([y = std::move(y)] { return ++*y; });
+  EXPECT_TRUE(uf2);
+  EXPECT_FALSE(uf2.IsTriviallyDestructible());
+  UntypedFunction uf3 = nullptr;
+  EXPECT_FALSE(uf3);
+  EXPECT_TRUE(uf3.IsTriviallyDestructible());
+
+  EXPECT_EQ(uf.Call<int()>(), 14);
+  swap(uf, uf2);
+  EXPECT_TRUE(uf);
+  EXPECT_FALSE(uf.IsTriviallyDestructible());
+  EXPECT_TRUE(uf2);
+  EXPECT_TRUE(uf2.IsTriviallyDestructible());
+  EXPECT_EQ(uf.Call<int()>(), 114);
+  EXPECT_EQ(uf2.Call<int()>(), 15);
+
+  swap(uf, uf3);
+  EXPECT_FALSE(uf);
+  EXPECT_TRUE(uf.IsTriviallyDestructible());
+  EXPECT_TRUE(uf3);
+  EXPECT_FALSE(uf3.IsTriviallyDestructible());
+  EXPECT_EQ(uf3.Call<int()>(), 115);
+}
+
+}  // namespace
+}  // namespace webrtc