2 * Copyright 2016 Facebook, Inc.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 #include <folly/ApplyTuple.h>
20 #include <gtest/gtest.h>
24 // this placates visual studio stupidity - see
25 // http://stackoverflow.com/questions/5503901
30 void func(int a, int b, double c) {
37 void func(int a, int b, double c) {
41 double retVal(int a, double b) {
46 Wat(Wat const&) = delete;
52 int func(int) { return 0; }
53 bool func(bool) { return true; }
57 int operator()() const {
64 CopyCount(CopyCount const&) {
65 std::cout << "copy count copy ctor\n";
69 void anotherFunc(CopyCount const&) {}
71 std::function<void (int, int, double)> makeFunc() {
76 GuardObjBase(GuardObjBase&&) noexcept {}
78 GuardObjBase(GuardObjBase const&) = delete;
79 GuardObjBase& operator=(GuardObjBase const&) = delete;
81 typedef GuardObjBase const& Guard;
83 template<class F, class Tuple>
84 struct GuardObj : GuardObjBase {
85 explicit GuardObj(F&& f, Tuple&& args)
87 , args_(std::move(args))
89 GuardObj(GuardObj&& g) noexcept
90 : GuardObjBase(std::move(g))
92 , args_(std::move(g.args_))
96 folly::applyTuple(f_, args_);
99 GuardObj(const GuardObj&) = delete;
100 GuardObj& operator=(const GuardObj&) = delete;
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...>>(
112 std::tuple<Args...>(std::forward<Args>(args)...)
118 Mover(Mover&&) noexcept {}
119 Mover(const Mover&) = delete;
120 Mover& operator=(const Mover&) = delete;
123 void move_only_func(Mover&&) {}
127 TEST(ApplyTuple, Test) {
128 auto argsTuple = std::make_tuple(1, 2, 3.0);
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);
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);
142 folly::applyTuple(&Wat::retVal,
143 std::make_tuple(wat.get(), 1, 9.0)));
145 auto test = guard(func, 1, 2, 3.0);
147 auto test2 = guard(anotherFunc, cpy);
148 auto test3 = guard(anotherFunc, std::cref(cpy));
153 static_cast<int (Overloaded::*)(int)>(&Overloaded::func),
154 std::make_tuple(&ovl, 12)));
157 static_cast<bool (Overloaded::*)(bool)>(&Overloaded::func),
158 std::make_tuple(&ovl, false)));
160 int x = folly::applyTuple(std::plus<int>(), std::make_tuple(12, 12));
164 folly::applyTuple(move_only_func,
165 std::forward_as_tuple(std::forward<Mover>(Mover())));
166 const auto tuple3 = std::make_tuple(1, 2, 3.0);
167 folly::applyTuple(func, tuple3);
170 TEST(ApplyTuple, Mutable) {
171 auto argsTuple = std::make_tuple(1, 2, 3.0);
173 folly::applyTuple([](int a, int b, double c) mutable { func(a, b, c); },
177 TEST(ApplyTuple, ConstOverloads) {
178 struct ConstOverloaded {
180 int operator()() { return 101; }
181 int operator()() const { return 102; }
184 ConstOverloaded covl;
187 EXPECT_EQ(folly::applyTuple(covl, std::make_tuple()), 101);
188 EXPECT_EQ(folly::applyTuple(std::ref(covl), std::make_tuple()), 101);
189 EXPECT_EQ(folly::applyTuple(std::move(covl), std::make_tuple()), 101);
191 // call operator()() const
192 EXPECT_EQ(folly::applyTuple(const_cast<ConstOverloaded const&>(covl),
195 EXPECT_EQ(folly::applyTuple(std::cref(covl), std::make_tuple()), 102);
198 TEST(ApplyTuple, RefOverloads) {
199 struct RefOverloaded {
201 int operator()() & { return 201; }
202 int operator()() const & { return 202; }
203 int operator()() && { return 203; }
208 // call operator()() &
209 EXPECT_EQ(folly::applyTuple(rovl, std::make_tuple()), 201);
210 EXPECT_EQ(folly::applyTuple(std::ref(rovl), std::make_tuple()), 201);
212 // call operator()() const &
213 EXPECT_EQ(folly::applyTuple(const_cast<RefOverloaded const&>(rovl),
216 EXPECT_EQ(folly::applyTuple(std::cref(rovl), std::make_tuple()), 202);
218 // call operator()() &&
219 EXPECT_EQ(folly::applyTuple(std::move(rovl), std::make_tuple()), 203);
224 int getX() const { return x; }
225 void setX(int xx) { x = xx; }
228 TEST(ApplyTuple, MemberFunction) {
233 EXPECT_EQ(folly::applyTuple(&MemberFunc::getX, std::make_tuple(&mf)), 123);
236 folly::applyTuple(&MemberFunc::setX, std::make_tuple(&mf, 234));
237 EXPECT_EQ(mf.x, 234);
238 EXPECT_EQ(folly::applyTuple(&MemberFunc::getX, std::make_tuple(&mf)), 234);
241 TEST(ApplyTuple, MemberFunctionWithRefWrapper) {
245 EXPECT_EQ(folly::applyTuple(&MemberFunc::getX, std::make_tuple(std::ref(mf))),
249 TEST(ApplyTuple, MemberFunctionWithConstPointer) {
254 folly::applyTuple(&MemberFunc::getX,
255 std::make_tuple(const_cast<MemberFunc const*>(&mf))),
259 TEST(ApplyTuple, MemberFunctionWithSharedPtr) {
264 folly::applyTuple(&MemberFunc::getX,
265 std::make_tuple(std::make_shared<MemberFunc>(mf))),
269 TEST(ApplyTuple, MemberFunctionWithUniquePtr) {
273 EXPECT_EQ(folly::applyTuple(&MemberFunc::getX,
274 std::make_tuple(std::unique_ptr<MemberFunc>(
275 new MemberFunc(mf)))),
279 TEST(ApplyTuple, Array) {
280 folly::applyTuple(func, std::array<int, 3>{{1, 2, 3}});
281 folly::applyTuple(func, std::array<double, 3>{{1, 2, 3}});
284 TEST(ApplyTuple, Pair) {
285 auto add = [](int x, int y) { return x + y; };
287 EXPECT_EQ(folly::applyTuple(add, std::pair<int, int>{1200, 34}), 1234);