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 "gtest/gtest.h"
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);
22 unique_function
<int(int, int)> Sum2
= std::move(Sum
);
23 EXPECT_EQ(Sum2(1, 2), 3);
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);
29 Sum2
= unique_function
<int(int, int)>([](int A
, int B
) { return A
+ B
; });
30 EXPECT_EQ(Sum2(1, 2), 3);
32 // Explicit self-move test.
33 *&Sum2
= std::move(Sum2
);
34 EXPECT_EQ(Sum2(1, 2), 3);
36 Sum2
= unique_function
<int(int, int)>();
39 // Make sure we can forward through l-value reference parameters.
40 unique_function
<void(int &)> Inc
= [](int &X
) { ++X
; };
45 // Make sure we can forward through r-value reference parameters with
47 unique_function
<int(std::unique_ptr
<int> &&)> ReadAndDeallocByRef
=
48 [](std::unique_ptr
<int> &&Ptr
) {
53 std::unique_ptr
<int> Ptr
{new int(13)};
54 EXPECT_EQ(ReadAndDeallocByRef(std::move(Ptr
)), 13);
55 EXPECT_FALSE((bool)Ptr
);
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);
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
) {
67 Ptr
.reset(new int(13));
68 EXPECT_EQ(ReadAndDeallocByVal(std::move(Ptr
)), 13);
69 EXPECT_FALSE((bool)Ptr
);
71 EXPECT_EQ(ReadAndDeallocByVal(std::unique_ptr
<int>(new int(42))), 42);
74 TEST(UniqueFunctionTest
, Captures
) {
75 long A
= 1, B
= 2, C
= 3, D
= 4, E
= 5;
77 unique_function
<long()> Tmp
;
79 unique_function
<long()> C1
= [A
]() { return A
; };
84 unique_function
<long()> C2
= [A
, B
]() { return A
+ B
; };
89 unique_function
<long()> C3
= [A
, B
, C
]() { return A
+ B
+ C
; };
94 unique_function
<long()> C4
= [A
, B
, C
, D
]() { return A
+ B
+ C
+ D
; };
99 unique_function
<long()> C5
= [A
, B
, C
, D
, E
]() { return A
+ B
+ C
+ D
+ E
; };
102 EXPECT_EQ(Tmp(), 15);
105 TEST(UniqueFunctionTest
, MoveOnly
) {
106 struct SmallCallable
{
107 std::unique_ptr
<int> A
{new int(1)};
109 int operator()(int B
) { return *A
+ B
; }
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);
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)};
123 int operator()() { return *A
+ *B
+ *C
+ *D
+ *E
; }
125 unique_function
<int()> Large
= LargeCallable();
126 EXPECT_EQ(Large(), 15);
127 unique_function
<int()> Large2
= std::move(Large
);
128 EXPECT_EQ(Large2(), 15);
131 TEST(UniqueFunctionTest
, CountForwardingCopies
) {
135 CopyCounter(int &CopyCount
) : CopyCount(CopyCount
) {}
136 CopyCounter(const CopyCounter
&Arg
) : CopyCount(Arg
.CopyCount
) {
141 unique_function
<void(CopyCounter
)> ByValF
= [](CopyCounter
) {};
143 ByValF(CopyCounter(CopyCount
));
144 EXPECT_EQ(1, CopyCount
);
148 CopyCounter Counter
{CopyCount
};
151 EXPECT_EQ(2, CopyCount
);
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
&) {
158 ByRefF(CopyCounter(CopyCount
));
159 EXPECT_EQ(0, CopyCount
);
163 CopyCounter Counter
{CopyCount
};
166 EXPECT_EQ(0, CopyCount
);
168 // If we use a reference, we can make a stronger guarantee that *no* copy
171 Uncopyable() = default;
172 Uncopyable(const Uncopyable
&) = delete;
174 unique_function
<void(const Uncopyable
&)> UncopyableF
=
175 [](const Uncopyable
&) {};
176 UncopyableF(Uncopyable());
181 TEST(UniqueFunctionTest
, CountForwardingMoves
) {
185 MoveCounter(int &MoveCount
) : MoveCount(MoveCount
) {}
186 MoveCounter(MoveCounter
&&Arg
) : MoveCount(Arg
.MoveCount
) { ++MoveCount
; }
189 unique_function
<void(MoveCounter
)> ByValF
= [](MoveCounter
) {};
191 ByValF(MoveCounter(MoveCount
));
192 EXPECT_EQ(1, MoveCount
);
196 MoveCounter Counter
{MoveCount
};
197 ByValF(std::move(Counter
));
199 EXPECT_EQ(2, MoveCount
);
201 // Check that when we use an r-value reference we get no spurious copies.
202 unique_function
<void(MoveCounter
&&)> ByRefF
= [](MoveCounter
&&) {};
204 ByRefF(MoveCounter(MoveCount
));
205 EXPECT_EQ(0, MoveCount
);
209 MoveCounter Counter
{MoveCount
};
210 ByRefF(std::move(Counter
));
212 EXPECT_EQ(0, MoveCount
);
214 // If we use an r-value reference we can in fact make a stronger guarantee
215 // with an unmovable type.
217 Unmovable() = default;
218 Unmovable(Unmovable
&&) = delete;
220 unique_function
<void(const Unmovable
&)> UnmovableF
= [](const Unmovable
&) {
222 UnmovableF(Unmovable());
227 } // anonymous namespace