Line data Source code
1 1 : // Distributed under the MIT License.
2 : // See LICENSE.txt for details.
3 :
4 : /// \file
5 : /// Defines functions for manipulating tuples
6 :
7 : #pragma once
8 :
9 : #include <tuple>
10 : #include <utility>
11 :
12 : namespace tuple_impl_detail {
13 : template <bool ReverseIteration, typename... Elements, typename N_aryOp,
14 : typename... Args, size_t... Is>
15 : constexpr inline void tuple_fold_impl(const std::tuple<Elements...>& tupull,
16 : N_aryOp&& op,
17 : std::index_sequence<Is...> /*meta*/,
18 : Args&... args) {
19 : constexpr size_t tuple_size = sizeof...(Elements);
20 : static_cast<void>(std::initializer_list<char>{
21 : (static_cast<void>(
22 : op(std::get<(ReverseIteration ? tuple_size - 1 - Is : Is)>(tupull),
23 : args...)),
24 : '0')...});
25 : }
26 :
27 : template <bool ReverseIteration, typename... Elements, typename N_aryOp,
28 : typename... Args, size_t... Is>
29 : constexpr inline void tuple_counted_fold_impl(
30 : const std::tuple<Elements...>& tupull, N_aryOp&& op,
31 : std::index_sequence<Is...> /*meta*/, Args&... args) {
32 : constexpr size_t tuple_size = sizeof...(Elements);
33 : static_cast<void>(std::initializer_list<char>{
34 : (static_cast<void>(
35 : op(std::get<(ReverseIteration ? tuple_size - 1 - Is : Is)>(tupull),
36 : (ReverseIteration ? tuple_size - 1 - Is : Is), args...)),
37 : '0')...});
38 : }
39 :
40 : template <bool ReverseIteration, typename... Elements, typename N_aryOp,
41 : typename... Args, size_t... Is>
42 : constexpr inline void tuple_transform_impl(
43 : const std::tuple<Elements...>& tupull, N_aryOp&& op,
44 : std::index_sequence<Is...> /*meta*/, Args&... args) {
45 : constexpr size_t tuple_size = sizeof...(Elements);
46 : static_cast<void>(std::initializer_list<char>{(
47 : static_cast<void>(op(
48 : std::get<(ReverseIteration ? tuple_size - 1 - Is : Is)>(tupull),
49 : std::integral_constant<size_t, (ReverseIteration ? tuple_size - 1 - Is
50 : : Is)>{},
51 : args...)),
52 : '0')...});
53 : }
54 : } // namespace tuple_impl_detail
55 :
56 : /// @{
57 : /*!
58 : * \ingroup UtilitiesGroup
59 : * \brief Perform a fold over a std::tuple
60 : *
61 : * \details
62 : * Iterates over the elements in a std::tuple `tuple` from left to right
63 : * (left fold) calling `op(element, args...)` on each element in `tuple`. A
64 : * right fold can be done by explicitly setting the first template parameter
65 : * to true. Folds are easily implemented using `tuple_fold` by updating
66 : * one of the `args...` at each iteration. If you need the index of the current
67 : * element you can use the `tuple_counted_fold` variant. `tuple_counted_fold`
68 : * passes the current index as the second argument to the Callable `op`. That
69 : * is, `op(element, index, args...)`.
70 : *
71 : * \example
72 : * The sum of a std::tuple of Arithmetics can be computed in several ways.
73 : * First, you can use a lambda:
74 : * \snippet Utilities/Test_Tuple.cpp tuple_fold_lambda
75 : * You'll notice that `state` is taken by reference and mutated.
76 : *
77 : * You can do the same thing with a struct defined as
78 : * \snippet Utilities/Test_Tuple.cpp tuple_fold_struct_defn
79 : * and then using an instance of the struct
80 : * \snippet Utilities/Test_Tuple.cpp tuple_fold_struct
81 : *
82 : * \note You are not able to pass a function pointer to `tuple_fold` or
83 : * `tuple_counted_fold` because you cannot pass a pointer to a function
84 : * template, only a function.
85 : *
86 : * \see expand_pack tuple_transform tuple_fold tuple_counted_fold std::tuple
87 : */
88 : template <bool ReverseIteration = false, typename... Elements, typename N_aryOp,
89 : typename... Args>
90 1 : constexpr inline void tuple_fold(const std::tuple<Elements...>& tuple,
91 : N_aryOp&& op, Args&&... args) {
92 : tuple_impl_detail::tuple_fold_impl<ReverseIteration>(
93 : tuple, std::forward<N_aryOp>(op),
94 : std::make_index_sequence<sizeof...(Elements)>{}, args...);
95 : }
96 :
97 : template <bool ReverseIteration = false, typename... Elements, typename N_aryOp,
98 : typename... Args>
99 1 : constexpr inline void tuple_counted_fold(const std::tuple<Elements...>& tuple,
100 : N_aryOp&& op, Args&&... args) {
101 : tuple_impl_detail::tuple_counted_fold_impl<ReverseIteration>(
102 : tuple, std::forward<N_aryOp>(op),
103 : std::make_index_sequence<sizeof...(Elements)>{}, args...);
104 : }
105 : /// @}
106 :
107 : /*!
108 : * \ingroup UtilitiesGroup
109 : * \brief Perform a transform over a std::tuple
110 : *
111 : * \details
112 : * Iterates over the elements in a std::tuple `tuple` from left to right
113 : * calling `op.operator()(element, index, args...)` on each element
114 : * in `tuple`. A right-to-left transform can be done by explicitly setting
115 : * the first template parameter to true. The second argument of the invokable
116 : * will be a deduced `std::integral_constant<size_t, value>`, from which the
117 : * current index can be extracted by using `decltype(index)::%value`.
118 : * For a function object the `decltype(index)` can be replaced by the deduced
119 : * type of `index`. For example,
120 : * \snippet Utilities/Test_Tuple.cpp tuple_transform_negate
121 : *
122 : * Using `tuple_transform` with a generic lambda goes as follows,
123 : * \snippet Utilities/Test_Tuple.cpp tuple_transform
124 : *
125 : * \see expand_pack tuple_fold tuple_counted_fold std::tuple
126 : */
127 : template <bool ReverseIteration = false, typename... Elements, typename N_aryOp,
128 : typename... Args>
129 1 : constexpr inline void tuple_transform(const std::tuple<Elements...>& tuple,
130 : N_aryOp&& op, Args&&... args) {
131 : tuple_impl_detail::tuple_transform_impl<ReverseIteration>(
132 : tuple, std::forward<N_aryOp>(op),
133 : std::make_index_sequence<sizeof...(Elements)>{}, args...);
134 : }
|