2 * Copyright 2017 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 <folly/portability/GTest.h>
25 // this placates visual studio stupidity - see
26 // http://stackoverflow.com/questions/5503901
31 void func(int a, int b, double c) {
38 void func(int a, int b, double c) {
42 double retVal(int a, double b) {
47 Wat(Wat const&) = delete;
53 int func(int) { return 0; }
54 bool func(bool) { return true; }
58 int operator()() const {
65 CopyCount(CopyCount const&) {
66 std::cout << "copy count copy ctor\n";
70 void anotherFunc(CopyCount const&) {}
72 std::function<void (int, int, double)> makeFunc() {
77 GuardObjBase(GuardObjBase&&) noexcept {}
79 GuardObjBase(GuardObjBase const&) = delete;
80 GuardObjBase& operator=(GuardObjBase const&) = delete;
82 typedef GuardObjBase const& Guard;
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))
90 GuardObj(GuardObj&& g) noexcept
91 : GuardObjBase(std::move(g))
93 , args_(std::move(g.args_))
97 folly::applyTuple(f_, args_);
100 GuardObj(const GuardObj&) = delete;
101 GuardObj& operator=(const GuardObj&) = delete;
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...>>(
113 std::tuple<Args...>(std::forward<Args>(args)...)
119 Mover(Mover&&) noexcept {}
120 Mover(const Mover&) = delete;
121 Mover& operator=(const Mover&) = delete;
124 void move_only_func(Mover&&) {}
128 TEST(ApplyTuple, Test) {
129 auto argsTuple = std::make_tuple(1, 2, 3.0);
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);
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);
143 folly::applyTuple(&Wat::retVal,
144 std::make_tuple(wat.get(), 1, 9.0)));
146 auto test = guard(func, 1, 2, 3.0);
148 auto test2 = guard(anotherFunc, cpy);
149 auto test3 = guard(anotherFunc, std::cref(cpy));
154 static_cast<int (Overloaded::*)(int)>(&Overloaded::func),
155 std::make_tuple(&ovl, 12)));
158 static_cast<bool (Overloaded::*)(bool)>(&Overloaded::func),
159 std::make_tuple(&ovl, false)));
161 int x = folly::applyTuple(std::plus<int>(), std::make_tuple(12, 12));
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);
171 TEST(ApplyTuple, Mutable) {
172 auto argsTuple = std::make_tuple(1, 2, 3.0);
174 folly::applyTuple([](int a, int b, double c) mutable { func(a, b, c); },
178 TEST(ApplyTuple, ConstOverloads) {
179 struct ConstOverloaded {
181 int operator()() { return 101; }
182 int operator()() const { return 102; }
185 ConstOverloaded covl;
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);
192 // call operator()() const
193 EXPECT_EQ(folly::applyTuple(const_cast<ConstOverloaded const&>(covl),
196 EXPECT_EQ(folly::applyTuple(std::cref(covl), std::make_tuple()), 102);
199 TEST(ApplyTuple, RefOverloads) {
200 struct RefOverloaded {
202 int operator()() & { return 201; }
203 int operator()() const & { return 202; }
204 int operator()() && { return 203; }
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);
213 // call operator()() const &
214 EXPECT_EQ(folly::applyTuple(const_cast<RefOverloaded const&>(rovl),
217 EXPECT_EQ(folly::applyTuple(std::cref(rovl), std::make_tuple()), 202);
219 // call operator()() &&
220 EXPECT_EQ(folly::applyTuple(std::move(rovl), std::make_tuple()), 203);
225 int getX() const { return x; }
226 void setX(int xx) { x = xx; }
229 TEST(ApplyTuple, MemberFunction) {
234 EXPECT_EQ(folly::applyTuple(&MemberFunc::getX, std::make_tuple(&mf)), 123);
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);
242 TEST(ApplyTuple, MemberFunctionWithRefWrapper) {
246 EXPECT_EQ(folly::applyTuple(&MemberFunc::getX, std::make_tuple(std::ref(mf))),
250 TEST(ApplyTuple, MemberFunctionWithConstPointer) {
255 folly::applyTuple(&MemberFunc::getX,
256 std::make_tuple(const_cast<MemberFunc const*>(&mf))),
260 TEST(ApplyTuple, MemberFunctionWithSharedPtr) {
265 folly::applyTuple(&MemberFunc::getX,
266 std::make_tuple(std::make_shared<MemberFunc>(mf))),
270 TEST(ApplyTuple, MemberFunctionWithUniquePtr) {
274 EXPECT_EQ(folly::applyTuple(&MemberFunc::getX,
275 std::make_tuple(std::unique_ptr<MemberFunc>(
276 new MemberFunc(mf)))),
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}});
285 TEST(ApplyTuple, Pair) {
286 auto add = [](int x, int y) { return x + y; };
288 EXPECT_EQ(folly::applyTuple(add, std::pair<int, int>{1200, 34}), 1234);
291 TEST(ApplyTuple, MultipleTuples) {
292 auto add = [](int x, int y, int z) { return x * 100 + y * 10 + z; };
294 EXPECT_EQ(123, folly::applyTuple(add, std::make_tuple(1, 2, 3)));
296 123, folly::applyTuple(add, std::make_tuple(1, 2, 3), std::make_tuple()));
298 123, folly::applyTuple(add, std::make_tuple(1, 2), std::make_tuple(3)));
300 123, folly::applyTuple(add, std::make_tuple(1), std::make_tuple(2, 3)));
302 123, folly::applyTuple(add, std::make_tuple(), std::make_tuple(1, 2, 3)));
307 add, std::make_tuple(1, 2, 3), std::make_tuple(), std::make_tuple()));
311 add, std::make_tuple(1), std::make_tuple(2), std::make_tuple(3)));
315 add, std::make_tuple(1), std::make_tuple(), std::make_tuple(2, 3)));
318 TEST(ApplyTuple, UncurryCopyMove) {
319 std::string separator = "================================\n";
320 auto formatRow = folly::uncurry([=](std::string a, std::string b) {
321 // capture separator by copy
322 return separator + a + "\n" + b + "\n" + separator;
324 auto row = std::make_tuple("hello", "world");
325 auto expected = separator + "hello\nworld\n" + separator;
326 EXPECT_EQ(expected, formatRow(row));
327 auto formatRowCopy = formatRow;
328 EXPECT_EQ(expected, formatRowCopy(row));
329 auto formatRowMove = std::move(formatRow);
330 EXPECT_EQ(expected, formatRowMove(row));
332 // capture value moved out from formatRow
333 EXPECT_NE(expected, formatRow(row));
336 TEST(ApplyTuple, Uncurry) {
337 EXPECT_EQ(42, folly::uncurry([](int x, int y) {
339 })(std::pair<int, int>(6, 7)));
340 EXPECT_EQ(42, folly::uncurry([](int&& x, int&& y) {
342 })(std::pair<int&&, int&&>(6, 7)));
343 EXPECT_EQ(42, folly::uncurry([](int&& x, int&& y) {
345 })(std::pair<int&&, int&&>(6, 7)));
347 std::string long1 = "a long string exceeding small string size";
348 std::string long2 = "and here is another one!";
349 std::string expected = long1 + long2;
351 auto cat = folly::uncurry(
352 [](std::string a, std::string b) { return std::move(a) + std::move(b); });
354 EXPECT_EQ(expected, cat(std::make_pair(long1, long2)));
355 EXPECT_FALSE(long1.empty());
356 EXPECT_FALSE(long2.empty());
357 EXPECT_EQ(expected, cat(std::tie(long1, long2)));
358 EXPECT_FALSE(long1.empty());
359 EXPECT_FALSE(long2.empty());
361 expected, cat(std::forward_as_tuple(std::move(long1), std::move(long2))));
362 EXPECT_TRUE(long1.empty());
363 EXPECT_TRUE(long2.empty());
366 TEST(ApplyTuple, UncurryStdFind) {
367 std::vector<std::pair<int, int>> v{{1, 9}, {2, 8}, {3, 7}, {4, 6}, {5, 5}};
369 3, std::count_if(v.begin(), v.end(), folly::uncurry([](int a, int b) {