template< -> template <
[folly.git] / folly / test / ApplyTupleTest.cpp
1 /*
2  * Copyright 2017 Facebook, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *   http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include <iostream>
18
19 #include <folly/ApplyTuple.h>
20 #include <folly/portability/GTest.h>
21
22 #include <array>
23 #include <memory>
24
25 // this placates visual studio stupidity - see
26 // http://stackoverflow.com/questions/5503901
27 namespace {}
28
29 namespace {
30
31 void func(int a, int b, double c) {
32   EXPECT_EQ(a, 1);
33   EXPECT_EQ(b, 2);
34   EXPECT_EQ(c, 3.0);
35 }
36
37 struct Wat {
38   void func(int a, int b, double c) {
39     ::func(a, b, c);
40   }
41
42   double retVal(int a, double b) {
43     return a + b;
44   }
45
46   Wat() {}
47   Wat(Wat const&) = delete;
48
49   int foo;
50 };
51
52 struct Overloaded {
53   int func(int) { return 0; }
54   bool func(bool) { return true; }
55 };
56
57 struct Func {
58   int operator()() const {
59     return 1;
60   }
61 };
62
63 struct CopyCount {
64   CopyCount() {}
65   CopyCount(CopyCount const&) {
66     std::cout << "copy count copy ctor\n";
67   }
68 };
69
70 void anotherFunc(CopyCount const&) {}
71
72 std::function<void (int, int, double)> makeFunc() {
73   return &func;
74 }
75
76 struct GuardObjBase {
77   GuardObjBase(GuardObjBase&&) noexcept {}
78   GuardObjBase() {}
79   GuardObjBase(GuardObjBase const&) = delete;
80   GuardObjBase& operator=(GuardObjBase const&) = delete;
81 };
82 typedef GuardObjBase const& Guard;
83
84 template <class F, class Tuple>
85 struct GuardObj : GuardObjBase {
86   explicit GuardObj(F&& f, Tuple&& args)
87     : f_(std::forward<F>(f))
88     , args_(std::forward<Tuple>(args))
89   {}
90   GuardObj(GuardObj&& g) noexcept
91     : GuardObjBase(std::move(g))
92     , f_(std::move(g.f_))
93     , args_(std::move(g.args_))
94   {}
95
96   ~GuardObj() {
97     folly::applyTuple(f_, args_);
98   }
99
100   GuardObj(const GuardObj&) = delete;
101   GuardObj& operator=(const GuardObj&) = delete;
102
103 private:
104   F f_;
105   Tuple args_;
106 };
107
108 template <class F, class... Args>
109 GuardObj<typename std::decay<F>::type,std::tuple<Args...>>
110 guard(F&& f, Args&&... args) {
111   return GuardObj<typename std::decay<F>::type,std::tuple<Args...>>(
112     std::forward<F>(f),
113     std::tuple<Args...>(std::forward<Args>(args)...)
114   );
115 }
116
117 struct Mover {
118   Mover() {}
119   Mover(Mover&&) noexcept {}
120   Mover(const Mover&) = delete;
121   Mover& operator=(const Mover&) = delete;
122 };
123
124 void move_only_func(Mover&&) {}
125
126 }
127
128 TEST(ApplyTuple, Test) {
129   auto argsTuple = std::make_tuple(1, 2, 3.0);
130   auto func2 = func;
131   folly::applyTuple(func2, argsTuple);
132   folly::applyTuple(func, argsTuple);
133   folly::applyTuple(func, std::make_tuple(1, 2, 3.0));
134   folly::applyTuple(makeFunc(), std::make_tuple(1, 2, 3.0));
135   folly::applyTuple(makeFunc(), argsTuple);
136
137   std::unique_ptr<Wat> wat(new Wat);
138   folly::applyTuple(&Wat::func, std::make_tuple(wat.get(), 1, 2, 3.0));
139   auto argsTuple2 = std::make_tuple(wat.get(), 1, 2, 3.0);
140   folly::applyTuple(&Wat::func, argsTuple2);
141
142   EXPECT_EQ(10.0,
143             folly::applyTuple(&Wat::retVal,
144                               std::make_tuple(wat.get(), 1, 9.0)));
145
146   auto test = guard(func, 1, 2, 3.0);
147   CopyCount cpy;
148   auto test2 = guard(anotherFunc, cpy);
149   auto test3 = guard(anotherFunc, std::cref(cpy));
150
151   Overloaded ovl;
152   EXPECT_EQ(0,
153             folly::applyTuple(
154               static_cast<int (Overloaded::*)(int)>(&Overloaded::func),
155               std::make_tuple(&ovl, 12)));
156   EXPECT_EQ(
157       /* do not code-mode to EXPECT_TRUE */ true,
158       folly::applyTuple(
159           static_cast<bool (Overloaded::*)(bool)>(&Overloaded::func),
160           std::make_tuple(&ovl, false)));
161
162   int x = folly::applyTuple(std::plus<int>(), std::make_tuple(12, 12));
163   EXPECT_EQ(24, x);
164
165   Mover m;
166   folly::applyTuple(move_only_func,
167                     std::forward_as_tuple(std::forward<Mover>(Mover())));
168   const auto tuple3 = std::make_tuple(1, 2, 3.0);
169   folly::applyTuple(func, tuple3);
170 }
171
172 TEST(ApplyTuple, Mutable) {
173   auto argsTuple = std::make_tuple(1, 2, 3.0);
174
175   folly::applyTuple([](int a, int b, double c) mutable { func(a, b, c); },
176                     argsTuple);
177 }
178
179 TEST(ApplyTuple, ConstOverloads) {
180   struct ConstOverloaded {
181     ConstOverloaded() {}
182     int operator()() { return 101; }
183     int operator()() const { return 102; }
184   };
185
186   ConstOverloaded covl;
187
188   // call operator()()
189   EXPECT_EQ(folly::applyTuple(covl, std::make_tuple()), 101);
190   EXPECT_EQ(folly::applyTuple(std::ref(covl), std::make_tuple()), 101);
191   EXPECT_EQ(folly::applyTuple(std::move(covl), std::make_tuple()), 101);
192
193   // call operator()() const
194   EXPECT_EQ(folly::applyTuple(const_cast<ConstOverloaded const&>(covl),
195                               std::make_tuple()),
196             102);
197   EXPECT_EQ(folly::applyTuple(std::cref(covl), std::make_tuple()), 102);
198 }
199
200 TEST(ApplyTuple, RefOverloads) {
201   struct RefOverloaded {
202     RefOverloaded() {}
203     int operator()() & { return 201; }
204     int operator()() const & { return 202; }
205     int operator()() && { return 203; }
206   };
207
208   RefOverloaded rovl;
209
210   // call operator()() &
211   EXPECT_EQ(folly::applyTuple(rovl, std::make_tuple()), 201);
212   EXPECT_EQ(folly::applyTuple(std::ref(rovl), std::make_tuple()), 201);
213
214   // call operator()() const &
215   EXPECT_EQ(folly::applyTuple(const_cast<RefOverloaded const&>(rovl),
216                               std::make_tuple()),
217             202);
218   EXPECT_EQ(folly::applyTuple(std::cref(rovl), std::make_tuple()), 202);
219
220   // call operator()() &&
221   EXPECT_EQ(folly::applyTuple(std::move(rovl), std::make_tuple()), 203);
222 }
223
224 struct MemberFunc {
225   int x;
226   int getX() const { return x; }
227   void setX(int xx) { x = xx; }
228 };
229
230 TEST(ApplyTuple, MemberFunction) {
231   MemberFunc mf;
232   mf.x = 123;
233
234   // call getter
235   EXPECT_EQ(folly::applyTuple(&MemberFunc::getX, std::make_tuple(&mf)), 123);
236
237   // call setter
238   folly::applyTuple(&MemberFunc::setX, std::make_tuple(&mf, 234));
239   EXPECT_EQ(mf.x, 234);
240   EXPECT_EQ(folly::applyTuple(&MemberFunc::getX, std::make_tuple(&mf)), 234);
241 }
242
243 TEST(ApplyTuple, MemberFunctionWithRefWrapper) {
244   MemberFunc mf;
245   mf.x = 234;
246
247   EXPECT_EQ(folly::applyTuple(&MemberFunc::getX, std::make_tuple(std::ref(mf))),
248             234);
249 }
250
251 TEST(ApplyTuple, MemberFunctionWithConstPointer) {
252   MemberFunc mf;
253   mf.x = 234;
254
255   EXPECT_EQ(
256       folly::applyTuple(&MemberFunc::getX,
257                         std::make_tuple(const_cast<MemberFunc const*>(&mf))),
258       234);
259 }
260
261 TEST(ApplyTuple, MemberFunctionWithSharedPtr) {
262   MemberFunc mf;
263   mf.x = 234;
264
265   EXPECT_EQ(
266       folly::applyTuple(&MemberFunc::getX,
267                         std::make_tuple(std::make_shared<MemberFunc>(mf))),
268       234);
269 }
270
271 TEST(ApplyTuple, MemberFunctionWithUniquePtr) {
272   MemberFunc mf;
273   mf.x = 234;
274
275   EXPECT_EQ(folly::applyTuple(&MemberFunc::getX,
276                               std::make_tuple(std::unique_ptr<MemberFunc>(
277                                   new MemberFunc(mf)))),
278             234);
279 }
280
281 TEST(ApplyTuple, Array) {
282   folly::applyTuple(func, std::array<int, 3>{{1, 2, 3}});
283   folly::applyTuple(func, std::array<double, 3>{{1, 2, 3}});
284 }
285
286 TEST(ApplyTuple, Pair) {
287   auto add = [](int x, int y) { return x + y; };
288
289   EXPECT_EQ(folly::applyTuple(add, std::pair<int, int>{1200, 34}), 1234);
290 }
291
292 TEST(ApplyTuple, MultipleTuples) {
293   auto add = [](int x, int y, int z) { return x * 100 + y * 10 + z; };
294
295   EXPECT_EQ(123, folly::applyTuple(add, std::make_tuple(1, 2, 3)));
296   EXPECT_EQ(
297       123, folly::applyTuple(add, std::make_tuple(1, 2, 3), std::make_tuple()));
298   EXPECT_EQ(
299       123, folly::applyTuple(add, std::make_tuple(1, 2), std::make_tuple(3)));
300   EXPECT_EQ(
301       123, folly::applyTuple(add, std::make_tuple(1), std::make_tuple(2, 3)));
302   EXPECT_EQ(
303       123, folly::applyTuple(add, std::make_tuple(), std::make_tuple(1, 2, 3)));
304
305   EXPECT_EQ(
306       123,
307       folly::applyTuple(
308           add, std::make_tuple(1, 2, 3), std::make_tuple(), std::make_tuple()));
309   EXPECT_EQ(
310       123,
311       folly::applyTuple(
312           add, std::make_tuple(1), std::make_tuple(2), std::make_tuple(3)));
313   EXPECT_EQ(
314       123,
315       folly::applyTuple(
316           add, std::make_tuple(1), std::make_tuple(), std::make_tuple(2, 3)));
317 }
318
319 TEST(ApplyTuple, UncurryCopyMove) {
320   std::string separator = "================================\n";
321   auto formatRow = folly::uncurry([=](std::string a, std::string b) {
322     // capture separator by copy
323     return separator + a + "\n" + b + "\n" + separator;
324   });
325   auto row = std::make_tuple("hello", "world");
326   auto expected = separator + "hello\nworld\n" + separator;
327   EXPECT_EQ(expected, formatRow(row));
328   auto formatRowCopy = formatRow;
329   EXPECT_EQ(expected, formatRowCopy(row));
330   auto formatRowMove = std::move(formatRow);
331   EXPECT_EQ(expected, formatRowMove(row));
332
333   // capture value moved out from formatRow
334   EXPECT_NE(expected, formatRow(row));
335 }
336
337 TEST(ApplyTuple, Uncurry) {
338   EXPECT_EQ(42, folly::uncurry([](int x, int y) {
339               return x * y;
340             })(std::pair<int, int>(6, 7)));
341   EXPECT_EQ(42, folly::uncurry([](int&& x, int&& y) {
342               return x * y;
343             })(std::pair<int&&, int&&>(6, 7)));
344   EXPECT_EQ(42, folly::uncurry([](int&& x, int&& y) {
345               return x * y;
346             })(std::pair<int&&, int&&>(6, 7)));
347
348   std::string long1 = "a long string exceeding small string size";
349   std::string long2 = "and here is another one!";
350   std::string expected = long1 + long2;
351
352   auto cat = folly::uncurry(
353       [](std::string a, std::string b) { return std::move(a) + std::move(b); });
354
355   EXPECT_EQ(expected, cat(std::make_pair(long1, long2)));
356   EXPECT_FALSE(long1.empty());
357   EXPECT_FALSE(long2.empty());
358   EXPECT_EQ(expected, cat(std::tie(long1, long2)));
359   EXPECT_FALSE(long1.empty());
360   EXPECT_FALSE(long2.empty());
361   EXPECT_EQ(
362       expected, cat(std::forward_as_tuple(std::move(long1), std::move(long2))));
363   EXPECT_TRUE(long1.empty());
364   EXPECT_TRUE(long2.empty());
365 }
366
367 TEST(ApplyTuple, UncurryStdFind) {
368   std::vector<std::pair<int, int>> v{{1, 9}, {2, 8}, {3, 7}, {4, 6}, {5, 5}};
369   EXPECT_EQ(
370       3, std::count_if(v.begin(), v.end(), folly::uncurry([](int a, int b) {
371                          return b % a == 0;
372                        })));
373 }