Copyright 2012 -> 2013
[folly.git] / folly / test / ApplyTupleTest.cpp
1 /*
2  * Copyright 2013 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 <gtest/gtest.h>
21
22 #include <iostream>
23 #include <memory>
24
25 namespace {
26
27 void func(int a, int b, double c) {
28   EXPECT_EQ(a, 1);
29   EXPECT_EQ(b, 2);
30   EXPECT_EQ(c, 3.0);
31 }
32
33 struct Wat {
34   void func(int a, int b, double c) {
35     ::func(a, b, c);
36   }
37
38   double retVal(int a, double b) {
39     return a + b;
40   }
41
42   Wat() {}
43   Wat(Wat const&) = delete;
44
45   int foo;
46 };
47
48 struct Overloaded {
49   int func(int) { return 0; }
50   bool func(bool) { return true; }
51 };
52
53 struct Func {
54   int operator()() const {
55     return 1;
56   }
57 };
58
59 struct CopyCount {
60   CopyCount() {}
61   CopyCount(CopyCount const&) {
62     std::cout << "copy count copy ctor\n";
63   }
64 };
65
66 void anotherFunc(CopyCount const&) {}
67
68 std::function<void (int, int, double)> makeFunc() {
69   return &func;
70 }
71
72 struct GuardObjBase {
73   GuardObjBase(GuardObjBase&&) {}
74   GuardObjBase() {}
75   GuardObjBase(GuardObjBase const&) = delete;
76   GuardObjBase& operator=(GuardObjBase const&) = delete;
77 };
78 typedef GuardObjBase const& Guard;
79
80 template<class F, class Tuple>
81 struct GuardObj : GuardObjBase {
82   explicit GuardObj(F&& f, Tuple&& args)
83     : f_(std::move(f))
84     , args_(std::move(args))
85   {}
86   GuardObj(GuardObj&& g)
87     : GuardObjBase(std::move(g))
88     , f_(std::move(g.f_))
89     , args_(std::move(g.args_))
90   {}
91
92   ~GuardObj() {
93     folly::applyTuple(f_, args_);
94   }
95
96   GuardObj(const GuardObj&) = delete;
97   GuardObj& operator=(const GuardObj&) = delete;
98
99 private:
100   F f_;
101   Tuple args_;
102 };
103
104 template<class F, class ...Args>
105 GuardObj<typename std::decay<F>::type,std::tuple<Args...>>
106 guard(F&& f, Args&&... args) {
107   return GuardObj<typename std::decay<F>::type,std::tuple<Args...>>(
108     std::forward<F>(f),
109     std::tuple<Args...>(std::forward<Args>(args)...)
110   );
111 }
112
113 struct Mover {
114   Mover() {}
115   Mover(Mover&&) {}
116   Mover(const Mover&) = delete;
117   Mover& operator=(const Mover&) = delete;
118 };
119
120 void move_only_func(Mover&&) {}
121
122 }
123
124 TEST(ApplyTuple, Test) {
125   auto argsTuple = std::make_tuple(1, 2, 3.0);
126   auto func2 = func;
127   folly::applyTuple(func2, argsTuple);
128   folly::applyTuple(func, argsTuple);
129   folly::applyTuple(func, std::make_tuple(1, 2, 3.0));
130   folly::applyTuple(makeFunc(), std::make_tuple(1, 2, 3.0));
131   folly::applyTuple(makeFunc(), argsTuple);
132
133   std::unique_ptr<Wat> wat(new Wat);
134   folly::applyTuple(&Wat::func, std::make_tuple(wat.get(), 1, 2, 3.0));
135   auto argsTuple2 = std::make_tuple(wat.get(), 1, 2, 3.0);
136   folly::applyTuple(&Wat::func, argsTuple2);
137
138   EXPECT_EQ(10.0,
139             folly::applyTuple(&Wat::retVal,
140                               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(0,
149             folly::applyTuple(
150               static_cast<int (Overloaded::*)(int)>(&Overloaded::func),
151               std::make_tuple(&ovl, 12)));
152   EXPECT_EQ(true,
153             folly::applyTuple(
154               static_cast<bool (Overloaded::*)(bool)>(&Overloaded::func),
155               std::make_tuple(&ovl, false)));
156
157   int x = folly::applyTuple(std::plus<int>(), std::make_tuple(12, 12));
158   EXPECT_EQ(24, x);
159
160   Mover m;
161   folly::applyTuple(move_only_func,
162                     std::forward_as_tuple(std::forward<Mover>(Mover())));
163 }