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