1/*
2 * Copyright 2012-present 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/Overload.h>
20#include <folly/functional/ApplyTuple.h>
21#include <folly/portability/GTest.h>
22
23#include <array>
24#include <memory>
25
26namespace {
27
28void func(int a, int b, double c) {
29 EXPECT_EQ(a, 1);
30 EXPECT_EQ(b, 2);
31 EXPECT_EQ(c, 3.0);
32}
33
34struct Wat {
35 void func(int a, int b, double c) {
36 ::func(a, b, c);
37 }
38
39 double retVal(int a, double b) {
40 return a + b;
41 }
42
43 Wat() {}
44 Wat(Wat const&) = delete;
45
46 int foo;
47};
48
49struct Overloaded {
50 int func(int) {
51 return 0;
52 }
53 bool func(bool) {
54 return true;
55 }
56};
57
58struct Func {
59 int operator()() const {
60 return 1;
61 }
62};
63
64struct CopyCount {
65 CopyCount() {}
66 CopyCount(CopyCount const&) {
67 std::cout << "copy count copy ctor\n";
68 }
69};
70
71void anotherFunc(CopyCount const&) {}
72
73std::function<void(int, int, double)> makeFunc() {
74 return &func;
75}
76
77struct GuardObjBase {
78 GuardObjBase(GuardObjBase&&) noexcept {}
79 GuardObjBase() {}
80 GuardObjBase(GuardObjBase const&) = delete;
81 GuardObjBase& operator=(GuardObjBase const&) = delete;
82};
83typedef GuardObjBase const& Guard;
84
85template <class F, class Tuple>
86struct GuardObj : GuardObjBase {
87 explicit GuardObj(F&& f, Tuple&& args)
88 : f_(std::forward<F>(f)), args_(std::forward<Tuple>(args)) {}
89 GuardObj(GuardObj&& g) noexcept
90 : GuardObjBase(std::move(g)),
91 f_(std::move(g.f_)),
92 args_(std::move(g.args_)) {}
93
94 ~GuardObj() {
95 folly::apply(f_, args_);
96 }
97
98 GuardObj(const GuardObj&) = delete;
99 GuardObj& operator=(const GuardObj&) = delete;
100
101 private:
102 F f_;
103 Tuple args_;
104};
105
106template <class F, class... Args>
107GuardObj<typename std::decay<F>::type, std::tuple<Args...>> guard(
108 F&& f,
109 Args&&... args) {
110 return GuardObj<typename std::decay<F>::type, std::tuple<Args...>>(
111 std::forward<F>(f), std::tuple<Args...>(std::forward<Args>(args)...));
112}
113
114struct Mover {
115 Mover() {}
116 Mover(Mover&&) noexcept {}
117 Mover(const Mover&) = delete;
118 Mover& operator=(const Mover&) = delete;
119};
120
121void move_only_func(Mover&&) {}
122
123} // namespace
124
125TEST(ApplyTuple, Test) {
126 auto argsTuple = std::make_tuple(1, 2, 3.0);
127 auto func2 = func;
128 folly::apply(func2, argsTuple);
129 folly::apply(func, argsTuple);
130 folly::apply(func, std::make_tuple(1, 2, 3.0));
131 folly::apply(makeFunc(), std::make_tuple(1, 2, 3.0));
132 folly::apply(makeFunc(), argsTuple);
133
134 std::unique_ptr<Wat> wat(new Wat);
135 folly::apply(&Wat::func, std::make_tuple(wat.get(), 1, 2, 3.0));
136 auto argsTuple2 = std::make_tuple(wat.get(), 1, 2, 3.0);
137 folly::apply(&Wat::func, argsTuple2);
138
139 EXPECT_EQ(
140 10.0, folly::apply(&Wat::retVal, std::make_tuple(wat.get(), 1, 9.0)));
141
142 auto test = guard(func, 1, 2, 3.0);
143 CopyCount cpy;
144 auto test2 = guard(anotherFunc, cpy);
145 auto test3 = guard(anotherFunc, std::cref(cpy));
146
147 Overloaded ovl;
148 EXPECT_EQ(
149 0,
150 folly::apply(
151 static_cast<int (Overloaded::*)(int)>(&Overloaded::func),
152 std::make_tuple(&ovl, 12)));
153 EXPECT_EQ(
154 /* do not code-mode to EXPECT_TRUE */ true,
155 folly::apply(
156 static_cast<bool (Overloaded::*)(bool)>(&Overloaded::func),
157 std::make_tuple(&ovl, false)));
158
159 int x = folly::apply(std::plus<int>(), std::make_tuple(12, 12));
160 EXPECT_EQ(24, x);
161
162 Mover m;
163 folly::apply(
164 move_only_func, std::forward_as_tuple(std::forward<Mover>(Mover())));
165 const auto tuple3 = std::make_tuple(1, 2, 3.0);
166 folly::apply(func, tuple3);
167}
168
169TEST(ApplyTuple, Mutable) {
170 auto argsTuple = std::make_tuple(1, 2, 3.0);
171
172 folly::apply(
173 [](int a, int b, double c) mutable { func(a, b, c); }, argsTuple);
174}
175
176TEST(ApplyTuple, ConstOverloads) {
177 struct ConstOverloaded {
178 ConstOverloaded() {}
179 int operator()() {
180 return 101;
181 }
182 int operator()() const {
183 return 102;
184 }
185 };
186
187 ConstOverloaded covl;
188
189 // call operator()()
190 EXPECT_EQ(folly::apply(covl, std::make_tuple()), 101);
191 EXPECT_EQ(folly::apply(std::ref(covl), std::make_tuple()), 101);
192 EXPECT_EQ(folly::apply(std::move(covl), std::make_tuple()), 101);
193
194 // call operator()() const
195 EXPECT_EQ(
196 folly::apply(const_cast<ConstOverloaded const&>(covl), std::make_tuple()),
197 102);
198 EXPECT_EQ(folly::apply(std::cref(covl), std::make_tuple()), 102);
199}
200
201TEST(ApplyTuple, RefOverloads) {
202 struct RefOverloaded {
203 RefOverloaded() {}
204 int operator()() & {
205 return 201;
206 }
207 int operator()() const& {
208 return 202;
209 }
210 int operator()() && {
211 return 203;
212 }
213 };
214
215 RefOverloaded rovl;
216
217 // call operator()() &
218 EXPECT_EQ(folly::apply(rovl, std::make_tuple()), 201);
219 EXPECT_EQ(folly::apply(std::ref(rovl), std::make_tuple()), 201);
220
221 // call operator()() const &
222 EXPECT_EQ(
223 folly::apply(const_cast<RefOverloaded const&>(rovl), std::make_tuple()),
224 202);
225 EXPECT_EQ(folly::apply(std::cref(rovl), std::make_tuple()), 202);
226
227 // call operator()() &&
228 EXPECT_EQ(folly::apply(std::move(rovl), std::make_tuple()), 203);
229}
230
231struct MemberFunc {
232 int x;
233 int getX() const {
234 return x;
235 }
236 void setX(int xx) {
237 x = xx;
238 }
239};
240
241TEST(ApplyTuple, MemberFunction) {
242 MemberFunc mf;
243 mf.x = 123;
244
245 // call getter
246 EXPECT_EQ(folly::apply(&MemberFunc::getX, std::make_tuple(&mf)), 123);
247
248 // call setter
249 folly::apply(&MemberFunc::setX, std::make_tuple(&mf, 234));
250 EXPECT_EQ(mf.x, 234);
251 EXPECT_EQ(folly::apply(&MemberFunc::getX, std::make_tuple(&mf)), 234);
252}
253
254TEST(ApplyTuple, MemberFunctionWithRefWrapper) {
255 MemberFunc mf;
256 mf.x = 234;
257
258 EXPECT_EQ(
259 folly::apply(&MemberFunc::getX, std::make_tuple(std::ref(mf))), 234);
260}
261
262TEST(ApplyTuple, MemberFunctionWithConstPointer) {
263 MemberFunc mf;
264 mf.x = 234;
265
266 EXPECT_EQ(
267 folly::apply(
268 &MemberFunc::getX,
269 std::make_tuple(const_cast<MemberFunc const*>(&mf))),
270 234);
271}
272
273TEST(ApplyTuple, MemberFunctionWithSharedPtr) {
274 MemberFunc mf;
275 mf.x = 234;
276
277 EXPECT_EQ(
278 folly::apply(
279 &MemberFunc::getX, std::make_tuple(std::make_shared<MemberFunc>(mf))),
280 234);
281}
282
283TEST(ApplyTuple, MemberFunctionWithUniquePtr) {
284 MemberFunc mf;
285 mf.x = 234;
286
287 EXPECT_EQ(
288 folly::apply(
289 &MemberFunc::getX, std::make_tuple(std::make_unique<MemberFunc>(mf))),
290 234);
291}
292
293TEST(ApplyTuple, Array) {
294 folly::apply(func, std::array<int, 3>{{1, 2, 3}});
295 folly::apply(func, std::array<double, 3>{{1, 2, 3}});
296}
297
298TEST(ApplyTuple, Pair) {
299 auto add = [](int x, int y) { return x + y; };
300
301 EXPECT_EQ(folly::apply(add, std::pair<int, int>{1200, 34}), 1234);
302}
303
304TEST(ApplyTuple, MultipleTuples) {
305 auto add = [](int x, int y, int z) { return x * 100 + y * 10 + z; };
306
307 EXPECT_EQ(123, folly::apply(add, std::make_tuple(1, 2, 3)));
308 EXPECT_EQ(
309 123,
310 folly::apply(
311 add, std::tuple_cat(std::make_tuple(1, 2, 3), std::make_tuple())));
312 EXPECT_EQ(
313 123,
314 folly::apply(
315 add, std::tuple_cat(std::make_tuple(1, 2), std::make_tuple(3))));
316 EXPECT_EQ(
317 123,
318 folly::apply(
319 add, std::tuple_cat(std::make_tuple(1), std::make_tuple(2, 3))));
320 EXPECT_EQ(
321 123,
322 folly::apply(
323 add, std::tuple_cat(std::make_tuple(), std::make_tuple(1, 2, 3))));
324
325 EXPECT_EQ(
326 123,
327 folly::apply(
328 add,
329 std::tuple_cat(
330 std::make_tuple(1, 2, 3), std::make_tuple(), std::make_tuple())));
331 EXPECT_EQ(
332 123,
333 folly::apply(
334 add,
335 std::tuple_cat(
336 std::make_tuple(1), std::make_tuple(2), std::make_tuple(3))));
337 EXPECT_EQ(
338 123,
339 folly::apply(
340 add,
341 std::tuple_cat(
342 std::make_tuple(1), std::make_tuple(), std::make_tuple(2, 3))));
343}
344
345TEST(ApplyTuple, UncurryCopyMove) {
346 std::string separator = "================================\n";
347 auto formatRow = folly::uncurry([=](std::string a, std::string b) {
348 // capture separator by copy
349 return separator + a + "\n" + b + "\n" + separator;
350 });
351 auto row = std::make_tuple("hello", "world");
352 auto expected = separator + "hello\nworld\n" + separator;
353 EXPECT_EQ(expected, formatRow(row));
354 auto formatRowCopy = formatRow;
355 EXPECT_EQ(expected, formatRowCopy(row));
356 auto formatRowMove = std::move(formatRow);
357 EXPECT_EQ(expected, formatRowMove(row));
358
359 // capture value moved out from formatRow
360 EXPECT_NE(expected, formatRow(row));
361}
362
363TEST(ApplyTuple, Uncurry) {
364 EXPECT_EQ(42, folly::uncurry([](int x, int y) {
365 return x * y;
366 })(std::pair<int, int>(6, 7)));
367 EXPECT_EQ(42, folly::uncurry([](int&& x, int&& y) {
368 return x * y;
369 })(std::pair<int&&, int&&>(6, 7)));
370 EXPECT_EQ(42, folly::uncurry([](int&& x, int&& y) {
371 return x * y;
372 })(std::pair<int&&, int&&>(6, 7)));
373
374 std::string long1 = "a long string exceeding small string size";
375 std::string long2 = "and here is another one!";
376 std::string expected = long1 + long2;
377
378 auto cat = folly::uncurry(
379 [](std::string a, std::string b) { return std::move(a) + std::move(b); });
380
381 EXPECT_EQ(expected, cat(std::make_pair(long1, long2)));
382 EXPECT_FALSE(long1.empty());
383 EXPECT_FALSE(long2.empty());
384 EXPECT_EQ(expected, cat(std::tie(long1, long2)));
385 EXPECT_FALSE(long1.empty());
386 EXPECT_FALSE(long2.empty());
387 EXPECT_EQ(
388 expected, cat(std::forward_as_tuple(std::move(long1), std::move(long2))));
389 EXPECT_TRUE(long1.empty());
390 EXPECT_TRUE(long2.empty());
391}
392
393TEST(ApplyTuple, UncurryStdFind) {
394 std::vector<std::pair<int, int>> v{{1, 9}, {2, 8}, {3, 7}, {4, 6}, {5, 5}};
395 EXPECT_EQ(
396 3, std::count_if(v.begin(), v.end(), folly::uncurry([](int a, int b) {
397 return b % a == 0;
398 })));
399}
400
401namespace {
402struct S {
403 template <typename... Args>
404 explicit S(Args&&... args) : tuple_(std::forward<Args>(args)...) {}
405
406 std::tuple<int, double, std::string> tuple_;
407};
408} // namespace
409
410TEST(MakeFromTupleTest, make_from_tuple) {
411 S expected{42, 1.0, "foobar"};
412
413 // const lvalue ref
414 auto s1 = folly::make_from_tuple<S>(expected.tuple_);
415 EXPECT_EQ(expected.tuple_, s1.tuple_);
416
417 // rvalue ref
418 S sCopy{expected.tuple_};
419 auto s2 = folly::make_from_tuple<S>(std::move(sCopy.tuple_));
420 EXPECT_EQ(expected.tuple_, s2.tuple_);
421 EXPECT_TRUE(std::get<2>(sCopy.tuple_).empty());
422
423 // forward
424 std::string str{"foobar"};
425 auto s3 =
426 folly::make_from_tuple<S>(std::forward_as_tuple(42, 1.0, std::move(str)));
427 EXPECT_EQ(expected.tuple_, s3.tuple_);
428 EXPECT_TRUE(str.empty());
429}
430
431TEST(MakeIndexSequenceFromTuple, Basic) {
432 using folly::index_sequence;
433 using folly::index_sequence_for_tuple;
434 using OneElementTuple = std::tuple<int>;
435 using TwoElementTuple = std::tuple<int>;
436
437 EXPECT_TRUE((std::is_same<
438 index_sequence_for_tuple<OneElementTuple>,
439 index_sequence<0>>::value));
440 EXPECT_TRUE((std::is_same<
441 index_sequence_for_tuple<const OneElementTuple>,
442 index_sequence<0>>::value));
443
444 EXPECT_TRUE((std::is_same<
445 index_sequence_for_tuple<TwoElementTuple>,
446 index_sequence<0>>::value));
447 EXPECT_TRUE((std::is_same<
448 index_sequence_for_tuple<const TwoElementTuple>,
449 index_sequence<0>>::value));
450}
451
452TEST(ApplyResult, Basic) {
453 {
454 auto f = [](auto) -> int { return {}; };
455 EXPECT_TRUE((std::is_same<
456 folly::apply_result_t<decltype(f), std::tuple<int>>,
457 int>{}));
458 }
459
460 {
461 auto f = folly::overload(
462 [](int) {},
463 [](double) -> double { return {}; },
464 [](int, int) -> int { return {}; });
465
466 EXPECT_TRUE((std::is_same<
467 folly::apply_result_t<decltype(f), std::tuple<int>>,
468 void>::value));
469 EXPECT_TRUE((std::is_same<
470 folly::apply_result_t<decltype(f), std::tuple<double>>,
471 double>::value));
472 EXPECT_TRUE((std::is_same<
473 folly::apply_result_t<decltype(f), std::tuple<int, int>>,
474 int>::value));
475 }
476}
477
478TEST(IsApplicable, Basic) {
479 {
480 auto f = [] {};
481 EXPECT_TRUE((folly::is_applicable<decltype(f), std::tuple<>>::value));
482 EXPECT_FALSE((folly::is_applicable<decltype(f), std::tuple<int>>::value));
483 }
484 {
485 auto f = folly::overload([](int) {}, [](double) -> double { return {}; });
486 EXPECT_TRUE((folly::is_applicable<decltype(f), std::tuple<double>>::value));
487 EXPECT_TRUE((folly::is_applicable<decltype(f), std::tuple<int>>::value));
488 EXPECT_FALSE((folly::is_applicable<decltype(f), std::tuple<>>::value));
489 EXPECT_FALSE(
490 (folly::is_applicable<decltype(f), std::tuple<int, double>>::value));
491 }
492}
493
494TEST(IsNothrowApplicable, Basic) {
495 {
496 auto f = []() noexcept {};
497 EXPECT_TRUE((folly::is_nothrow_applicable<decltype(f), std::tuple<>>{}));
498 EXPECT_FALSE(
499 (folly::is_nothrow_applicable<decltype(f), std::tuple<int>>{}));
500 }
501 {
502 auto f = folly::overload(
503 [](int) noexcept {}, [](double) -> double { return {}; });
504 EXPECT_FALSE(
505 (folly::is_nothrow_applicable<decltype(f), std::tuple<double>>{}));
506 EXPECT_TRUE((folly::is_nothrow_applicable<decltype(f), std::tuple<int>>{}));
507 EXPECT_FALSE((folly::is_nothrow_applicable<decltype(f), std::tuple<>>{}));
508 EXPECT_FALSE(
509 (folly::is_nothrow_applicable<decltype(f), std::tuple<int, double>>::
510 value));
511 }
512}
513
514TEST(IsApplicableR, Basic) {
515 {
516 auto f = []() -> int { return {}; };
517 EXPECT_TRUE((folly::is_applicable_r<double, decltype(f), std::tuple<>>{}));
518 EXPECT_FALSE(
519 (folly::is_applicable_r<double, decltype(f), std::tuple<int>>{}));
520 }
521 {
522 auto f = folly::overload(
523 [](int) noexcept {}, [](double) -> double { return {}; });
524 EXPECT_TRUE(
525 (folly::is_applicable_r<float, decltype(f), std::tuple<double>>{}));
526 EXPECT_TRUE((folly::is_applicable_r<void, decltype(f), std::tuple<int>>{}));
527 EXPECT_FALSE((folly::is_applicable_r<void, decltype(f), std::tuple<>>{}));
528 EXPECT_FALSE(
529 (folly::is_applicable_r<double, decltype(f), std::tuple<int, double>>::
530 value));
531 }
532}
533
534TEST(IsNothrowApplicableR, Basic) {
535 {
536 auto f = []() noexcept->int {
537 return {};
538 };
539 EXPECT_TRUE(
540 (folly::is_nothrow_applicable_r<double, decltype(f), std::tuple<>>{}));
541 EXPECT_FALSE(
542 (folly::
543 is_nothrow_applicable_r<double, decltype(f), std::tuple<int>>{}));
544 }
545 {
546 auto f = folly::overload(
547 [](int) noexcept {}, [](double) -> double { return {}; });
548 EXPECT_FALSE((
549 folly::
550 is_nothrow_applicable_r<float, decltype(f), std::tuple<double>>{}));
551 EXPECT_TRUE(
552 (folly::is_nothrow_applicable_r<void, decltype(f), std::tuple<int>>{}));
553 EXPECT_FALSE(
554 (folly::is_nothrow_applicable_r<void, decltype(f), std::tuple<>>{}));
555 EXPECT_FALSE((folly::is_nothrow_applicable_r<
556 double,
557 decltype(f),
558 std::tuple<int, double>>::value));
559 }
560}
561
562TEST(ForwardTuple, Basic) {
563 auto tuple = std::make_tuple(1, 2.0);
564
565 EXPECT_TRUE((std::is_same<
566 decltype(folly::forward_tuple(tuple)),
567 std::tuple<int&, double&>>::value));
568 EXPECT_EQ(folly::forward_tuple(tuple), tuple);
569 EXPECT_TRUE((std::is_same<
570 decltype(folly::forward_tuple(folly::as_const(tuple))),
571 std::tuple<const int&, const double&>>::value));
572 EXPECT_EQ(folly::forward_tuple(folly::as_const(tuple)), tuple);
573
574 EXPECT_TRUE((std::is_same<
575 decltype(folly::forward_tuple(std::move(tuple))),
576 std::tuple<int&&, double&&>>::value));
577 EXPECT_EQ(folly::forward_tuple(std::move(tuple)), tuple);
578 EXPECT_TRUE(
579 (std::is_same<
580 decltype(folly::forward_tuple(std::move(folly::as_const(tuple)))),
581 std::tuple<const int&, const double&>>::value));
582 EXPECT_EQ(folly::forward_tuple(std::move(folly::as_const(tuple))), tuple);
583
584 auto integer = 1;
585 auto floating_point = 2.0;
586 auto ref_tuple = std::forward_as_tuple(integer, std::move(floating_point));
587
588 EXPECT_TRUE((std::is_same<
589 decltype(folly::forward_tuple(ref_tuple)),
590 std::tuple<int&, double&>>::value));
591
592 EXPECT_TRUE((std::is_same<
593 decltype(folly::forward_tuple(std::move(ref_tuple))),
594 std::tuple<int&, double&&>>::value));
595
596 EXPECT_TRUE((std::is_same<
597 decltype(std::tuple_cat(
598 folly::forward_tuple(tuple),
599 folly::forward_tuple(std::move(tuple)))),
600 std::tuple<int&, double&, int&&, double&&>>::value));
601}
602