| /* |
| * Copyright 2015 Facebook, Inc. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #include <iostream> |
| |
| #include <folly/ApplyTuple.h> |
| #include <gtest/gtest.h> |
| |
| #include <memory> |
| |
| // this placates visual studio stupidity - see |
| // http://stackoverflow.com/questions/5503901 |
| namespace {} |
| |
| namespace { |
| |
| void func(int a, int b, double c) { |
| EXPECT_EQ(a, 1); |
| EXPECT_EQ(b, 2); |
| EXPECT_EQ(c, 3.0); |
| } |
| |
| struct Wat { |
| void func(int a, int b, double c) { |
| ::func(a, b, c); |
| } |
| |
| double retVal(int a, double b) { |
| return a + b; |
| } |
| |
| Wat() {} |
| Wat(Wat const&) = delete; |
| |
| int foo; |
| }; |
| |
| struct Overloaded { |
| int func(int) { return 0; } |
| bool func(bool) { return true; } |
| }; |
| |
| struct Func { |
| int operator()() const { |
| return 1; |
| } |
| }; |
| |
| struct CopyCount { |
| CopyCount() {} |
| CopyCount(CopyCount const&) { |
| std::cout << "copy count copy ctor\n"; |
| } |
| }; |
| |
| void anotherFunc(CopyCount const&) {} |
| |
| std::function<void (int, int, double)> makeFunc() { |
| return &func; |
| } |
| |
| struct GuardObjBase { |
| GuardObjBase(GuardObjBase&&) noexcept {} |
| GuardObjBase() {} |
| GuardObjBase(GuardObjBase const&) = delete; |
| GuardObjBase& operator=(GuardObjBase const&) = delete; |
| }; |
| typedef GuardObjBase const& Guard; |
| |
| template<class F, class Tuple> |
| struct GuardObj : GuardObjBase { |
| explicit GuardObj(F&& f, Tuple&& args) |
| : f_(std::move(f)) |
| , args_(std::move(args)) |
| {} |
| GuardObj(GuardObj&& g) noexcept |
| : GuardObjBase(std::move(g)) |
| , f_(std::move(g.f_)) |
| , args_(std::move(g.args_)) |
| {} |
| |
| ~GuardObj() { |
| folly::applyTuple(f_, args_); |
| } |
| |
| GuardObj(const GuardObj&) = delete; |
| GuardObj& operator=(const GuardObj&) = delete; |
| |
| private: |
| F f_; |
| Tuple args_; |
| }; |
| |
| template<class F, class ...Args> |
| GuardObj<typename std::decay<F>::type,std::tuple<Args...>> |
| guard(F&& f, Args&&... args) { |
| return GuardObj<typename std::decay<F>::type,std::tuple<Args...>>( |
| std::forward<F>(f), |
| std::tuple<Args...>(std::forward<Args>(args)...) |
| ); |
| } |
| |
| struct Mover { |
| Mover() {} |
| Mover(Mover&&) noexcept {} |
| Mover(const Mover&) = delete; |
| Mover& operator=(const Mover&) = delete; |
| }; |
| |
| void move_only_func(Mover&&) {} |
| |
| } |
| |
| TEST(ApplyTuple, Test) { |
| auto argsTuple = std::make_tuple(1, 2, 3.0); |
| auto func2 = func; |
| folly::applyTuple(func2, argsTuple); |
| folly::applyTuple(func, argsTuple); |
| folly::applyTuple(func, std::make_tuple(1, 2, 3.0)); |
| folly::applyTuple(makeFunc(), std::make_tuple(1, 2, 3.0)); |
| folly::applyTuple(makeFunc(), argsTuple); |
| |
| std::unique_ptr<Wat> wat(new Wat); |
| folly::applyTuple(&Wat::func, std::make_tuple(wat.get(), 1, 2, 3.0)); |
| auto argsTuple2 = std::make_tuple(wat.get(), 1, 2, 3.0); |
| folly::applyTuple(&Wat::func, argsTuple2); |
| |
| EXPECT_EQ(10.0, |
| folly::applyTuple(&Wat::retVal, |
| std::make_tuple(wat.get(), 1, 9.0))); |
| |
| auto test = guard(func, 1, 2, 3.0); |
| CopyCount cpy; |
| auto test2 = guard(anotherFunc, cpy); |
| auto test3 = guard(anotherFunc, std::cref(cpy)); |
| |
| Overloaded ovl; |
| EXPECT_EQ(0, |
| folly::applyTuple( |
| static_cast<int (Overloaded::*)(int)>(&Overloaded::func), |
| std::make_tuple(&ovl, 12))); |
| EXPECT_EQ(true, |
| folly::applyTuple( |
| static_cast<bool (Overloaded::*)(bool)>(&Overloaded::func), |
| std::make_tuple(&ovl, false))); |
| |
| int x = folly::applyTuple(std::plus<int>(), std::make_tuple(12, 12)); |
| EXPECT_EQ(24, x); |
| |
| Mover m; |
| folly::applyTuple(move_only_func, |
| std::forward_as_tuple(std::forward<Mover>(Mover()))); |
| const auto tuple3 = std::make_tuple(1, 2, 3.0); |
| folly::applyTuple(func, tuple3); |
| } |