Index: include/llvm/ADT/STLExtras.h =================================================================== --- include/llvm/ADT/STLExtras.h +++ include/llvm/ADT/STLExtras.h @@ -24,6 +24,7 @@ #include #include #include +#include #include // for std::pair #include "llvm/ADT/Optional.h" @@ -698,6 +699,28 @@ return detail::make_enumerator(std::begin(Range), std::end(Range)); } +namespace detail { +template +auto apply_tuple_impl(F &&f, Tuple &&t, index_sequence) + -> decltype(std::forward(f)(std::get(std::forward(t))...)) { + return std::forward(f)(std::get(std::forward(t))...); +} +} + +/// Given an input tuple (a1, a2, ..., an), pass the arguments of the +/// tuple variadically to f as if by calling f(a1, a2, ..., an) and +/// return the result. +template +auto apply_tuple(F &&f, Tuple &&t) -> decltype(detail::apply_tuple_impl( + std::forward(f), std::forward(t), + build_index_impl< + std::tuple_size::type>::value>())) { + using Indices = build_index_impl< + std::tuple_size::type>::value>; + + return detail::apply_tuple_impl(std::forward(f), std::forward(t), + Indices()); +} } // End llvm namespace #endif Index: unittests/ADT/STLExtrasTest.cpp =================================================================== --- unittests/ADT/STLExtrasTest.cpp +++ unittests/ADT/STLExtrasTest.cpp @@ -86,4 +86,67 @@ EXPECT_EQ('c', foo[1]); EXPECT_EQ('d', foo[2]); } + +TEST(STLExtrasTest, ApplyTuple) { + auto T = std::make_tuple(1, 2, 3, 4); + auto U = llvm::apply_tuple( + [](int A, int B, int C, int D) { + return std::make_tuple(A - B, B - C, C - D, D - A); + }, + T); + + EXPECT_EQ(-1, std::get<0>(U)); + EXPECT_EQ(-1, std::get<1>(U)); + EXPECT_EQ(-1, std::get<2>(U)); + EXPECT_EQ(3, std::get<3>(U)); + + auto V = llvm::apply_tuple( + [](int A, int B, int C, int D) { + return std::make_tuple(std::make_pair(A, char('A' + A)), + std::make_pair(B, char('A' + B)), + std::make_pair(C, char('A' + C)), D); + }, + T); + + EXPECT_EQ(std::make_pair(1, 'B'), std::get<0>(V)); + EXPECT_EQ(std::make_pair(2, 'C'), std::get<1>(V)); + EXPECT_EQ(std::make_pair(3, 'D'), std::get<2>(V)); + EXPECT_EQ(4, std::get<3>(V)); +} + +struct deref_iterator_tuple { + template auto operator()(Iters &&... Items) { + return std::make_tuple(*Items...); + } +}; + +struct increment_iterator_tuple { + template auto operator()(Iters &&... Items) { + return std::make_tuple(++Items...); + } +}; + +TEST(STLExtrasTest, ApplyTupleVariadic) { + std::vector A = {1, 2, 3}; + std::vector B = {'A', 'B', 'C'}; + std::vector C = {"A", "B", "C"}; + + auto Iters = std::make_tuple(A.begin(), B.begin(), C.begin()); + auto Values = apply_tuple(deref_iterator_tuple(), Iters); + + static_assert( + std::is_same, decltype(Values)>::value, + "Incorrect tuple type!"); + + EXPECT_EQ(1, std::get<0>(Values)); + EXPECT_EQ('A', std::get<1>(Values)); + EXPECT_EQ("A", std::get<2>(Values)); + + Iters = apply_tuple(increment_iterator_tuple(), Iters); + Values = apply_tuple(deref_iterator_tuple(), Iters); + + EXPECT_EQ(2, std::get<0>(Values)); + EXPECT_EQ('B', std::get<1>(Values)); + EXPECT_EQ("B", std::get<2>(Values)); +} }