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