• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //===- FunctionExtrasTest.cpp - Unit tests for function type erasure ------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #include "llvm/ADT/FunctionExtras.h"
11 #include "gtest/gtest.h"
12 
13 #include <memory>
14 
15 using namespace llvm;
16 
17 namespace {
18 
TEST(UniqueFunctionTest,Basic)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(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 
TEST(UniqueFunctionTest,Captures)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 
TEST(UniqueFunctionTest,MoveOnly)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 
TEST(UniqueFunctionTest,CountForwardingCopies)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 
TEST(UniqueFunctionTest,CountForwardingMoves)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 } // anonymous namespace
229