Imported Upstream version 2.99.2
[platform/upstream/libsigc++.git] / sigc++ / tuple-utils / tuple_for_each.h
1 /* Copyright (C) 2016 Murray Cumming
2  *
3  * This program is free software: you can redistribute it and/or modify
4  * it under the terms of the GNU General Public License as published by
5  * the Free Software Foundation, either version 3 of the License, or
6  *  (at your option) any later version.
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11  * GNU General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License
14  * along with this program.  If not, see <http://www.gnu.org/licenses/
15  */
16
17 #ifndef SIGC_TUPLE_UTILS_TUPLE_FOR_EACH_H
18 #define SIGC_TUPLE_UTILS_TUPLE_FOR_EACH_H
19
20 #include <tuple>
21
22 namespace sigc {
23
24 namespace internal {
25
26 namespace detail {
27
28 template <template <typename> class T_visitor, std::size_t size_from_index,
29   typename... T_extras>
30 struct tuple_for_each_impl {
31   template <typename T>
32   constexpr
33   static
34   void
35   tuple_for_each(T&& t, T_extras&&... extras) {
36     //We use std::decay_t<> because tuple_size is not defined for references.
37     constexpr auto size = std::tuple_size<std::decay_t<T>>::value;
38     static_assert(size > 1, "size must be more than 0.");
39
40     constexpr auto index = size - size_from_index;
41     static_assert(index >= 0, "unexpected index.");
42
43     using element_type = typename std::tuple_element<index, std::decay_t<T>>::type;
44     T_visitor<element_type>::visit(std::get<index>(t), std::forward<T_extras>(extras)...);
45
46     tuple_for_each_impl<T_visitor, size_from_index - 1, T_extras...>::tuple_for_each(
47       std::forward<T>(t), std::forward<T_extras>(extras)...);
48   }
49 };
50
51 template <template <typename> class T_visitor, typename... T_extras>
52 struct tuple_for_each_impl<T_visitor, 1, T_extras...> {
53   template <typename T>
54   constexpr
55   static
56   void
57   tuple_for_each(T&& t, T_extras&&... extras) {
58     //We use std::decay_t<> because tuple_size is not defined for references.
59     constexpr auto size = std::tuple_size<std::decay_t<T>>::value;
60     static_assert(size > 0, "size must be more than 0.");
61
62     constexpr auto index = size - 1;
63     static_assert(index >= 0, "unexpected index.");
64
65     using element_type = typename std::tuple_element<index, std::decay_t<T>>::type;
66     T_visitor<element_type>::visit(std::get<index>(std::forward<T>(t)), std::forward<T_extras>(extras)...);
67   }
68 };
69
70 template <template <typename> class T_visitor, typename... T_extras>
71 struct tuple_for_each_impl<T_visitor, 0, T_extras...> {
72   template <typename T>
73   constexpr
74   static
75   void
76   tuple_for_each(T&& /* t */, T_extras&&... /* extras */) {
77     //Do nothing because the tuple has no elements.
78   }
79 };
80
81 } // detail namespace
82
83
84 /**
85  * Call the @e T_Visitor functors visit() method for each element,
86  * from the first to the last.
87  *
88  * @tparam T_visitor should be a template that has a static visit() method.
89  * @tparam T the tuple type.
90  * @tparam T_extras the types of any extra arguments to pass to @e T_Visitor's
91  * visit() method.
92  * @param t The tuple whose elements should be visited.
93  * @param extras Any extra arguments to pass to @e T_Visitor's visit() method.
94  */
95 template <template <typename> class T_visitor, typename T, typename... T_extras>
96 constexpr
97 void
98 tuple_for_each(T&& t, T_extras&&... extras) {
99   //We use std::decay_t<> because tuple_size is not defined for references.
100   constexpr auto size = std::tuple_size<std::decay_t<T>>::value;
101
102   if(size == 0) {
103     return;
104   }
105
106   detail::tuple_for_each_impl<T_visitor, size, T_extras...>::tuple_for_each(
107     std::forward<T>(t), std::forward<T_extras>(extras)...);
108 }
109
110 } // namespace internal
111
112 } // namespace sigc
113
114 #endif //SIGC_TUPLE_UTILS_TUPLE_FOR_EACH_H