qxLib
tuple_utils.h
Go to the documentation of this file.
1 /**
2 
3  @file tuple_utils.h
4  @brief Contains utils for working with std::tuple
5  @author Khrapov
6  @date 16.06.2023
7  @copyright © Nick Khrapov, 2023. All right reserved.
8 
9 **/
10 #pragma once
11 
12 #include <tuple>
13 #include <type_traits>
14 
15 namespace qx::tuple
16 {
17 
18 // -------------------------------------------------------- join -------------------------------------------------------
19 
20 /**
21  @struct join
22  @brief Appends types or another tuple to tuple
23 **/
24 template<class...>
25 struct join
26 {
27 };
28 
29 template<class... first_pack_t, class... second_pack_t>
30 struct join<std::tuple<first_pack_t...>, std::tuple<second_pack_t...>>
31 {
32  using type = std::tuple<first_pack_t..., second_pack_t...>;
33 };
34 
35 template<class... first_pack_t, class second_t, class... optional_args_t>
36 struct join<std::tuple<first_pack_t...>, second_t, optional_args_t...>
37 {
38  using type = std::tuple<first_pack_t..., second_t, optional_args_t...>;
39 };
40 
41 template<class... args_t>
42 using join_t = typename join<args_t...>::type;
43 
44 // ------------------------------------------------------- remove ------------------------------------------------------
45 
46 namespace details
47 {
48 
49 template<class...>
51 {
52 };
53 
54 template<class target_t, class... pack_t>
55 struct remove_single<target_t, std::tuple<pack_t...>>
56 {
57  using type = std::tuple<pack_t...>;
58 };
59 
60 template<class target_t, class parameter_t, class... pack_t>
61 struct remove_single<target_t, std::tuple<parameter_t, pack_t...>>
62 {
63  using type = typename join<
64  std::conditional_t<std::is_same_v<target_t, parameter_t>, std::tuple<>, std::tuple<parameter_t>>,
65  typename remove_single<target_t, std::tuple<pack_t...>>::type>::type;
66 };
67 
68 } // namespace details
69 
70 /**
71  @struct remove
72  @brief Removes all types from the second argument from the first tuple
73 **/
74 template<class...>
75 struct remove
76 {
77 };
78 
79 template<class... types_t>
80 struct remove<std::tuple<types_t...>, std::tuple<>>
81 {
82  using type = std::tuple<types_t...>;
83 };
84 
85 template<class target_t, class... remaining_targets_t, class... types_t>
86 struct remove<std::tuple<types_t...>, std::tuple<target_t, remaining_targets_t...>>
87 {
88  using type = typename details::remove_single<
89  target_t,
90  typename remove<std::tuple<types_t...>, std::tuple<remaining_targets_t...>>::type>::type;
91 };
92 
93 template<class... args_t>
94 using remove_t = typename remove<args_t...>::type;
95 
96 // ------------------------------------------------------ contains -----------------------------------------------------
97 
98 namespace details
99 {
100 
101 template<class T, class tuple_t>
102 struct contains;
103 
104 template<class T>
105 struct contains<T, std::tuple<>> : std::false_type
106 {
107 };
108 
109 template<class T, class U, class... args_t>
110 struct contains<T, std::tuple<U, args_t...>> : contains<T, std::tuple<args_t...>>
111 {
112 };
113 
114 template<class T, class... args_t>
115 struct contains<T, std::tuple<T, args_t...>> : std::true_type
116 {
117 };
118 
119 } // namespace details
120 
121 /**
122  @struct contains
123  @brief Check that tuple type contains T
124  @tparam tuple_t - std::tuple<> type
125  @tparam T - type to check
126 **/
127 template<class tuple_t, class T>
128 using contains = details::contains<T, tuple_t>;
129 
130 template<class tuple_t, class T>
131 static constexpr bool contains_v = contains<tuple_t, T>::value;
132 
133 // ----------------------------------------------------- transform -----------------------------------------------------
134 
135 /**
136  @struct transform
137  @brief Get a new tuple type by transforming every type inside a given tuple
138  @tparam tuple_t - std::tuple<> type
139  @tparam transformation_t - transformation type, for ex. std::add_pointer, std::remove_pointer etc. (without `_t`!)
140 **/
141 template<class tuple_t, template<class T> class transformation_t>
142 struct transform;
143 
144 template<template<class T> class transformation_t, class... args_t>
145 struct transform<std::tuple<args_t...>, transformation_t>
146 {
147  using type = std::tuple<typename transformation_t<args_t>::type...>;
148 };
149 
150 template<class tuple_t, template<class T> class transformation_t>
151 using transform_t = typename transform<tuple_t, transformation_t>::type;
152 
153 // ------------------------------------------------------- index -------------------------------------------------------
154 
155 /**
156  @struct index
157  @brief Get an index of the first occurrence of the given type
158  @tparam tuple_t - std::tuple<> type
159  @tparam T - type to check
160 **/
161 template<class tuple_t, class T>
162 struct index;
163 
164 template<class T, class... args_t>
165 struct index<std::tuple<T, args_t...>, T>
166 {
167  static constexpr size_t value = 0;
168 };
169 
170 template<class T, class U, class... args_t>
171 struct index<std::tuple<U, args_t...>, T>
172 {
173  static constexpr size_t value = 1 + index<std::tuple<args_t...>, T>::value;
174 };
175 
176 template<class tuple_t, class T>
177 constexpr size_t index_v = index<tuple_t, T>::value;
178 
179 // ------------------------------------------------------ iterate ------------------------------------------------------
180 
181 /**
182  @brief Iterate over a tuple with a callable that receives a type along with its index
183  @tparam tuple_t - std::tuple<> type
184  @tparam type_callable_t - callable type
185  @param callable - callable object
186 
187  @code
188  using tuple_type = std::tuple<float, int, std::string, unsigned, size_t>;
189  qx::tuple::iterate<tuple_type>(
190  []<class T, size_t I>()
191  {
192  // ...
193  });
194  @endcode
195 **/
196 template<class tuple_t, class type_callable_t>
197 constexpr void iterate(const type_callable_t& callable)
198 {
199  // we need to add a pointer because we can'permutationsAB compile a tuple with an abstract class type
200  using tuple_pointer_type = transform_t<tuple_t, std::add_pointer>;
201 
202  auto temp_callable = [&callable]<class T>(const T&)
203  {
204  callable.template operator()<std::remove_pointer_t<T>, index_v<tuple_pointer_type, T>>();
205  };
206 
207  std::apply(
208  [&temp_callable](auto&&... args)
209  {
210  ((temp_callable(args)), ...);
211  },
212  tuple_pointer_type());
213 }
214 
215 // ---------------------------------------------------- combinations ---------------------------------------------------
216 
217 namespace details
218 {
219 constexpr size_t pow(size_t n1, size_t n2)
220 {
221  size_t nResult = 1;
222  for (size_t i = 0; i < n2; ++i)
223  nResult *= n1;
224 
225  return nResult;
226 }
227 
228 template<class... tuples_t>
230 
231 template<class... args_t>
232 struct merge_tuples<std::tuple<args_t...>>
233 {
234  using type = std::tuple<args_t...>;
235 };
236 
237 template<class... args_1_t, class... args_2_t, class... args_rest_t>
238 struct merge_tuples<std::tuple<args_1_t...>, std::tuple<args_2_t...>, args_rest_t...>
239 {
240  using type = typename merge_tuples<std::tuple<args_1_t..., args_2_t...>, args_rest_t...>::type;
241 };
242 
243 template<class inner_tuples_tuple_t, class... all_types_t>
245 
246 template<class... inner_tuples_t, class... all_types_t>
247 struct generate_layer<std::tuple<inner_tuples_t...>, all_types_t...>
248 {
249 private:
250  template<class inner_tuple_t>
251  struct generator
252  {
253  using type = std::tuple<typename tuple::join<inner_tuple_t, all_types_t>::type...>;
254  };
255 
256 public:
257  using type = typename merge_tuples<typename generator<inner_tuples_t>::type...>::type;
258 };
259 
260 template<class all_tuples_t, class prev_new_tuples_t, size_t nCombinations, class... all_types_t>
261 struct combine;
262 
263 template<bool bBreak /* = true */, class all_tuples_t, class new_tuples_t, size_t nCombinations, class... all_types_t>
265 {
266  using type = all_tuples_t;
267 };
268 
269 template<class all_tuples_t, class new_tuples_t, size_t nCombinations, class... all_types_t>
270 struct break_or_combine</* bool bBreak = */ false, all_tuples_t, new_tuples_t, nCombinations, all_types_t...>
271 {
272  using type =
273  typename combine<tuple::join_t<all_tuples_t, new_tuples_t>, new_tuples_t, nCombinations, all_types_t...>::type;
274 };
275 
276 template<class all_tuples_t, class prev_new_tuples_t, size_t nCombinations, class... all_types_t>
277 struct combine
278 {
279  using new_tuples_t = typename generate_layer<prev_new_tuples_t, all_types_t...>::type;
280 
281  using type = typename break_or_combine<
282  nCombinations == std::tuple_size_v<all_tuples_t>,
283  all_tuples_t,
284  new_tuples_t,
285  nCombinations,
286  all_types_t...>::type;
287 };
288 
289 } // namespace details
290 
291 /**
292  @struct permutations
293  @brief Generates k-permutations with repetition for all_types_t
294  @tparam all_types_t - types for permutations
295 
296  @code
297  using t = qx::tuple::permutations_t<A, B>;
298  static_assert(std::is_same_v<
299  t,
300  std::tuple<std::tuple<A>, std::tuple<B>, std::tuple<A, A>, std::tuple<A, B>, std::tuple<B, A>, std::tuple<B, B>>>);
301  @endcode
302 **/
303 template<class... all_types_t>
305 {
306  static constexpr size_t nTypes = sizeof...(all_types_t);
307  static constexpr size_t nCombinations = nTypes * (details::pow(nTypes, nTypes) - 1) / (nTypes - 1);
308  using start_tuples_t = std::tuple<std::tuple<all_types_t>...>;
309  using type = typename details::combine<start_tuples_t, start_tuples_t, nCombinations, all_types_t...>::type;
310 };
311 
312 template<class... all_types_t>
313 using permutations_t = typename permutations<all_types_t...>::type;
314 
315 } // namespace qx::tuple
void iterate(const container_t &container, const callable_t &callable, const filter_t &filter=filters::always_true, const adapter_t &adapter=iterate_adapters::no_change)
Iterate container with filter.
Definition: iterate.h:50
double pow(T number, int nPower)
Power function for integer power.
Definition: common.inl:82
Check that tuple type contains T.
Get an index of the first occurrence of the given type.
Definition: tuple_utils.h:162
Appends types or another tuple to tuple.
Definition: tuple_utils.h:26
Generates k-permutations with repetition for all_types_t.
Definition: tuple_utils.h:305
Removes all types from the second argument from the first tuple.
Definition: tuple_utils.h:76
Get a new tuple type by transforming every type inside a given tuple.
Definition: tuple_utils.h:142