Add STLExtras apply_tuple
Zachary Turner via llvm-commits
llvm-commits at lists.llvm.org
Thu Sep 29 15:33:30 PDT 2016
Given a tuple of type Ts..., invokes a user-supplied functor passing Ts...
variadically as the parameter list, allowing the functor to return a new
tuple (of a possibly different type).
I believe this is standard in C++17, so I'm adding it early. In one of the
test cases I demonstrate some useful use cases, including that of iterating
efficiently iterating and de-referencing multiple ranges in parallel.
>From 46117057cdbd3558cb542a3fd6969b0dcde304ab Mon Sep 17 00:00:00 2001
From: Zachary Turner <zturner at google.com>
Date: Thu, 29 Sep 2016 15:16:35 -0700
Subject: [PATCH] apply_tuple
---
include/llvm/ADT/STLExtras.h | 13 +++++++++
unittests/ADT/STLExtrasTest.cpp | 63
+++++++++++++++++++++++++++++++++++++++++
2 files changed, 76 insertions(+)
diff --git a/include/llvm/ADT/STLExtras.h b/include/llvm/ADT/STLExtras.h
index 63f919d..5ebba37 100644
--- a/include/llvm/ADT/STLExtras.h
+++ b/include/llvm/ADT/STLExtras.h
@@ -24,6 +24,7 @@
#include <functional>
#include <iterator>
#include <memory>
+#include <tuple>
#include <utility> // for std::pair
#include "llvm/ADT/Optional.h"
@@ -680,6 +681,18 @@ template <typename R> auto enumerate(R &&Range) {
return detail::enumerator_impl<I, V>(std::begin(Range), std::end(Range));
}
+template <typename F, typename Tuple, std::size_t... I>
+auto apply_tuple_impl(F &&f, Tuple &&t, index_sequence<I...>) {
+ return std::forward<F>(f)(std::get<I>(std::forward<Tuple>(t))...);
+}
+
+template <typename F, typename Tuple> auto apply_tuple(F &&f, Tuple &&t) {
+ using Indices =
+ build_index_impl<std::tuple_size<std::decay<Tuple>::type>::value>;
+
+ return apply_tuple_impl(std::forward<F>(f), std::forward<Tuple>(t),
+ Indices());
+}
} // End llvm namespace
#endif
diff --git a/unittests/ADT/STLExtrasTest.cpp
b/unittests/ADT/STLExtrasTest.cpp
index d7457f5..26953cb 100644
--- a/unittests/ADT/STLExtrasTest.cpp
+++ b/unittests/ADT/STLExtrasTest.cpp
@@ -79,4 +79,67 @@ TEST(STLExtrasTest, EnumerateModify) {
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 <typename... Iters> auto operator()(Iters &&... Items) {
+ return std::make_tuple(*Items...);
+ }
+};
+
+struct increment_iterator_tuple {
+ template <typename... Iters> auto operator()(Iters &&... Items) {
+ return std::make_tuple(++Items...);
+ }
+};
+
+TEST(STLExtrasTest, ApplyTupleVariadic) {
+ std::vector<int> A = {1, 2, 3};
+ std::vector<char> B = {'A', 'B', 'C'};
+ std::vector<std::string> 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<std::tuple<int, char, std::string>,
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));
+}
}
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20160929/d925bd17/attachment.html>
More information about the llvm-commits
mailing list