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 | #include <type_traits> |
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(p: 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 | TEST(UniqueFunctionTest, Const) { |
229 | // Can assign from const lambda. |
230 | unique_function<int(int) const> Plus2 = [X(std::make_unique<int>(args: 2))](int Y) { |
231 | return *X + Y; |
232 | }; |
233 | EXPECT_EQ(5, Plus2(3)); |
234 | |
235 | // Can call through a const ref. |
236 | const auto &Plus2Ref = Plus2; |
237 | EXPECT_EQ(5, Plus2Ref(3)); |
238 | |
239 | // Can move-construct and assign. |
240 | unique_function<int(int) const> Plus2A = std::move(Plus2); |
241 | EXPECT_EQ(5, Plus2A(3)); |
242 | unique_function<int(int) const> Plus2B; |
243 | Plus2B = std::move(Plus2A); |
244 | EXPECT_EQ(5, Plus2B(3)); |
245 | |
246 | // Can convert to non-const function type, but not back. |
247 | unique_function<int(int)> Plus2C = std::move(Plus2B); |
248 | EXPECT_EQ(5, Plus2C(3)); |
249 | |
250 | // Overloaded call operator correctly resolved. |
251 | struct ChooseCorrectOverload { |
252 | StringRef operator()() { return "non-const" ; } |
253 | StringRef operator()() const { return "const" ; } |
254 | }; |
255 | unique_function<StringRef()> ChooseMutable = ChooseCorrectOverload(); |
256 | ChooseCorrectOverload A; |
257 | EXPECT_EQ("non-const" , ChooseMutable()); |
258 | EXPECT_EQ("non-const" , A()); |
259 | unique_function<StringRef() const> ChooseConst = ChooseCorrectOverload(); |
260 | const ChooseCorrectOverload &X = A; |
261 | EXPECT_EQ("const" , ChooseConst()); |
262 | EXPECT_EQ("const" , X()); |
263 | } |
264 | |
265 | // Test that overloads on unique_functions are resolved as expected. |
266 | std::string returns(StringRef) { return "not a function" ; } |
267 | std::string returns(unique_function<double()> F) { return "number" ; } |
268 | std::string returns(unique_function<StringRef()> F) { return "string" ; } |
269 | |
270 | TEST(UniqueFunctionTest, SFINAE) { |
271 | EXPECT_EQ("not a function" , returns("boo!" )); |
272 | EXPECT_EQ("number" , returns([] { return 42; })); |
273 | EXPECT_EQ("string" , returns([] { return "hello" ; })); |
274 | } |
275 | |
276 | // A forward declared type, and a templated type. |
277 | class Incomplete; |
278 | template <typename T> class Templated { T A; }; |
279 | |
280 | // Check that we can define unique_function that have references to |
281 | // incomplete types, even if those types are templated over an |
282 | // incomplete type. |
283 | TEST(UniqueFunctionTest, IncompleteTypes) { |
284 | unique_function<void(Templated<Incomplete> &&)> |
285 | IncompleteArgumentRValueReference; |
286 | unique_function<void(Templated<Incomplete> &)> |
287 | IncompleteArgumentLValueReference; |
288 | unique_function<void(Templated<Incomplete> *)> IncompleteArgumentPointer; |
289 | unique_function<Templated<Incomplete> &()> IncompleteResultLValueReference; |
290 | unique_function<Templated<Incomplete> && ()> IncompleteResultRValueReference2; |
291 | unique_function<Templated<Incomplete> *()> IncompleteResultPointer; |
292 | } |
293 | |
294 | // Incomplete function returning an incomplete type |
295 | Incomplete incompleteFunction(); |
296 | const Incomplete incompleteFunctionConst(); |
297 | |
298 | // Check that we can assign a callable to a unique_function when the |
299 | // callable return value is incomplete. |
300 | TEST(UniqueFunctionTest, IncompleteCallableType) { |
301 | unique_function<Incomplete()> IncompleteReturnInCallable{incompleteFunction}; |
302 | unique_function<const Incomplete()> IncompleteReturnInCallableConst{ |
303 | incompleteFunctionConst}; |
304 | unique_function<const Incomplete()> IncompleteReturnInCallableConstConversion{ |
305 | incompleteFunction}; |
306 | } |
307 | |
308 | // Define the incomplete function |
309 | class Incomplete {}; |
310 | Incomplete incompleteFunction() { return {}; } |
311 | const Incomplete incompleteFunctionConst() { return {}; } |
312 | |
313 | } // anonymous namespace |
314 | |