e56d85ac7e6ab5099d194c9cbcae3f0439956787
[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(true,
157             folly::applyTuple(
158               static_cast<bool (Overloaded::*)(bool)>(&Overloaded::func),
159               std::make_tuple(&ovl, false)));
160
161   int x = folly::applyTuple(std::plus<int>(), std::make_tuple(12, 12));
162   EXPECT_EQ(24, x);
163
164   Mover m;
165   folly::applyTuple(move_only_func,
166                     std::forward_as_tuple(std::forward<Mover>(Mover())));
167   const auto tuple3 = std::make_tuple(1, 2, 3.0);
168   folly::applyTuple(func, tuple3);
169 }
170
171 TEST(ApplyTuple, Mutable) {
172   auto argsTuple = std::make_tuple(1, 2, 3.0);
173
174   folly::applyTuple([](int a, int b, double c) mutable { func(a, b, c); },
175                     argsTuple);
176 }
177
178 TEST(ApplyTuple, ConstOverloads) {
179   struct ConstOverloaded {
180     ConstOverloaded() {}
181     int operator()() { return 101; }
182     int operator()() const { return 102; }
183   };
184
185   ConstOverloaded covl;
186
187   // call operator()()
188   EXPECT_EQ(folly::applyTuple(covl, std::make_tuple()), 101);
189   EXPECT_EQ(folly::applyTuple(std::ref(covl), std::make_tuple()), 101);
190   EXPECT_EQ(folly::applyTuple(std::move(covl), std::make_tuple()), 101);
191
192   // call operator()() const
193   EXPECT_EQ(folly::applyTuple(const_cast<ConstOverloaded const&>(covl),
194                               std::make_tuple()),
195             102);
196   EXPECT_EQ(folly::applyTuple(std::cref(covl), std::make_tuple()), 102);
197 }
198
199 TEST(ApplyTuple, RefOverloads) {
200   struct RefOverloaded {
201     RefOverloaded() {}
202     int operator()() & { return 201; }
203     int operator()() const & { return 202; }
204     int operator()() && { return 203; }
205   };
206
207   RefOverloaded rovl;
208
209   // call operator()() &
210   EXPECT_EQ(folly::applyTuple(rovl, std::make_tuple()), 201);
211   EXPECT_EQ(folly::applyTuple(std::ref(rovl), std::make_tuple()), 201);
212
213   // call operator()() const &
214   EXPECT_EQ(folly::applyTuple(const_cast<RefOverloaded const&>(rovl),
215                               std::make_tuple()),
216             202);
217   EXPECT_EQ(folly::applyTuple(std::cref(rovl), std::make_tuple()), 202);
218
219   // call operator()() &&
220   EXPECT_EQ(folly::applyTuple(std::move(rovl), std::make_tuple()), 203);
221 }
222
223 struct MemberFunc {
224   int x;
225   int getX() const { return x; }
226   void setX(int xx) { x = xx; }
227 };
228
229 TEST(ApplyTuple, MemberFunction) {
230   MemberFunc mf;
231   mf.x = 123;
232
233   // call getter
234   EXPECT_EQ(folly::applyTuple(&MemberFunc::getX, std::make_tuple(&mf)), 123);
235
236   // call setter
237   folly::applyTuple(&MemberFunc::setX, std::make_tuple(&mf, 234));
238   EXPECT_EQ(mf.x, 234);
239   EXPECT_EQ(folly::applyTuple(&MemberFunc::getX, std::make_tuple(&mf)), 234);
240 }
241
242 TEST(ApplyTuple, MemberFunctionWithRefWrapper) {
243   MemberFunc mf;
244   mf.x = 234;
245
246   EXPECT_EQ(folly::applyTuple(&MemberFunc::getX, std::make_tuple(std::ref(mf))),
247             234);
248 }
249
250 TEST(ApplyTuple, MemberFunctionWithConstPointer) {
251   MemberFunc mf;
252   mf.x = 234;
253
254   EXPECT_EQ(
255       folly::applyTuple(&MemberFunc::getX,
256                         std::make_tuple(const_cast<MemberFunc const*>(&mf))),
257       234);
258 }
259
260 TEST(ApplyTuple, MemberFunctionWithSharedPtr) {
261   MemberFunc mf;
262   mf.x = 234;
263
264   EXPECT_EQ(
265       folly::applyTuple(&MemberFunc::getX,
266                         std::make_tuple(std::make_shared<MemberFunc>(mf))),
267       234);
268 }
269
270 TEST(ApplyTuple, MemberFunctionWithUniquePtr) {
271   MemberFunc mf;
272   mf.x = 234;
273
274   EXPECT_EQ(folly::applyTuple(&MemberFunc::getX,
275                               std::make_tuple(std::unique_ptr<MemberFunc>(
276                                   new MemberFunc(mf)))),
277             234);
278 }
279
280 TEST(ApplyTuple, Array) {
281   folly::applyTuple(func, std::array<int, 3>{{1, 2, 3}});
282   folly::applyTuple(func, std::array<double, 3>{{1, 2, 3}});
283 }
284
285 TEST(ApplyTuple, Pair) {
286   auto add = [](int x, int y) { return x + y; };
287
288   EXPECT_EQ(folly::applyTuple(add, std::pair<int, int>{1200, 34}), 1234);
289 }
290
291 TEST(ApplyTuple, MultipleTuples) {
292   auto add = [](int x, int y, int z) { return x * 100 + y * 10 + z; };
293
294   EXPECT_EQ(123, folly::applyTuple(add, std::make_tuple(1, 2, 3)));
295   EXPECT_EQ(
296       123, folly::applyTuple(add, std::make_tuple(1, 2, 3), std::make_tuple()));
297   EXPECT_EQ(
298       123, folly::applyTuple(add, std::make_tuple(1, 2), std::make_tuple(3)));
299   EXPECT_EQ(
300       123, folly::applyTuple(add, std::make_tuple(1), std::make_tuple(2, 3)));
301   EXPECT_EQ(
302       123, folly::applyTuple(add, std::make_tuple(), std::make_tuple(1, 2, 3)));
303
304   EXPECT_EQ(
305       123,
306       folly::applyTuple(
307           add, std::make_tuple(1, 2, 3), std::make_tuple(), std::make_tuple()));
308   EXPECT_EQ(
309       123,
310       folly::applyTuple(
311           add, std::make_tuple(1), std::make_tuple(2), std::make_tuple(3)));
312   EXPECT_EQ(
313       123,
314       folly::applyTuple(
315           add, std::make_tuple(1), std::make_tuple(), std::make_tuple(2, 3)));
316 }