1 //===- FunctionExtrasTest.cpp - Unit tests for function type erasure ------===//
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
7 //===----------------------------------------------------------------------===//
9 #include "llvm/ADT/FunctionExtras.h"
10 #include "CountCopyAndMove.h"
11 #include "gtest/gtest.h"
14 #include <type_traits>
20 TEST(UniqueFunctionTest
, Basic
) {
21 unique_function
<int(int, int)> Sum
= [](int A
, int B
) { return A
+ B
; };
22 EXPECT_EQ(Sum(1, 2), 3);
24 unique_function
<int(int, int)> Sum2
= std::move(Sum
);
25 EXPECT_EQ(Sum2(1, 2), 3);
27 unique_function
<int(int, int)> Sum3
= [](int A
, int B
) { return A
+ B
; };
28 Sum2
= std::move(Sum3
);
29 EXPECT_EQ(Sum2(1, 2), 3);
31 Sum2
= unique_function
<int(int, int)>([](int A
, int B
) { return A
+ B
; });
32 EXPECT_EQ(Sum2(1, 2), 3);
34 // Explicit self-move test.
35 *&Sum2
= std::move(Sum2
);
36 EXPECT_EQ(Sum2(1, 2), 3);
38 Sum2
= unique_function
<int(int, int)>();
41 // Make sure we can forward through l-value reference parameters.
42 unique_function
<void(int &)> Inc
= [](int &X
) { ++X
; };
47 // Make sure we can forward through r-value reference parameters with
49 unique_function
<int(std::unique_ptr
<int> &&)> ReadAndDeallocByRef
=
50 [](std::unique_ptr
<int> &&Ptr
) {
55 std::unique_ptr
<int> Ptr
{new int(13)};
56 EXPECT_EQ(ReadAndDeallocByRef(std::move(Ptr
)), 13);
57 EXPECT_FALSE((bool)Ptr
);
59 // Make sure we can pass a move-only temporary as opposed to a local variable.
60 EXPECT_EQ(ReadAndDeallocByRef(std::unique_ptr
<int>(new int(42))), 42);
62 // Make sure we can pass a move-only type by-value.
63 unique_function
<int(std::unique_ptr
<int>)> ReadAndDeallocByVal
=
64 [](std::unique_ptr
<int> Ptr
) {
69 Ptr
.reset(new int(13));
70 EXPECT_EQ(ReadAndDeallocByVal(std::move(Ptr
)), 13);
71 EXPECT_FALSE((bool)Ptr
);
73 EXPECT_EQ(ReadAndDeallocByVal(std::unique_ptr
<int>(new int(42))), 42);
76 TEST(UniqueFunctionTest
, Captures
) {
77 long A
= 1, B
= 2, C
= 3, D
= 4, E
= 5;
79 unique_function
<long()> Tmp
;
81 unique_function
<long()> C1
= [A
]() { return A
; };
86 unique_function
<long()> C2
= [A
, B
]() { return A
+ B
; };
91 unique_function
<long()> C3
= [A
, B
, C
]() { return A
+ B
+ C
; };
96 unique_function
<long()> C4
= [A
, B
, C
, D
]() { return A
+ B
+ C
+ D
; };
101 unique_function
<long()> C5
= [A
, B
, C
, D
, E
]() { return A
+ B
+ C
+ D
+ E
; };
104 EXPECT_EQ(Tmp(), 15);
107 TEST(UniqueFunctionTest
, MoveOnly
) {
108 struct SmallCallable
{
109 std::unique_ptr
<int> A
{new int(1)};
111 int operator()(int B
) { return *A
+ B
; }
113 unique_function
<int(int)> Small
= SmallCallable();
114 EXPECT_EQ(Small(2), 3);
115 unique_function
<int(int)> Small2
= std::move(Small
);
116 EXPECT_EQ(Small2(2), 3);
118 struct LargeCallable
{
119 std::unique_ptr
<int> A
{new int(1)};
120 std::unique_ptr
<int> B
{new int(2)};
121 std::unique_ptr
<int> C
{new int(3)};
122 std::unique_ptr
<int> D
{new int(4)};
123 std::unique_ptr
<int> E
{new int(5)};
125 int operator()() { return *A
+ *B
+ *C
+ *D
+ *E
; }
127 unique_function
<int()> Large
= LargeCallable();
128 EXPECT_EQ(Large(), 15);
129 unique_function
<int()> Large2
= std::move(Large
);
130 EXPECT_EQ(Large2(), 15);
133 TEST(UniqueFunctionTest
, CountForwardingCopies
) {
137 CopyCounter(int &CopyCount
) : CopyCount(CopyCount
) {}
138 CopyCounter(const CopyCounter
&Arg
) : CopyCount(Arg
.CopyCount
) {
143 unique_function
<void(CopyCounter
)> ByValF
= [](CopyCounter
) {};
145 ByValF(CopyCounter(CopyCount
));
146 EXPECT_EQ(1, CopyCount
);
150 CopyCounter Counter
{CopyCount
};
153 EXPECT_EQ(2, CopyCount
);
155 // Check that we don't generate a copy at all when we can bind a reference all
156 // the way down, even if that reference could *in theory* allow copies.
157 unique_function
<void(const CopyCounter
&)> ByRefF
= [](const CopyCounter
&) {
160 ByRefF(CopyCounter(CopyCount
));
161 EXPECT_EQ(0, CopyCount
);
165 CopyCounter Counter
{CopyCount
};
168 EXPECT_EQ(0, CopyCount
);
170 // If we use a reference, we can make a stronger guarantee that *no* copy
173 Uncopyable() = default;
174 Uncopyable(const Uncopyable
&) = delete;
176 unique_function
<void(const Uncopyable
&)> UncopyableF
=
177 [](const Uncopyable
&) {};
178 UncopyableF(Uncopyable());
183 TEST(UniqueFunctionTest
, CountForwardingMoves
) {
187 MoveCounter(int &MoveCount
) : MoveCount(MoveCount
) {}
188 MoveCounter(MoveCounter
&&Arg
) : MoveCount(Arg
.MoveCount
) { ++MoveCount
; }
191 unique_function
<void(MoveCounter
)> ByValF
= [](MoveCounter
) {};
193 ByValF(MoveCounter(MoveCount
));
194 EXPECT_EQ(1, MoveCount
);
198 MoveCounter Counter
{MoveCount
};
199 ByValF(std::move(Counter
));
201 EXPECT_EQ(2, MoveCount
);
203 // Check that when we use an r-value reference we get no spurious copies.
204 unique_function
<void(MoveCounter
&&)> ByRefF
= [](MoveCounter
&&) {};
206 ByRefF(MoveCounter(MoveCount
));
207 EXPECT_EQ(0, MoveCount
);
211 MoveCounter Counter
{MoveCount
};
212 ByRefF(std::move(Counter
));
214 EXPECT_EQ(0, MoveCount
);
216 // If we use an r-value reference we can in fact make a stronger guarantee
217 // with an unmovable type.
219 Unmovable() = default;
220 Unmovable(Unmovable
&&) = delete;
222 unique_function
<void(const Unmovable
&)> UnmovableF
= [](const Unmovable
&) {
224 UnmovableF(Unmovable());
229 TEST(UniqueFunctionTest
, Const
) {
230 // Can assign from const lambda.
231 unique_function
<int(int) const> Plus2
= [X(std::make_unique
<int>(2))](int Y
) {
234 EXPECT_EQ(5, Plus2(3));
236 // Can call through a const ref.
237 const auto &Plus2Ref
= Plus2
;
238 EXPECT_EQ(5, Plus2Ref(3));
240 // Can move-construct and assign.
241 unique_function
<int(int) const> Plus2A
= std::move(Plus2
);
242 EXPECT_EQ(5, Plus2A(3));
243 unique_function
<int(int) const> Plus2B
;
244 Plus2B
= std::move(Plus2A
);
245 EXPECT_EQ(5, Plus2B(3));
247 // Can convert to non-const function type, but not back.
248 unique_function
<int(int)> Plus2C
= std::move(Plus2B
);
249 EXPECT_EQ(5, Plus2C(3));
251 // Overloaded call operator correctly resolved.
252 struct ChooseCorrectOverload
{
253 StringRef
operator()() { return "non-const"; }
254 StringRef
operator()() const { return "const"; }
256 unique_function
<StringRef()> ChooseMutable
= ChooseCorrectOverload();
257 ChooseCorrectOverload A
;
258 EXPECT_EQ("non-const", ChooseMutable());
259 EXPECT_EQ("non-const", A());
260 unique_function
<StringRef() const> ChooseConst
= ChooseCorrectOverload();
261 const ChooseCorrectOverload
&X
= A
;
262 EXPECT_EQ("const", ChooseConst());
263 EXPECT_EQ("const", X());
266 // Test that overloads on unique_functions are resolved as expected.
267 std::string
returns(StringRef
) { return "not a function"; }
268 std::string
returns(unique_function
<double()> F
) { return "number"; }
269 std::string
returns(unique_function
<StringRef()> F
) { return "string"; }
271 TEST(UniqueFunctionTest
, SFINAE
) {
272 EXPECT_EQ("not a function", returns("boo!"));
273 EXPECT_EQ("number", returns([] { return 42; }));
274 EXPECT_EQ("string", returns([] { return "hello"; }));
277 // A forward declared type, and a templated type.
279 template <typename T
> class Templated
{ T A
; };
281 // Check that we can define unique_function that have references to
282 // incomplete types, even if those types are templated over an
284 TEST(UniqueFunctionTest
, IncompleteTypes
) {
285 unique_function
<void(Templated
<Incomplete
> &&)>
286 IncompleteArgumentRValueReference
;
287 unique_function
<void(Templated
<Incomplete
> &)>
288 IncompleteArgumentLValueReference
;
289 unique_function
<void(Templated
<Incomplete
> *)> IncompleteArgumentPointer
;
290 unique_function
<Templated
<Incomplete
> &()> IncompleteResultLValueReference
;
291 unique_function
<Templated
<Incomplete
> && ()> IncompleteResultRValueReference2
;
292 unique_function
<Templated
<Incomplete
> *()> IncompleteResultPointer
;
295 // Incomplete function returning an incomplete type
296 Incomplete
incompleteFunction();
297 const Incomplete
incompleteFunctionConst();
299 // Check that we can assign a callable to a unique_function when the
300 // callable return value is incomplete.
301 TEST(UniqueFunctionTest
, IncompleteCallableType
) {
302 unique_function
<Incomplete()> IncompleteReturnInCallable
{incompleteFunction
};
303 unique_function
<const Incomplete()> IncompleteReturnInCallableConst
{
304 incompleteFunctionConst
};
305 unique_function
<const Incomplete()> IncompleteReturnInCallableConstConversion
{
309 // Define the incomplete function
311 Incomplete
incompleteFunction() { return {}; }
312 const Incomplete
incompleteFunctionConst() { return {}; }
314 // Check that we can store a pointer-sized payload inline in the unique_function.
315 TEST(UniqueFunctionTest
, InlineStorageWorks
) {
316 // We do assume a couple of implementation details of the unique_function here:
317 // - It can store certain small-enough payload inline
318 // - Inline storage size is at least >= sizeof(void*)
320 unique_function
<void(void *)> UniqueFunctionWithInlineStorage
{
322 auto mid
= reinterpret_cast<uintptr_t>(&ptr
);
323 auto beg
= reinterpret_cast<uintptr_t>(self
);
324 auto end
= reinterpret_cast<uintptr_t>(self
) +
325 sizeof(unique_function
<void(void *)>);
326 // Make sure the address of the captured pointer lies somewhere within
327 // the unique_function object.
328 EXPECT_TRUE(mid
>= beg
&& mid
< end
);
330 UniqueFunctionWithInlineStorage(&UniqueFunctionWithInlineStorage
);
333 // Check that the moved-from captured state is properly destroyed during
334 // move construction/assignment.
335 TEST(UniqueFunctionTest
, MovedFromStateIsDestroyedCorrectly
) {
336 CountCopyAndMove::ResetCounts();
338 unique_function
<void()> CapturingFunction
{
339 [Counter
= CountCopyAndMove
{}] {}};
340 unique_function
<void()> CapturingFunctionMoved
{
341 std::move(CapturingFunction
)};
343 EXPECT_EQ(CountCopyAndMove::TotalConstructions(),
344 CountCopyAndMove::Destructions
);
347 } // anonymous namespace