From: James Sedgwick Date: Thu, 19 Oct 2017 14:45:51 +0000 (-0700) Subject: move ApplyTuple to functional/ X-Git-Tag: v2017.10.23.00~14 X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=bfa61031d36f41aaa907d40371c28ac0e84c8e0d;p=folly.git move ApplyTuple to functional/ Summary: as above Reviewed By: yfeldblum Differential Revision: D6086563 fbshipit-source-id: ab7f50ba46ebd1dbef6438f956258b2fbb13cb5c --- diff --git a/CMakeLists.txt b/CMakeLists.txt index cdc992a8..68fdc288 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -358,6 +358,9 @@ if (BUILD_TESTS) DIRECTORY fibers/test/ TEST fibers_test SOURCES FibersTest.cpp + DIRECTORY functional/test/ + TEST apply_tuple_test SOURCES ApplyTupleTest.cpp + DIRECTORY futures/test/ TEST barrier_test SOURCES BarrierTest.cpp TEST callback_lifetime_test SOURCES CallbackLifetimeTest.cpp @@ -474,7 +477,6 @@ if (BUILD_TESTS) DIRECTORY test/ TEST ahm_int_stress_test SOURCES AHMIntStressTest.cpp - TEST apply_tuple_test SOURCES ApplyTupleTest.cpp TEST arena_test SOURCES ArenaTest.cpp TEST arena_smartptr_test SOURCES ArenaSmartPtrTest.cpp TEST array_test SOURCES ArrayTest.cpp diff --git a/folly/ApplyTuple.h b/folly/ApplyTuple.h deleted file mode 100644 index cce6fec0..00000000 --- a/folly/ApplyTuple.h +++ /dev/null @@ -1,164 +0,0 @@ -/* - * Copyright 2017 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. - */ - -/* - * Defines a function folly::applyTuple, which takes a function and a - * std::tuple of arguments and calls the function with those - * arguments. - * - * Example: - * - * int x = folly::applyTuple(std::plus(), std::make_tuple(12, 12)); - * ASSERT(x == 24); - */ - -#pragma once - -#include -#include -#include - -#include - -namespace folly { - -////////////////////////////////////////////////////////////////////// - -namespace detail { -namespace apply_tuple { - -inline constexpr std::size_t sum() { - return 0; -} -template -inline constexpr std::size_t sum(std::size_t v1, Args... vs) { - return v1 + sum(vs...); -} - -template -struct TupleSizeSum { - static constexpr auto value = sum(std::tuple_size::value...); -}; - -template -using MakeIndexSequenceFromTuple = folly::make_index_sequence< - TupleSizeSum::type...>::value>; - -// This is to allow using this with pointers to member functions, -// where the first argument in the tuple will be the this pointer. -template -inline constexpr F&& makeCallable(F&& f) { - return std::forward(f); -} -template -inline constexpr auto makeCallable(M(C::*d)) -> decltype(std::mem_fn(d)) { - return std::mem_fn(d); -} - -template -inline constexpr auto call(F&& f, Tuple&& t, folly::index_sequence) - -> decltype( - std::forward(f)(std::get(std::forward(t))...)) { - return std::forward(f)(std::get(std::forward(t))...); -} - -template -inline constexpr auto forwardTuple(Tuple&& t, folly::index_sequence) - -> decltype( - std::forward_as_tuple(std::get(std::forward(t))...)) { - return std::forward_as_tuple(std::get(std::forward(t))...); -} - -} // namespace apply_tuple -} // namespace detail - -////////////////////////////////////////////////////////////////////// - -/** - * Invoke a callable object with a set of arguments passed as a tuple, or a - * series of tuples - * - * Example: the following lines are equivalent - * func(1, 2, 3, "foo"); - * applyTuple(func, std::make_tuple(1, 2, 3, "foo")); - * applyTuple(func, std::make_tuple(1, 2), std::make_tuple(3, "foo")); - */ - -template -inline constexpr auto applyTuple(F&& f, Tuples&&... t) - -> decltype(detail::apply_tuple::call( - detail::apply_tuple::makeCallable(std::forward(f)), - std::tuple_cat(detail::apply_tuple::forwardTuple( - std::forward(t), - detail::apply_tuple::MakeIndexSequenceFromTuple{})...), - detail::apply_tuple::MakeIndexSequenceFromTuple{})) { - return detail::apply_tuple::call( - detail::apply_tuple::makeCallable(std::forward(f)), - std::tuple_cat(detail::apply_tuple::forwardTuple( - std::forward(t), - detail::apply_tuple::MakeIndexSequenceFromTuple{})...), - detail::apply_tuple::MakeIndexSequenceFromTuple{}); -} - -namespace detail { -namespace apply_tuple { - -template -class Uncurry { - public: - explicit Uncurry(F&& func) : func_(std::move(func)) {} - explicit Uncurry(const F& func) : func_(func) {} - - template - auto operator()(Tuple&& tuple) const - -> decltype(applyTuple(std::declval(), std::forward(tuple))) { - return applyTuple(func_, std::forward(tuple)); - } - - private: - F func_; -}; -} // namespace apply_tuple -} // namespace detail - -/** - * Wraps a function taking N arguments into a function which accepts a tuple of - * N arguments. Note: This function will also accept an std::pair if N == 2. - * - * For example, given the below code: - * - * std::vector> rows = ...; - * auto test = [](std::tuple& row) { - * return std::get<0>(row) * std::get<1>(row) * std::get<2>(row) == 24; - * }; - * auto found = std::find_if(rows.begin(), rows.end(), test); - * - * - * 'test' could be rewritten as: - * - * auto test = - * folly::uncurry([](int a, int b, int c) { return a * b * c == 24; }); - * - */ -template -auto uncurry(F&& f) - -> detail::apply_tuple::Uncurry::type> { - return detail::apply_tuple::Uncurry::type>( - std::forward(f)); -} - -////////////////////////////////////////////////////////////////////// -} diff --git a/folly/Hash.h b/folly/Hash.h index 410d2720..5253975a 100644 --- a/folly/Hash.h +++ b/folly/Hash.h @@ -24,8 +24,8 @@ #include #include -#include #include +#include #include #include diff --git a/folly/Makefile.am b/folly/Makefile.am index ce29ac05..0b48eab2 100644 --- a/folly/Makefile.am +++ b/folly/Makefile.am @@ -27,7 +27,6 @@ lib_LTLIBRARIES = \ follyincludedir = $(includedir)/folly nobase_follyinclude_HEADERS = \ - ApplyTuple.h \ Arena.h \ Arena-inl.h \ Array.h \ @@ -106,7 +105,7 @@ nobase_follyinclude_HEADERS = \ executors/ThreadPoolExecutor.h \ executors/ThreadedExecutor.h \ executors/UnboundedBlockingQueue.h \ - executors/QueuedImmediateExecutor.h \ + functional/ApplyTuple.h \ Demangle.h \ DiscriminatedPtr.h \ DynamicConverter.h \ diff --git a/folly/functional/ApplyTuple.h b/folly/functional/ApplyTuple.h new file mode 100644 index 00000000..cce6fec0 --- /dev/null +++ b/folly/functional/ApplyTuple.h @@ -0,0 +1,164 @@ +/* + * Copyright 2017 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. + */ + +/* + * Defines a function folly::applyTuple, which takes a function and a + * std::tuple of arguments and calls the function with those + * arguments. + * + * Example: + * + * int x = folly::applyTuple(std::plus(), std::make_tuple(12, 12)); + * ASSERT(x == 24); + */ + +#pragma once + +#include +#include +#include + +#include + +namespace folly { + +////////////////////////////////////////////////////////////////////// + +namespace detail { +namespace apply_tuple { + +inline constexpr std::size_t sum() { + return 0; +} +template +inline constexpr std::size_t sum(std::size_t v1, Args... vs) { + return v1 + sum(vs...); +} + +template +struct TupleSizeSum { + static constexpr auto value = sum(std::tuple_size::value...); +}; + +template +using MakeIndexSequenceFromTuple = folly::make_index_sequence< + TupleSizeSum::type...>::value>; + +// This is to allow using this with pointers to member functions, +// where the first argument in the tuple will be the this pointer. +template +inline constexpr F&& makeCallable(F&& f) { + return std::forward(f); +} +template +inline constexpr auto makeCallable(M(C::*d)) -> decltype(std::mem_fn(d)) { + return std::mem_fn(d); +} + +template +inline constexpr auto call(F&& f, Tuple&& t, folly::index_sequence) + -> decltype( + std::forward(f)(std::get(std::forward(t))...)) { + return std::forward(f)(std::get(std::forward(t))...); +} + +template +inline constexpr auto forwardTuple(Tuple&& t, folly::index_sequence) + -> decltype( + std::forward_as_tuple(std::get(std::forward(t))...)) { + return std::forward_as_tuple(std::get(std::forward(t))...); +} + +} // namespace apply_tuple +} // namespace detail + +////////////////////////////////////////////////////////////////////// + +/** + * Invoke a callable object with a set of arguments passed as a tuple, or a + * series of tuples + * + * Example: the following lines are equivalent + * func(1, 2, 3, "foo"); + * applyTuple(func, std::make_tuple(1, 2, 3, "foo")); + * applyTuple(func, std::make_tuple(1, 2), std::make_tuple(3, "foo")); + */ + +template +inline constexpr auto applyTuple(F&& f, Tuples&&... t) + -> decltype(detail::apply_tuple::call( + detail::apply_tuple::makeCallable(std::forward(f)), + std::tuple_cat(detail::apply_tuple::forwardTuple( + std::forward(t), + detail::apply_tuple::MakeIndexSequenceFromTuple{})...), + detail::apply_tuple::MakeIndexSequenceFromTuple{})) { + return detail::apply_tuple::call( + detail::apply_tuple::makeCallable(std::forward(f)), + std::tuple_cat(detail::apply_tuple::forwardTuple( + std::forward(t), + detail::apply_tuple::MakeIndexSequenceFromTuple{})...), + detail::apply_tuple::MakeIndexSequenceFromTuple{}); +} + +namespace detail { +namespace apply_tuple { + +template +class Uncurry { + public: + explicit Uncurry(F&& func) : func_(std::move(func)) {} + explicit Uncurry(const F& func) : func_(func) {} + + template + auto operator()(Tuple&& tuple) const + -> decltype(applyTuple(std::declval(), std::forward(tuple))) { + return applyTuple(func_, std::forward(tuple)); + } + + private: + F func_; +}; +} // namespace apply_tuple +} // namespace detail + +/** + * Wraps a function taking N arguments into a function which accepts a tuple of + * N arguments. Note: This function will also accept an std::pair if N == 2. + * + * For example, given the below code: + * + * std::vector> rows = ...; + * auto test = [](std::tuple& row) { + * return std::get<0>(row) * std::get<1>(row) * std::get<2>(row) == 24; + * }; + * auto found = std::find_if(rows.begin(), rows.end(), test); + * + * + * 'test' could be rewritten as: + * + * auto test = + * folly::uncurry([](int a, int b, int c) { return a * b * c == 24; }); + * + */ +template +auto uncurry(F&& f) + -> detail::apply_tuple::Uncurry::type> { + return detail::apply_tuple::Uncurry::type>( + std::forward(f)); +} + +////////////////////////////////////////////////////////////////////// +} diff --git a/folly/functional/Partial.h b/folly/functional/Partial.h index b3914528..650a394c 100644 --- a/folly/functional/Partial.h +++ b/folly/functional/Partial.h @@ -16,7 +16,7 @@ #pragma once -#include +#include namespace folly { diff --git a/folly/functional/test/ApplyTupleTest.cpp b/folly/functional/test/ApplyTupleTest.cpp new file mode 100644 index 00000000..e661e479 --- /dev/null +++ b/folly/functional/test/ApplyTupleTest.cpp @@ -0,0 +1,373 @@ +/* + * Copyright 2017 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 + +#include +#include + +#include +#include + +// 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 makeFunc() { + return &func; +} + +struct GuardObjBase { + GuardObjBase(GuardObjBase&&) noexcept {} + GuardObjBase() {} + GuardObjBase(GuardObjBase const&) = delete; + GuardObjBase& operator=(GuardObjBase const&) = delete; +}; +typedef GuardObjBase const& Guard; + +template +struct GuardObj : GuardObjBase { + explicit GuardObj(F&& f, Tuple&& args) + : f_(std::forward(f)) + , args_(std::forward(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 +GuardObj::type,std::tuple> +guard(F&& f, Args&&... args) { + return GuardObj::type,std::tuple>( + std::forward(f), + std::tuple(std::forward(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(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(&Overloaded::func), + std::make_tuple(&ovl, 12))); + EXPECT_EQ( + /* do not code-mode to EXPECT_TRUE */ true, + folly::applyTuple( + static_cast(&Overloaded::func), + std::make_tuple(&ovl, false))); + + int x = folly::applyTuple(std::plus(), std::make_tuple(12, 12)); + EXPECT_EQ(24, x); + + Mover m; + folly::applyTuple(move_only_func, + std::forward_as_tuple(std::forward(Mover()))); + const auto tuple3 = std::make_tuple(1, 2, 3.0); + folly::applyTuple(func, tuple3); +} + +TEST(ApplyTuple, Mutable) { + auto argsTuple = std::make_tuple(1, 2, 3.0); + + folly::applyTuple([](int a, int b, double c) mutable { func(a, b, c); }, + argsTuple); +} + +TEST(ApplyTuple, ConstOverloads) { + struct ConstOverloaded { + ConstOverloaded() {} + int operator()() { return 101; } + int operator()() const { return 102; } + }; + + ConstOverloaded covl; + + // call operator()() + EXPECT_EQ(folly::applyTuple(covl, std::make_tuple()), 101); + EXPECT_EQ(folly::applyTuple(std::ref(covl), std::make_tuple()), 101); + EXPECT_EQ(folly::applyTuple(std::move(covl), std::make_tuple()), 101); + + // call operator()() const + EXPECT_EQ(folly::applyTuple(const_cast(covl), + std::make_tuple()), + 102); + EXPECT_EQ(folly::applyTuple(std::cref(covl), std::make_tuple()), 102); +} + +TEST(ApplyTuple, RefOverloads) { + struct RefOverloaded { + RefOverloaded() {} + int operator()() & { return 201; } + int operator()() const & { return 202; } + int operator()() && { return 203; } + }; + + RefOverloaded rovl; + + // call operator()() & + EXPECT_EQ(folly::applyTuple(rovl, std::make_tuple()), 201); + EXPECT_EQ(folly::applyTuple(std::ref(rovl), std::make_tuple()), 201); + + // call operator()() const & + EXPECT_EQ(folly::applyTuple(const_cast(rovl), + std::make_tuple()), + 202); + EXPECT_EQ(folly::applyTuple(std::cref(rovl), std::make_tuple()), 202); + + // call operator()() && + EXPECT_EQ(folly::applyTuple(std::move(rovl), std::make_tuple()), 203); +} + +struct MemberFunc { + int x; + int getX() const { return x; } + void setX(int xx) { x = xx; } +}; + +TEST(ApplyTuple, MemberFunction) { + MemberFunc mf; + mf.x = 123; + + // call getter + EXPECT_EQ(folly::applyTuple(&MemberFunc::getX, std::make_tuple(&mf)), 123); + + // call setter + folly::applyTuple(&MemberFunc::setX, std::make_tuple(&mf, 234)); + EXPECT_EQ(mf.x, 234); + EXPECT_EQ(folly::applyTuple(&MemberFunc::getX, std::make_tuple(&mf)), 234); +} + +TEST(ApplyTuple, MemberFunctionWithRefWrapper) { + MemberFunc mf; + mf.x = 234; + + EXPECT_EQ(folly::applyTuple(&MemberFunc::getX, std::make_tuple(std::ref(mf))), + 234); +} + +TEST(ApplyTuple, MemberFunctionWithConstPointer) { + MemberFunc mf; + mf.x = 234; + + EXPECT_EQ( + folly::applyTuple(&MemberFunc::getX, + std::make_tuple(const_cast(&mf))), + 234); +} + +TEST(ApplyTuple, MemberFunctionWithSharedPtr) { + MemberFunc mf; + mf.x = 234; + + EXPECT_EQ( + folly::applyTuple(&MemberFunc::getX, + std::make_tuple(std::make_shared(mf))), + 234); +} + +TEST(ApplyTuple, MemberFunctionWithUniquePtr) { + MemberFunc mf; + mf.x = 234; + + EXPECT_EQ(folly::applyTuple(&MemberFunc::getX, + std::make_tuple(std::unique_ptr( + new MemberFunc(mf)))), + 234); +} + +TEST(ApplyTuple, Array) { + folly::applyTuple(func, std::array{{1, 2, 3}}); + folly::applyTuple(func, std::array{{1, 2, 3}}); +} + +TEST(ApplyTuple, Pair) { + auto add = [](int x, int y) { return x + y; }; + + EXPECT_EQ(folly::applyTuple(add, std::pair{1200, 34}), 1234); +} + +TEST(ApplyTuple, MultipleTuples) { + auto add = [](int x, int y, int z) { return x * 100 + y * 10 + z; }; + + EXPECT_EQ(123, folly::applyTuple(add, std::make_tuple(1, 2, 3))); + EXPECT_EQ( + 123, folly::applyTuple(add, std::make_tuple(1, 2, 3), std::make_tuple())); + EXPECT_EQ( + 123, folly::applyTuple(add, std::make_tuple(1, 2), std::make_tuple(3))); + EXPECT_EQ( + 123, folly::applyTuple(add, std::make_tuple(1), std::make_tuple(2, 3))); + EXPECT_EQ( + 123, folly::applyTuple(add, std::make_tuple(), std::make_tuple(1, 2, 3))); + + EXPECT_EQ( + 123, + folly::applyTuple( + add, std::make_tuple(1, 2, 3), std::make_tuple(), std::make_tuple())); + EXPECT_EQ( + 123, + folly::applyTuple( + add, std::make_tuple(1), std::make_tuple(2), std::make_tuple(3))); + EXPECT_EQ( + 123, + folly::applyTuple( + add, std::make_tuple(1), std::make_tuple(), std::make_tuple(2, 3))); +} + +TEST(ApplyTuple, UncurryCopyMove) { + std::string separator = "================================\n"; + auto formatRow = folly::uncurry([=](std::string a, std::string b) { + // capture separator by copy + return separator + a + "\n" + b + "\n" + separator; + }); + auto row = std::make_tuple("hello", "world"); + auto expected = separator + "hello\nworld\n" + separator; + EXPECT_EQ(expected, formatRow(row)); + auto formatRowCopy = formatRow; + EXPECT_EQ(expected, formatRowCopy(row)); + auto formatRowMove = std::move(formatRow); + EXPECT_EQ(expected, formatRowMove(row)); + + // capture value moved out from formatRow + EXPECT_NE(expected, formatRow(row)); +} + +TEST(ApplyTuple, Uncurry) { + EXPECT_EQ(42, folly::uncurry([](int x, int y) { + return x * y; + })(std::pair(6, 7))); + EXPECT_EQ(42, folly::uncurry([](int&& x, int&& y) { + return x * y; + })(std::pair(6, 7))); + EXPECT_EQ(42, folly::uncurry([](int&& x, int&& y) { + return x * y; + })(std::pair(6, 7))); + + std::string long1 = "a long string exceeding small string size"; + std::string long2 = "and here is another one!"; + std::string expected = long1 + long2; + + auto cat = folly::uncurry( + [](std::string a, std::string b) { return std::move(a) + std::move(b); }); + + EXPECT_EQ(expected, cat(std::make_pair(long1, long2))); + EXPECT_FALSE(long1.empty()); + EXPECT_FALSE(long2.empty()); + EXPECT_EQ(expected, cat(std::tie(long1, long2))); + EXPECT_FALSE(long1.empty()); + EXPECT_FALSE(long2.empty()); + EXPECT_EQ( + expected, cat(std::forward_as_tuple(std::move(long1), std::move(long2)))); + EXPECT_TRUE(long1.empty()); + EXPECT_TRUE(long2.empty()); +} + +TEST(ApplyTuple, UncurryStdFind) { + std::vector> v{{1, 9}, {2, 8}, {3, 7}, {4, 6}, {5, 5}}; + EXPECT_EQ( + 3, std::count_if(v.begin(), v.end(), folly::uncurry([](int a, int b) { + return b % a == 0; + }))); +} diff --git a/folly/gen/test/StringTest.cpp b/folly/gen/test/StringTest.cpp index 47d76d2b..8db23ccc 100644 --- a/folly/gen/test/StringTest.cpp +++ b/folly/gen/test/StringTest.cpp @@ -18,7 +18,7 @@ #include #include -#include +#include #include #include diff --git a/folly/test/ApplyTupleTest.cpp b/folly/test/ApplyTupleTest.cpp deleted file mode 100644 index a09f8074..00000000 --- a/folly/test/ApplyTupleTest.cpp +++ /dev/null @@ -1,373 +0,0 @@ -/* - * Copyright 2017 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 - -#include -#include - -#include -#include - -// 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 makeFunc() { - return &func; -} - -struct GuardObjBase { - GuardObjBase(GuardObjBase&&) noexcept {} - GuardObjBase() {} - GuardObjBase(GuardObjBase const&) = delete; - GuardObjBase& operator=(GuardObjBase const&) = delete; -}; -typedef GuardObjBase const& Guard; - -template -struct GuardObj : GuardObjBase { - explicit GuardObj(F&& f, Tuple&& args) - : f_(std::forward(f)) - , args_(std::forward(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 -GuardObj::type,std::tuple> -guard(F&& f, Args&&... args) { - return GuardObj::type,std::tuple>( - std::forward(f), - std::tuple(std::forward(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(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(&Overloaded::func), - std::make_tuple(&ovl, 12))); - EXPECT_EQ( - /* do not code-mode to EXPECT_TRUE */ true, - folly::applyTuple( - static_cast(&Overloaded::func), - std::make_tuple(&ovl, false))); - - int x = folly::applyTuple(std::plus(), std::make_tuple(12, 12)); - EXPECT_EQ(24, x); - - Mover m; - folly::applyTuple(move_only_func, - std::forward_as_tuple(std::forward(Mover()))); - const auto tuple3 = std::make_tuple(1, 2, 3.0); - folly::applyTuple(func, tuple3); -} - -TEST(ApplyTuple, Mutable) { - auto argsTuple = std::make_tuple(1, 2, 3.0); - - folly::applyTuple([](int a, int b, double c) mutable { func(a, b, c); }, - argsTuple); -} - -TEST(ApplyTuple, ConstOverloads) { - struct ConstOverloaded { - ConstOverloaded() {} - int operator()() { return 101; } - int operator()() const { return 102; } - }; - - ConstOverloaded covl; - - // call operator()() - EXPECT_EQ(folly::applyTuple(covl, std::make_tuple()), 101); - EXPECT_EQ(folly::applyTuple(std::ref(covl), std::make_tuple()), 101); - EXPECT_EQ(folly::applyTuple(std::move(covl), std::make_tuple()), 101); - - // call operator()() const - EXPECT_EQ(folly::applyTuple(const_cast(covl), - std::make_tuple()), - 102); - EXPECT_EQ(folly::applyTuple(std::cref(covl), std::make_tuple()), 102); -} - -TEST(ApplyTuple, RefOverloads) { - struct RefOverloaded { - RefOverloaded() {} - int operator()() & { return 201; } - int operator()() const & { return 202; } - int operator()() && { return 203; } - }; - - RefOverloaded rovl; - - // call operator()() & - EXPECT_EQ(folly::applyTuple(rovl, std::make_tuple()), 201); - EXPECT_EQ(folly::applyTuple(std::ref(rovl), std::make_tuple()), 201); - - // call operator()() const & - EXPECT_EQ(folly::applyTuple(const_cast(rovl), - std::make_tuple()), - 202); - EXPECT_EQ(folly::applyTuple(std::cref(rovl), std::make_tuple()), 202); - - // call operator()() && - EXPECT_EQ(folly::applyTuple(std::move(rovl), std::make_tuple()), 203); -} - -struct MemberFunc { - int x; - int getX() const { return x; } - void setX(int xx) { x = xx; } -}; - -TEST(ApplyTuple, MemberFunction) { - MemberFunc mf; - mf.x = 123; - - // call getter - EXPECT_EQ(folly::applyTuple(&MemberFunc::getX, std::make_tuple(&mf)), 123); - - // call setter - folly::applyTuple(&MemberFunc::setX, std::make_tuple(&mf, 234)); - EXPECT_EQ(mf.x, 234); - EXPECT_EQ(folly::applyTuple(&MemberFunc::getX, std::make_tuple(&mf)), 234); -} - -TEST(ApplyTuple, MemberFunctionWithRefWrapper) { - MemberFunc mf; - mf.x = 234; - - EXPECT_EQ(folly::applyTuple(&MemberFunc::getX, std::make_tuple(std::ref(mf))), - 234); -} - -TEST(ApplyTuple, MemberFunctionWithConstPointer) { - MemberFunc mf; - mf.x = 234; - - EXPECT_EQ( - folly::applyTuple(&MemberFunc::getX, - std::make_tuple(const_cast(&mf))), - 234); -} - -TEST(ApplyTuple, MemberFunctionWithSharedPtr) { - MemberFunc mf; - mf.x = 234; - - EXPECT_EQ( - folly::applyTuple(&MemberFunc::getX, - std::make_tuple(std::make_shared(mf))), - 234); -} - -TEST(ApplyTuple, MemberFunctionWithUniquePtr) { - MemberFunc mf; - mf.x = 234; - - EXPECT_EQ(folly::applyTuple(&MemberFunc::getX, - std::make_tuple(std::unique_ptr( - new MemberFunc(mf)))), - 234); -} - -TEST(ApplyTuple, Array) { - folly::applyTuple(func, std::array{{1, 2, 3}}); - folly::applyTuple(func, std::array{{1, 2, 3}}); -} - -TEST(ApplyTuple, Pair) { - auto add = [](int x, int y) { return x + y; }; - - EXPECT_EQ(folly::applyTuple(add, std::pair{1200, 34}), 1234); -} - -TEST(ApplyTuple, MultipleTuples) { - auto add = [](int x, int y, int z) { return x * 100 + y * 10 + z; }; - - EXPECT_EQ(123, folly::applyTuple(add, std::make_tuple(1, 2, 3))); - EXPECT_EQ( - 123, folly::applyTuple(add, std::make_tuple(1, 2, 3), std::make_tuple())); - EXPECT_EQ( - 123, folly::applyTuple(add, std::make_tuple(1, 2), std::make_tuple(3))); - EXPECT_EQ( - 123, folly::applyTuple(add, std::make_tuple(1), std::make_tuple(2, 3))); - EXPECT_EQ( - 123, folly::applyTuple(add, std::make_tuple(), std::make_tuple(1, 2, 3))); - - EXPECT_EQ( - 123, - folly::applyTuple( - add, std::make_tuple(1, 2, 3), std::make_tuple(), std::make_tuple())); - EXPECT_EQ( - 123, - folly::applyTuple( - add, std::make_tuple(1), std::make_tuple(2), std::make_tuple(3))); - EXPECT_EQ( - 123, - folly::applyTuple( - add, std::make_tuple(1), std::make_tuple(), std::make_tuple(2, 3))); -} - -TEST(ApplyTuple, UncurryCopyMove) { - std::string separator = "================================\n"; - auto formatRow = folly::uncurry([=](std::string a, std::string b) { - // capture separator by copy - return separator + a + "\n" + b + "\n" + separator; - }); - auto row = std::make_tuple("hello", "world"); - auto expected = separator + "hello\nworld\n" + separator; - EXPECT_EQ(expected, formatRow(row)); - auto formatRowCopy = formatRow; - EXPECT_EQ(expected, formatRowCopy(row)); - auto formatRowMove = std::move(formatRow); - EXPECT_EQ(expected, formatRowMove(row)); - - // capture value moved out from formatRow - EXPECT_NE(expected, formatRow(row)); -} - -TEST(ApplyTuple, Uncurry) { - EXPECT_EQ(42, folly::uncurry([](int x, int y) { - return x * y; - })(std::pair(6, 7))); - EXPECT_EQ(42, folly::uncurry([](int&& x, int&& y) { - return x * y; - })(std::pair(6, 7))); - EXPECT_EQ(42, folly::uncurry([](int&& x, int&& y) { - return x * y; - })(std::pair(6, 7))); - - std::string long1 = "a long string exceeding small string size"; - std::string long2 = "and here is another one!"; - std::string expected = long1 + long2; - - auto cat = folly::uncurry( - [](std::string a, std::string b) { return std::move(a) + std::move(b); }); - - EXPECT_EQ(expected, cat(std::make_pair(long1, long2))); - EXPECT_FALSE(long1.empty()); - EXPECT_FALSE(long2.empty()); - EXPECT_EQ(expected, cat(std::tie(long1, long2))); - EXPECT_FALSE(long1.empty()); - EXPECT_FALSE(long2.empty()); - EXPECT_EQ( - expected, cat(std::forward_as_tuple(std::move(long1), std::move(long2)))); - EXPECT_TRUE(long1.empty()); - EXPECT_TRUE(long2.empty()); -} - -TEST(ApplyTuple, UncurryStdFind) { - std::vector> v{{1, 9}, {2, 8}, {3, 7}, {4, 6}, {5, 5}}; - EXPECT_EQ( - 3, std::count_if(v.begin(), v.end(), folly::uncurry([](int a, int b) { - return b % a == 0; - }))); -}