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 <cstddef>
13 #include <tuple>
14 #include <type_traits>
15 
16 namespace qx::tuple_utils
17 {
18 
19 // -------------------------------------------------------- join -------------------------------------------------------
20 
21 /**
22  @struct join
23  @brief Appends types or another tuple to tuple
24 **/
25 template<class...>
26 struct join
27 {
28 };
29 
30 template<class... first_pack_t, class... second_pack_t>
31 struct join<std::tuple<first_pack_t...>, std::tuple<second_pack_t...>>
32 {
33  using type = std::tuple<first_pack_t..., second_pack_t...>;
34 };
35 
36 template<class... first_pack_t, class second_t, class... optional_args_t>
37 struct join<std::tuple<first_pack_t...>, second_t, optional_args_t...>
38 {
39  using type = std::tuple<first_pack_t..., second_t, optional_args_t...>;
40 };
41 
42 template<class... args_t>
43 using join_t = typename join<args_t...>::type;
44 
45 
46 
47 
48 // ------------------------------------------------------- remove ------------------------------------------------------
49 
50 namespace details
51 {
52 
53 template<class...>
55 {
56 };
57 
58 template<class target_t, class... pack_t>
59 struct remove_single<target_t, std::tuple<pack_t...>>
60 {
61  using type = std::tuple<pack_t...>;
62 };
63 
64 template<class target_t, class parameter_t, class... pack_t>
65 struct remove_single<target_t, std::tuple<parameter_t, pack_t...>>
66 {
67  using type = typename join<
68  std::conditional_t<std::is_same_v<target_t, parameter_t>, std::tuple<>, std::tuple<parameter_t>>,
69  typename remove_single<target_t, std::tuple<pack_t...>>::type>::type;
70 };
71 
72 } // namespace details
73 
74 /**
75  @struct remove
76  @brief Removes all types from the second argument from the first tuple
77 **/
78 template<class...>
79 struct remove
80 {
81 };
82 
83 template<class... types_t>
84 struct remove<std::tuple<types_t...>, std::tuple<>>
85 {
86  using type = std::tuple<types_t...>;
87 };
88 
89 template<class target_t, class... remaining_targets_t, class... types_t>
90 struct remove<std::tuple<types_t...>, std::tuple<target_t, remaining_targets_t...>>
91 {
92  using type = typename details::remove_single<
93  target_t,
94  typename remove<std::tuple<types_t...>, std::tuple<remaining_targets_t...>>::type>::type;
95 };
96 
97 template<class... args_t>
98 using remove_t = typename remove<args_t...>::type;
99 
100 
101 
102 
103 // ------------------------------------------------------ contains -----------------------------------------------------
104 
105 namespace details
106 {
107 
108 template<class T, class tuple_t>
109 struct contains;
110 
111 template<class T>
112 struct contains<T, std::tuple<>> : std::false_type
113 {
114 };
115 
116 template<class T, class U, class... args_t>
117 struct contains<T, std::tuple<U, args_t...>> : contains<T, std::tuple<args_t...>>
118 {
119 };
120 
121 template<class T, class... args_t>
122 struct contains<T, std::tuple<T, args_t...>> : std::true_type
123 {
124 };
125 
126 } // namespace details
127 
128 /**
129  @struct contains
130  @brief Check that tuple type contains T
131  @tparam tuple_t - std::tuple<> type
132  @tparam T - type to check
133 **/
134 template<class tuple_t, class T>
135 using contains = details::contains<T, tuple_t>;
136 
137 template<class tuple_t, class T>
138 static constexpr bool contains_v = contains<tuple_t, T>::value;
139 
140 
141 
142 
143 // ----------------------------------------------------- transform -----------------------------------------------------
144 
145 /**
146  @struct transform
147  @brief Get a new tuple type by transforming every type inside a given tuple
148  @tparam tuple_t - std::tuple<> type
149  @tparam transformation_t - transformation type, for ex. std::add_pointer, std::remove_pointer etc. (without `_t`!)
150 **/
151 template<class tuple_t, template<class T> class transformation_t>
152 struct transform;
153 
154 template<template<class T> class transformation_t, class... args_t>
155 struct transform<std::tuple<args_t...>, transformation_t>
156 {
157  using type = std::tuple<typename transformation_t<args_t>::type...>;
158 };
159 
160 template<class tuple_t, template<class T> class transformation_t>
161 using transform_t = typename transform<tuple_t, transformation_t>::type;
162 
163 
164 
165 
166 // ------------------------------------------------------- index -------------------------------------------------------
167 
168 /**
169  @struct index
170  @brief Get an index of the first occurrence of the given type
171  @tparam tuple_t - std::tuple<> type
172  @tparam T - type to check
173 **/
174 template<class tuple_t, class T>
175 struct index;
176 
177 template<class T, class... args_t>
178 struct index<std::tuple<T, args_t...>, T>
179 {
180  static constexpr size_t value = 0;
181 };
182 
183 template<class T, class U, class... args_t>
184 struct index<std::tuple<U, args_t...>, T>
185 {
186  static constexpr size_t value = 1 + index<std::tuple<args_t...>, T>::value;
187 };
188 
189 template<class tuple_t, class T>
190 constexpr size_t index_v = index<tuple_t, T>::value;
191 
192 
193 
194 
195 // ------------------------------------------------------ iterate ------------------------------------------------------
196 
197 namespace iterate_details
198 {
199 
200 template<class tuple_t, class type_callable_t, size_t... indices>
201 constexpr void iterate_impl(const type_callable_t& callable, std::index_sequence<indices...>)
202 {
203  (callable.template operator()<std::tuple_element_t<indices, tuple_t>, indices>(), ...);
204 }
205 
206 } // namespace iterate_details
207 
208 /**
209  @brief Iterate over a tuple with a callable that receives a type along with its index
210  @tparam tuple_t - std::tuple<> type
211  @tparam type_callable_t - callable type
212  @param callable - callable object
213 
214  @code
215  using tuple_type = std::tuple<float, int, std::string, unsigned, size_t>;
216  qx::tuple::iterate<tuple_type>(
217  []<class T, size_t I>()
218  {
219  // ...
220  });
221  @endcode
222 **/
223 template<class tuple_t, class type_callable_t>
224 constexpr void iterate(const type_callable_t& callable)
225 {
226  iterate_details::iterate_impl<tuple_t>(callable, std::make_index_sequence<std::tuple_size_v<tuple_t>>());
227 }
228 
229 
230 
231 
232 // ---------------------------------------------------- permutations ---------------------------------------------------
233 
234 namespace permutations_details
235 {
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
constexpr 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:175
Appends types or another tuple to tuple.
Definition: tuple_utils.h:27
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:80
Get a new tuple type by transforming every type inside a given tuple.
Definition: tuple_utils.h:152