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