1 //===- FunctionExtrasTest.cpp - Unit tests for function type erasure ------===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 #include "llvm/ADT/FunctionExtras.h" 11 #include "gtest/gtest.h" 12 13 #include <memory> 14 15 using namespace llvm; 16 17 namespace { 18 19 TEST(UniqueFunctionTest, Basic) { 20 unique_function<int(int, int)> Sum = [](int A, int B) { return A + B; }; 21 EXPECT_EQ(Sum(1, 2), 3); 22 23 unique_function<int(int, int)> Sum2 = std::move(Sum); 24 EXPECT_EQ(Sum2(1, 2), 3); 25 26 unique_function<int(int, int)> Sum3 = [](int A, int B) { return A + B; }; 27 Sum2 = std::move(Sum3); 28 EXPECT_EQ(Sum2(1, 2), 3); 29 30 Sum2 = unique_function<int(int, int)>([](int A, int B) { return A + B; }); 31 EXPECT_EQ(Sum2(1, 2), 3); 32 33 // Explicit self-move test. 34 *&Sum2 = std::move(Sum2); 35 EXPECT_EQ(Sum2(1, 2), 3); 36 37 Sum2 = unique_function<int(int, int)>(); 38 EXPECT_FALSE(Sum2); 39 40 // Make sure we can forward through l-value reference parameters. 41 unique_function<void(int &)> Inc = [](int &X) { ++X; }; 42 int X = 42; 43 Inc(X); 44 EXPECT_EQ(X, 43); 45 46 // Make sure we can forward through r-value reference parameters with 47 // move-only types. 48 unique_function<int(std::unique_ptr<int> &&)> ReadAndDeallocByRef = 49 [](std::unique_ptr<int> &&Ptr) { 50 int V = *Ptr; 51 Ptr.reset(); 52 return V; 53 }; 54 std::unique_ptr<int> Ptr{new int(13)}; 55 EXPECT_EQ(ReadAndDeallocByRef(std::move(Ptr)), 13); 56 EXPECT_FALSE((bool)Ptr); 57 58 // Make sure we can pass a move-only temporary as opposed to a local variable. 59 EXPECT_EQ(ReadAndDeallocByRef(std::unique_ptr<int>(new int(42))), 42); 60 61 // Make sure we can pass a move-only type by-value. 62 unique_function<int(std::unique_ptr<int>)> ReadAndDeallocByVal = 63 [](std::unique_ptr<int> Ptr) { 64 int V = *Ptr; 65 Ptr.reset(); 66 return V; 67 }; 68 Ptr.reset(new int(13)); 69 EXPECT_EQ(ReadAndDeallocByVal(std::move(Ptr)), 13); 70 EXPECT_FALSE((bool)Ptr); 71 72 EXPECT_EQ(ReadAndDeallocByVal(std::unique_ptr<int>(new int(42))), 42); 73 } 74 75 TEST(UniqueFunctionTest, Captures) { 76 long A = 1, B = 2, C = 3, D = 4, E = 5; 77 78 unique_function<long()> Tmp; 79 80 unique_function<long()> C1 = [A]() { return A; }; 81 EXPECT_EQ(C1(), 1); 82 Tmp = std::move(C1); 83 EXPECT_EQ(Tmp(), 1); 84 85 unique_function<long()> C2 = [A, B]() { return A + B; }; 86 EXPECT_EQ(C2(), 3); 87 Tmp = std::move(C2); 88 EXPECT_EQ(Tmp(), 3); 89 90 unique_function<long()> C3 = [A, B, C]() { return A + B + C; }; 91 EXPECT_EQ(C3(), 6); 92 Tmp = std::move(C3); 93 EXPECT_EQ(Tmp(), 6); 94 95 unique_function<long()> C4 = [A, B, C, D]() { return A + B + C + D; }; 96 EXPECT_EQ(C4(), 10); 97 Tmp = std::move(C4); 98 EXPECT_EQ(Tmp(), 10); 99 100 unique_function<long()> C5 = [A, B, C, D, E]() { return A + B + C + D + E; }; 101 EXPECT_EQ(C5(), 15); 102 Tmp = std::move(C5); 103 EXPECT_EQ(Tmp(), 15); 104 } 105 106 TEST(UniqueFunctionTest, MoveOnly) { 107 struct SmallCallable { 108 std::unique_ptr<int> A{new int(1)}; 109 110 int operator()(int B) { return *A + B; } 111 }; 112 unique_function<int(int)> Small = SmallCallable(); 113 EXPECT_EQ(Small(2), 3); 114 unique_function<int(int)> Small2 = std::move(Small); 115 EXPECT_EQ(Small2(2), 3); 116 117 struct LargeCallable { 118 std::unique_ptr<int> A{new int(1)}; 119 std::unique_ptr<int> B{new int(2)}; 120 std::unique_ptr<int> C{new int(3)}; 121 std::unique_ptr<int> D{new int(4)}; 122 std::unique_ptr<int> E{new int(5)}; 123 124 int operator()() { return *A + *B + *C + *D + *E; } 125 }; 126 unique_function<int()> Large = LargeCallable(); 127 EXPECT_EQ(Large(), 15); 128 unique_function<int()> Large2 = std::move(Large); 129 EXPECT_EQ(Large2(), 15); 130 } 131 132 TEST(UniqueFunctionTest, CountForwardingCopies) { 133 struct CopyCounter { 134 int &CopyCount; 135 136 CopyCounter(int &CopyCount) : CopyCount(CopyCount) {} 137 CopyCounter(const CopyCounter &Arg) : CopyCount(Arg.CopyCount) { 138 ++CopyCount; 139 } 140 }; 141 142 unique_function<void(CopyCounter)> ByValF = [](CopyCounter) {}; 143 int CopyCount = 0; 144 ByValF(CopyCounter(CopyCount)); 145 EXPECT_EQ(1, CopyCount); 146 147 CopyCount = 0; 148 { 149 CopyCounter Counter{CopyCount}; 150 ByValF(Counter); 151 } 152 EXPECT_EQ(2, CopyCount); 153 154 // Check that we don't generate a copy at all when we can bind a reference all 155 // the way down, even if that reference could *in theory* allow copies. 156 unique_function<void(const CopyCounter &)> ByRefF = [](const CopyCounter &) { 157 }; 158 CopyCount = 0; 159 ByRefF(CopyCounter(CopyCount)); 160 EXPECT_EQ(0, CopyCount); 161 162 CopyCount = 0; 163 { 164 CopyCounter Counter{CopyCount}; 165 ByRefF(Counter); 166 } 167 EXPECT_EQ(0, CopyCount); 168 169 // If we use a reference, we can make a stronger guarantee that *no* copy 170 // occurs. 171 struct Uncopyable { 172 Uncopyable() = default; 173 Uncopyable(const Uncopyable &) = delete; 174 }; 175 unique_function<void(const Uncopyable &)> UncopyableF = 176 [](const Uncopyable &) {}; 177 UncopyableF(Uncopyable()); 178 Uncopyable X; 179 UncopyableF(X); 180 } 181 182 TEST(UniqueFunctionTest, CountForwardingMoves) { 183 struct MoveCounter { 184 int &MoveCount; 185 186 MoveCounter(int &MoveCount) : MoveCount(MoveCount) {} 187 MoveCounter(MoveCounter &&Arg) : MoveCount(Arg.MoveCount) { ++MoveCount; } 188 }; 189 190 unique_function<void(MoveCounter)> ByValF = [](MoveCounter) {}; 191 int MoveCount = 0; 192 ByValF(MoveCounter(MoveCount)); 193 EXPECT_EQ(1, MoveCount); 194 195 MoveCount = 0; 196 { 197 MoveCounter Counter{MoveCount}; 198 ByValF(std::move(Counter)); 199 } 200 EXPECT_EQ(2, MoveCount); 201 202 // Check that when we use an r-value reference we get no spurious copies. 203 unique_function<void(MoveCounter &&)> ByRefF = [](MoveCounter &&) {}; 204 MoveCount = 0; 205 ByRefF(MoveCounter(MoveCount)); 206 EXPECT_EQ(0, MoveCount); 207 208 MoveCount = 0; 209 { 210 MoveCounter Counter{MoveCount}; 211 ByRefF(std::move(Counter)); 212 } 213 EXPECT_EQ(0, MoveCount); 214 215 // If we use an r-value reference we can in fact make a stronger guarantee 216 // with an unmovable type. 217 struct Unmovable { 218 Unmovable() = default; 219 Unmovable(Unmovable &&) = delete; 220 }; 221 unique_function<void(const Unmovable &)> UnmovableF = [](const Unmovable &) { 222 }; 223 UnmovableF(Unmovable()); 224 Unmovable X; 225 UnmovableF(X); 226 } 227 228 } // anonymous namespace 229