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_utils
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 
45 
46 
47 // ------------------------------------------------------- remove ------------------------------------------------------
48 
49 namespace details
50 {
51 
52 template<class...>
54 {
55 };
56 
57 template<class target_t, class... pack_t>
58 struct remove_single<target_t, std::tuple<pack_t...>>
59 {
60  using type = std::tuple<pack_t...>;
61 };
62 
63 template<class target_t, class parameter_t, class... pack_t>
64 struct remove_single<target_t, std::tuple<parameter_t, pack_t...>>
65 {
66  using type = typename join<
67  std::conditional_t<std::is_same_v<target_t, parameter_t>, std::tuple<>, std::tuple<parameter_t>>,
68  typename remove_single<target_t, std::tuple<pack_t...>>::type>::type;
69 };
70 
71 } // namespace details
72 
73 /**
74  @struct remove
75  @brief Removes all types from the second argument from the first tuple
76 **/
77 template<class...>
78 struct remove
79 {
80 };
81 
82 template<class... types_t>
83 struct remove<std::tuple<types_t...>, std::tuple<>>
84 {
85  using type = std::tuple<types_t...>;
86 };
87 
88 template<class target_t, class... remaining_targets_t, class... types_t>
89 struct remove<std::tuple<types_t...>, std::tuple<target_t, remaining_targets_t...>>
90 {
91  using type = typename details::remove_single<
92  target_t,
93  typename remove<std::tuple<types_t...>, std::tuple<remaining_targets_t...>>::type>::type;
94 };
95 
96 template<class... args_t>
97 using remove_t = typename remove<args_t...>::type;
98 
99 
100 
101 
102 // ------------------------------------------------------ contains -----------------------------------------------------
103 
104 namespace details
105 {
106 
107 template<class T, class tuple_t>
108 struct contains;
109 
110 template<class T>
111 struct contains<T, std::tuple<>> : std::false_type
112 {
113 };
114 
115 template<class T, class U, class... args_t>
116 struct contains<T, std::tuple<U, args_t...>> : contains<T, std::tuple<args_t...>>
117 {
118 };
119 
120 template<class T, class... args_t>
121 struct contains<T, std::tuple<T, args_t...>> : std::true_type
122 {
123 };
124 
125 } // namespace details
126 
127 /**
128  @struct contains
129  @brief Check that tuple type contains T
130  @tparam tuple_t - std::tuple<> type
131  @tparam T - type to check
132 **/
133 template<class tuple_t, class T>
134 using contains = details::contains<T, tuple_t>;
135 
136 template<class tuple_t, class T>
137 static constexpr bool contains_v = contains<tuple_t, T>::value;
138 
139 
140 
141 
142 // ----------------------------------------------------- transform -----------------------------------------------------
143 
144 /**
145  @struct transform
146  @brief Get a new tuple type by transforming every type inside a given tuple
147  @tparam tuple_t - std::tuple<> type
148  @tparam transformation_t - transformation type, for ex. std::add_pointer, std::remove_pointer etc. (without `_t`!)
149 **/
150 template<class tuple_t, template<class T> class transformation_t>
151 struct transform;
152 
153 template<template<class T> class transformation_t, class... args_t>
154 struct transform<std::tuple<args_t...>, transformation_t>
155 {
156  using type = std::tuple<typename transformation_t<args_t>::type...>;
157 };
158 
159 template<class tuple_t, template<class T> class transformation_t>
160 using transform_t = typename transform<tuple_t, transformation_t>::type;
161 
162 
163 
164 
165 // ------------------------------------------------------- index -------------------------------------------------------
166 
167 /**
168  @struct index
169  @brief Get an index of the first occurrence of the given type
170  @tparam tuple_t - std::tuple<> type
171  @tparam T - type to check
172 **/
173 template<class tuple_t, class T>
174 struct index;
175 
176 template<class T, class... args_t>
177 struct index<std::tuple<T, args_t...>, T>
178 {
179  static constexpr size_t value = 0;
180 };
181 
182 template<class T, class U, class... args_t>
183 struct index<std::tuple<U, args_t...>, T>
184 {
185  static constexpr size_t value = 1 + index<std::tuple<args_t...>, T>::value;
186 };
187 
188 template<class tuple_t, class T>
189 constexpr size_t index_v = index<tuple_t, T>::value;
190 
191 
192 
193 
194 // ------------------------------------------------------ iterate ------------------------------------------------------
195 
196 /**
197  @brief Iterate over a tuple with a callable that receives a type along with its index
198  @tparam tuple_t - std::tuple<> type
199  @tparam type_callable_t - callable type
200  @param callable - callable object
201 
202  @code
203  using tuple_type = std::tuple<float, int, std::string, unsigned, size_t>;
204  qx::tuple::iterate<tuple_type>(
205  []<class T, size_t I>()
206  {
207  // ...
208  });
209  @endcode
210 **/
211 template<class tuple_t, class type_callable_t>
212 constexpr void iterate(const type_callable_t& callable)
213 {
214  // we need to add a pointer because we can'permutationsAB compile a tuple with an abstract class type
215  using tuple_pointer_type = transform_t<tuple_t, std::add_pointer>;
216 
217  auto temp_callable = [&callable]<class T>(const T&)
218  {
219  callable.template operator()<std::remove_pointer_t<T>, index_v<tuple_pointer_type, T>>();
220  };
221 
222  std::apply(
223  [&temp_callable](auto&&... args)
224  {
225  ((temp_callable(args)), ...);
226  },
227  tuple_pointer_type());
228 }
229 
230 
231 
232 
233 // ---------------------------------------------------- permutations ---------------------------------------------------
234 
235 namespace permutations_details
236 {
237 constexpr size_t pow(size_t n1, size_t n2)
238 {
239  size_t nResult = 1;
240  for (size_t i = 0; i < n2; ++i)
241  nResult *= n1;
242 
243  return nResult;
244 }
245 
246 template<class... tuples_t>
248 
249 template<class... args_t>
250 struct merge_tuples<std::tuple<args_t...>>
251 {
252  using type = std::tuple<args_t...>;
253 };
254 
255 template<class... args_1_t, class... args_2_t, class... args_rest_t>
256 struct merge_tuples<std::tuple<args_1_t...>, std::tuple<args_2_t...>, args_rest_t...>
257 {
258  using type = typename merge_tuples<std::tuple<args_1_t..., args_2_t...>, args_rest_t...>::type;
259 };
260 
261 template<class inner_tuples_tuple_t, class... all_types_t>
263 
264 template<class... inner_tuples_t, class... all_types_t>
265 struct generate_layer<std::tuple<inner_tuples_t...>, all_types_t...>
266 {
267 private:
268  template<class inner_tuple_t>
269  struct generator
270  {
271  using type = std::tuple<typename join<inner_tuple_t, all_types_t>::type...>;
272  };
273 
274 public:
275  using type = typename merge_tuples<typename generator<inner_tuples_t>::type...>::type;
276 };
277 
278 template<class all_tuples_t, class prev_new_tuples_t, size_t nCombinations, class... all_types_t>
279 struct combine;
280 
281 template<bool bBreak /* = true */, class all_tuples_t, class new_tuples_t, size_t nCombinations, class... all_types_t>
283 {
284  using type = all_tuples_t;
285 };
286 
287 template<class all_tuples_t, class new_tuples_t, size_t nCombinations, class... all_types_t>
288 struct break_or_combine</* bool bBreak = */ false, all_tuples_t, new_tuples_t, nCombinations, all_types_t...>
289 {
290  using type =
291  typename combine<join_t<all_tuples_t, new_tuples_t>, new_tuples_t, nCombinations, all_types_t...>::type;
292 };
293 
294 template<class all_tuples_t, class prev_new_tuples_t, size_t nCombinations, class... all_types_t>
295 struct combine
296 {
297 private:
298  using new_tuples_t = typename generate_layer<prev_new_tuples_t, all_types_t...>::type;
299 
300 public:
301  using type = typename break_or_combine<
302  nCombinations == std::tuple_size_v<all_tuples_t>,
303  all_tuples_t,
304  new_tuples_t,
305  nCombinations,
306  all_types_t...>::type;
307 };
308 
309 } // namespace permutations_details
310 
311 /**
312  @struct permutations
313  @brief Generates k-permutations with repetition for all_types_t
314  @tparam all_types_t - types for permutations
315 
316  @code
317  using t = qx::tuple::permutations_t<A, B>;
318  static_assert(std::is_same_v<
319  t,
320  std::tuple<std::tuple<A>, std::tuple<B>, std::tuple<A, A>, std::tuple<A, B>, std::tuple<B, A>, std::tuple<B, B>>>);
321  @endcode
322 **/
323 template<class... all_types_t>
325 {
326  static constexpr size_t nTypes = sizeof...(all_types_t);
327  static constexpr size_t nCombinations = nTypes * (permutations_details::pow(nTypes, nTypes) - 1) / (nTypes - 1);
328  using start_tuples_t = std::tuple<std::tuple<all_types_t>...>;
329  using type =
330  typename permutations_details::combine<start_tuples_t, start_tuples_t, nCombinations, all_types_t...>::type;
331 };
332 
333 template<class... all_types_t>
334 using permutations_t = typename permutations<all_types_t...>::type;
335 
336 
337 
338 
339 // ------------------------------------------------- cartesian product -------------------------------------------------
340 
341 namespace cartesian_product_details
342 {
343 
344 template<class prefix_t, class tuple_t>
346 
347 template<class prefix_t, class... rest_types_t>
348 struct prepend_to_all<prefix_t, std::tuple<rest_types_t...>>
349 {
350  using type = std::tuple<typename join<std::tuple<prefix_t>, rest_types_t>::type...>;
351 };
352 
353 template<class... tuples_t>
354 struct flatten;
355 
356 template<>
357 struct flatten<>
358 {
359  using type = std::tuple<>;
360 };
361 
362 template<class... first_tuple_args_t>
363 struct flatten<std::tuple<first_tuple_args_t...>>
364 {
365  using type = std::tuple<first_tuple_args_t...>;
366 };
367 
368 template<class... first_tuple_args_t, class... second_tuple_args_t, class... rest_tuples_t>
369 struct flatten<std::tuple<first_tuple_args_t...>, std::tuple<second_tuple_args_t...>, rest_tuples_t...>
370 {
371  using type = typename flatten<std::tuple<first_tuple_args_t..., second_tuple_args_t...>, rest_tuples_t...>::type;
372 };
373 
374 } // namespace cartesian_product_details
375 
376 template<class... input_tuples_t>
378 
379 template<>
381 {
382  using type = std::tuple<std::tuple<>>;
383 };
384 
385 template<class first_input_tuple_t, class... rest_input_tuples_t>
386 struct cartesian_product<first_input_tuple_t, rest_input_tuples_t...>
387 {
388 private:
389  using tail_product_type = typename cartesian_product<rest_input_tuples_t...>::type;
390 
391  template<class element_t>
392  struct expand
393  {
395  };
396 
397  template<class... elements_t>
398  struct expand_all;
399 
400  template<class... elements_t>
401  struct expand_all<std::tuple<elements_t...>>
402  {
404  };
405 
406 public:
407  using type = typename expand_all<first_input_tuple_t>::type;
408 };
409 
410 template<class... tuples_args_t>
411 using cartesian_product_t = typename cartesian_product<tuples_args_t...>::type;
412 
413 
414 
415 
416 // ------------------------------------------------------- all of ------------------------------------------------------
417 
418 template<template<class> class predicate_t, class... args_t>
419 concept all_of_c = (predicate_t<args_t>::value && ...);
420 
421 template<template<class> class predicate_t, class tuple_t>
422 struct all_of;
423 
424 template<template<class> class predicate_t, class... args_t>
425 struct all_of<predicate_t, std::tuple<args_t...>>
426 {
427  static constexpr bool value = all_of_c<predicate_t, args_t...>;
428 };
429 
430 template<template<class> class predicate_t, class... args_t>
431 constexpr bool all_of_v = all_of<predicate_t, args_t...>::value;
432 
433 } // namespace qx::tuple_utils
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:174
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:325
Removes all types from the second argument from the first tuple.
Definition: tuple_utils.h:79
Get a new tuple type by transforming every type inside a given tuple.
Definition: tuple_utils.h:151