Commit efc54c28 authored by Sven Over's avatar Sven Over Committed by Facebook Github Bot 3

Let applyTuple accept any number of tuples

Summary:
Instead of passing exactly one tuple of arguments to applyTuple,
this diff allows to pass any number (zero or more) of tuples.

This can be very handy when piecing together arguments for
a function call.

Reviewed By: yfeldblum

Differential Revision: D3681499

fbshipit-source-id: a75a448636759f71db8d303e9dccada5b559af54
parent ef50b189
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
#pragma once #pragma once
#include <functional> #include <functional>
#include <tuple>
#include <utility> #include <utility>
namespace folly { namespace folly {
...@@ -46,9 +47,17 @@ struct MakeIndexSequence : MakeIndexSequence<N - 1, N - 1, Is...> {}; ...@@ -46,9 +47,17 @@ struct MakeIndexSequence : MakeIndexSequence<N - 1, N - 1, Is...> {};
template <std::size_t... Is> template <std::size_t... Is>
struct MakeIndexSequence<0, Is...> : IndexSequence<Is...> {}; struct MakeIndexSequence<0, Is...> : IndexSequence<Is...> {};
template <class Tuple> inline constexpr std::size_t sum() {
using MakeIndexSequenceFromTuple = return 0;
MakeIndexSequence<std::tuple_size<typename std::decay<Tuple>::type>::value>; }
template <typename... Args>
inline constexpr std::size_t sum(std::size_t v1, Args... vs) {
return v1 + sum(vs...);
}
template <class... Tuple>
using MakeIndexSequenceFromTuple = MakeIndexSequence<sum(
std::tuple_size<typename std::decay<Tuple>::type>::value...)>;
// This is to allow using this with pointers to member functions, // This is to allow using this with pointers to member functions,
// where the first argument in the tuple will be the this pointer. // where the first argument in the tuple will be the this pointer.
...@@ -68,21 +77,42 @@ inline constexpr auto call(F&& f, Tuple&& t, IndexSequence<Indexes...>) ...@@ -68,21 +77,42 @@ inline constexpr auto call(F&& f, Tuple&& t, IndexSequence<Indexes...>)
return std::forward<F>(f)(std::get<Indexes>(std::forward<Tuple>(t))...); return std::forward<F>(f)(std::get<Indexes>(std::forward<Tuple>(t))...);
} }
template <class Tuple, std::size_t... Indexes>
inline constexpr auto forwardTuple(Tuple&& t, IndexSequence<Indexes...>)
-> decltype(
std::forward_as_tuple(std::get<Indexes>(std::forward<Tuple>(t))...)) {
return std::forward_as_tuple(std::get<Indexes>(std::forward<Tuple>(t))...);
}
} // namespace apply_tuple } // namespace apply_tuple
} // namespace detail } // namespace detail
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
template <class F, class Tuple> /**
inline constexpr auto applyTuple(F&& f, Tuple&& t) * 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 <class F, class... Tuples>
inline constexpr auto applyTuple(F&& f, Tuples&&... t)
-> decltype(detail::apply_tuple::call( -> decltype(detail::apply_tuple::call(
detail::apply_tuple::makeCallable(std::forward<F>(f)), detail::apply_tuple::makeCallable(std::forward<F>(f)),
std::forward<Tuple>(t), std::tuple_cat(detail::apply_tuple::forwardTuple(
detail::apply_tuple::MakeIndexSequenceFromTuple<Tuple>{})) { std::forward<Tuples>(t),
detail::apply_tuple::MakeIndexSequenceFromTuple<Tuples>{})...),
detail::apply_tuple::MakeIndexSequenceFromTuple<Tuples...>{})) {
return detail::apply_tuple::call( return detail::apply_tuple::call(
detail::apply_tuple::makeCallable(std::forward<F>(f)), detail::apply_tuple::makeCallable(std::forward<F>(f)),
std::forward<Tuple>(t), std::tuple_cat(detail::apply_tuple::forwardTuple(
detail::apply_tuple::MakeIndexSequenceFromTuple<Tuple>{}); std::forward<Tuples>(t),
detail::apply_tuple::MakeIndexSequenceFromTuple<Tuples>{})...),
detail::apply_tuple::MakeIndexSequenceFromTuple<Tuples...>{});
} }
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
......
...@@ -287,3 +287,30 @@ TEST(ApplyTuple, Pair) { ...@@ -287,3 +287,30 @@ TEST(ApplyTuple, Pair) {
EXPECT_EQ(folly::applyTuple(add, std::pair<int, int>{1200, 34}), 1234); EXPECT_EQ(folly::applyTuple(add, std::pair<int, int>{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)));
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment