meta.h
Go to the documentation of this file.
1 #ifndef TTG_UTIL_META_H
2 #define TTG_UTIL_META_H
3 
4 #include <functional>
5 #include <type_traits>
6 
7 #include "ttg/util/span.h"
8 #include "ttg/util/typelist.h"
9 #include "ttg/buffer.h"
10 #include "ttg/ptr.h"
11 #include "ttg/devicescratch.h"
12 
13 namespace ttg {
14 
15  class Void;
16 
17  namespace meta {
18 
19 #if __cplusplus >= 201703L
20  using std::void_t;
21 #else
22  template <class...>
23  using void_t = void;
24 #endif
25 
26  template <typename T>
27  using remove_cvr_t = std::remove_cv_t<std::remove_reference_t<T>>;
28 
30  // (meta)tuple/typelist/typepack manipulations
32 
33  // tuple<Ts...> -> tuple<std::remove_reference_t<Ts>...>
34  template <typename T, typename Enabler = void>
35  struct nonref_tuple;
36 
37  template <typename... Ts>
38  struct nonref_tuple<std::tuple<Ts...>> {
39  using type = std::tuple<typename std::remove_reference<Ts>::type...>;
40  };
41 
42  template <typename Tuple>
44 
45  template <typename... TupleTs>
46  struct tuple_concat;
47 
48  template <typename... Ts>
49  struct tuple_concat<std::tuple<Ts...>> {
50  using type = std::tuple<Ts...>;
51  };
52 
53  template <typename... Ts, typename... Us, typename... R>
54  struct tuple_concat<std::tuple<Ts...>, std::tuple<Us...>, R...> {
55  using type = typename tuple_concat<
56  decltype(std::tuple_cat(std::declval<std::tuple<Ts...>>(), std::declval<std::tuple<Us...>>())), R...>::type;
57  };
58 
59  template <typename... TupleTs>
60  using tuple_concat_t = typename tuple_concat<TupleTs...>::type;
61 
62  // filtered_tuple<tuple,p>::type returns tuple with types for which the predicate evaluates to true
63  template <typename Tuple, template <typename> typename Predicate>
65 
66  namespace detail {
67  template <bool>
68  struct keep_or_drop {
69  template <typename E>
70  using type = std::tuple<E>;
71  };
72 
73  template <>
74  struct keep_or_drop<false> {
75  template <typename E>
76  using type = std::tuple<>;
77  };
78  } // namespace detail
79 
80  template <template <typename> typename Pred, typename... Es>
81  struct filtered_tuple<std::tuple<Es...>, Pred> {
82  using type = decltype(std::tuple_cat(
83  std::declval<typename detail::keep_or_drop<Pred<Es>::value>::template type<Es>>()...));
84  };
85 
86  template <typename Tuple, template <typename> typename Pred>
88 
89  // clang-format off
94  // clang-format on
95  template <template <typename> typename Predicate, bool Default, typename... Ts>
96  struct probe_last;
97 
98  template <template <typename> typename Predicate, bool Default>
99  struct probe_last<Predicate, Default> : public std::bool_constant<Default> {};
100 
101  template <template <typename> typename Predicate, bool Default, typename T>
102  struct probe_last<Predicate, Default, T> : public std::bool_constant<Predicate<T>::value> {};
103 
104  template <template <typename> typename Predicate, bool Default, typename T1, typename... Ts>
105  struct probe_last<Predicate, Default, T1, Ts...> : public probe_last<Predicate, Default, Ts...> {};
106 
107  template <template <typename> typename Predicate, bool Default, typename... Ts>
108  struct probe_last<Predicate, Default, std::tuple<Ts...>> : public probe_last<Predicate, Default, Ts...> {};
109 
110  template <template <typename> typename Predicate, bool Default, typename... Ts>
111  struct probe_last<Predicate, Default, ttg::typelist<Ts...>> : public probe_last<Predicate, Default, Ts...> {};
112 
113  // clang-format off
118  // clang-format on
119  template <template <typename> typename Predicate, bool Default, typename... Ts>
120  constexpr bool probe_last_v = probe_last<Predicate, Default, Ts...>::value;
121 
122  // clang-format off
127  // clang-format on
128  template <template <typename> typename Predicate, bool Default, typename... Ts>
129  struct probe_first;
130 
131  template <template <typename> typename Predicate, bool Default>
132  struct probe_first<Predicate, Default> : public std::bool_constant<Default> {};
133 
134  template <template <typename> typename Predicate, bool Default, typename T1, typename... Ts>
135  struct probe_first<Predicate, Default, T1, Ts...> : public std::bool_constant<Predicate<T1>::value> {};
136 
137  template <template <typename> typename Predicate, bool Default, typename... Ts>
138  struct probe_first<Predicate, Default, std::tuple<Ts...>> : public probe_first<Predicate, Default, Ts...> {};
139 
140  template <template <typename> typename Predicate, bool Default, typename... Ts>
141  struct probe_first<Predicate, Default, ttg::typelist<Ts...>> : public probe_first<Predicate, Default, Ts...> {};
142 
143  // clang-format off
148  // clang-format on
149  template <template <typename> typename Predicate, bool Default, typename... Ts>
150  constexpr bool probe_first_v = probe_first<Predicate, Default, Ts...>::value;
151 
152  // clang-format off
156  // clang-format on
157  template <template <typename> typename Predicate, typename... Ts>
158  struct probe_any : std::bool_constant<(Predicate<Ts>::value || ...)> {};
159 
160  template <template <typename> typename Predicate, typename... Ts>
161  struct probe_any<Predicate, std::tuple<Ts...>> : public probe_any<Predicate, Ts...> {};
162 
163  template <template <typename> typename Predicate, typename... Ts>
164  struct probe_any<Predicate, ttg::typelist<Ts...>> : public probe_any<Predicate, Ts...> {};
165 
166  // clang-format off
170  // clang-format on
171  template <template <typename> typename Predicate, typename... Ts>
172  constexpr bool probe_any_v = probe_any<Predicate, Ts...>::value;
173 
174  // clang-format off
178  // clang-format on
179  template <template <typename> typename Predicate, typename... Ts>
180  struct probe_all : std::bool_constant<(Predicate<Ts>::value && ...)> {};
181 
182  template <template <typename> typename Predicate, typename... Ts>
183  struct probe_all<Predicate, std::tuple<Ts...>> : public probe_all<Predicate, Ts...> {};
184 
185  template <template <typename> typename Predicate, typename... Ts>
186  struct probe_all<Predicate, ttg::typelist<Ts...>> : public probe_all<Predicate, Ts...> {};
187 
188  // clang-format off
192  // clang-format on
193  template <template <typename> typename Predicate, typename... Ts>
194  constexpr bool probe_all_v = probe_all<Predicate, Ts...>::value;
195 
197  // is_Void_v
198  // is_void_v = Void or void
199  // is_none_void_v
200  // is_any_void_v
201  // is_last_void_v
202  // void_to_Void_t
203  // is_any_nonconst_lvalue_reference_v
205  template <typename T>
206  constexpr bool is_Void_v = std::is_same_v<std::decay_t<T>, Void>;
207 
208  template <typename T>
209  constexpr bool is_void_v = is_Void_v<T> || std::is_void_v<T>;
210 
211  template <typename T>
212  struct is_void : std::bool_constant<is_void_v<T>> {};
213 
214  template <typename T>
215  constexpr bool is_nonvoid_v = !is_void_v<T>;
216 
217  template <typename T>
218  struct is_nonvoid : std::bool_constant<is_nonvoid_v<T>> {};
219 
220  template <typename... Ts>
221  constexpr bool is_all_void_v = (is_void_v<Ts> && ...);
222 
223  template <typename... Ts>
224  constexpr bool is_all_void_v<ttg::typelist<Ts...>> = is_all_void_v<Ts...>;
225 
226  template <typename... Ts>
227  constexpr bool is_all_Void_v = (is_Void_v<Ts> && ...);
228 
229  template <typename... Ts>
230  constexpr bool is_all_Void_v<ttg::typelist<Ts...>> = is_all_Void_v<Ts...>;
231 
232  template <typename... Ts>
233  constexpr bool is_any_void_v = (is_void_v<Ts> || ...);
234 
235  template <typename... Ts>
236  constexpr bool is_any_void_v<ttg::typelist<Ts...>> = is_all_void_v<Ts...>;
237 
238  template <typename... Ts>
239  constexpr bool is_any_Void_v = (is_Void_v<Ts> || ...);
240 
241  template <typename... Ts>
242  constexpr bool is_any_Void_v<ttg::typelist<Ts...>> = is_any_Void_v<Ts...>;
243 
244  template <typename... Ts>
245  constexpr bool is_none_void_v = !is_any_void_v<Ts...>;
246 
247  template <typename... Ts>
248  constexpr bool is_none_void_v<ttg::typelist<Ts...>> = is_none_void_v<Ts...>;
249 
250  template <typename... Ts>
251  constexpr bool is_none_Void_v = !is_any_Void_v<Ts...>;
252 
253  template <typename... Ts>
254  constexpr bool is_none_Void_v<ttg::typelist<Ts...>> = is_none_Void_v<Ts...>;
255 
256  template <typename... Ts>
257  struct is_last_void : probe_last<is_void, false, Ts...> {};
258 
259  template <typename... Ts>
260  constexpr bool is_last_void_v = is_last_void<Ts...>::value;
261 
262  template <typename T>
263  struct void_to_Void {
264  using type = T;
265  };
266  template <>
267  struct void_to_Void<void> {
268  using type = Void;
269  };
270  template <typename T>
272 
273  template <typename T>
275  std::is_lvalue_reference_v<T> &&std::is_const_v<std::remove_reference_t<T>>;
276 
277  template <typename T>
278  struct is_const_lvalue_reference : std::bool_constant<is_const_lvalue_reference_v<T>> {};
279 
280  template <typename T>
282  std::is_lvalue_reference_v<T> && !std::is_const_v<std::remove_reference_t<T>>;
283 
284  template <typename T>
285  struct is_nonconst_lvalue_reference : std::bool_constant<is_nonconst_lvalue_reference_v<T>> {};
286 
287  template <typename... Ts>
288  constexpr bool is_any_nonconst_lvalue_reference_v = (is_nonconst_lvalue_reference_v<Ts> || ...);
289 
290  template <typename... Ts>
292 
293  template <typename... Ts>
294  constexpr bool is_any_nonconst_lvalue_reference_v<std::tuple<Ts...>> = is_any_nonconst_lvalue_reference_v<Ts...>;
295 
296 
298  // device type traits
300 
301  template<typename T>
302  struct is_ptr : std::false_type
303  { };
304 
305  template<typename T>
306  struct is_ptr<ttg::Ptr<T>> : std::true_type
307  { };
308 
309  template<typename T>
310  constexpr bool is_ptr_v = is_ptr<T>::value;
311 
312  template<typename T>
313  struct is_buffer : std::false_type
314  { };
315 
316  template<typename T, typename A>
317  struct is_buffer<ttg::Buffer<T, A>> : std::true_type
318  { };
319 
320  template<typename T, typename A>
321  struct is_buffer<const ttg::Buffer<T, A>> : std::true_type
322  { };
323 
324  template<typename T>
326 
327  template<typename T>
328  struct is_devicescratch : std::false_type
329  { };
330 
331  template<typename T>
332  struct is_devicescratch<ttg::devicescratch<T>> : std::true_type
333  { };
334 
335  template<typename T>
336  struct is_devicescratch<const ttg::devicescratch<T>> : std::true_type
337  { };
338 
339  template<typename T>
341 
342 
344  // typelist metafunctions
346 
348  template <typename Typelist, std::size_t N, typename Enabler = void>
349  struct drop_first_n;
350 
351  template <typename... Ts>
352  struct drop_first_n<std::tuple<Ts...>, std::size_t(0)> {
353  using type = std::tuple<Ts...>;
354  };
355 
356  template <typename... Ts>
357  struct drop_first_n<typelist<Ts...>, std::size_t(0)> {
358  using type = typelist<Ts...>;
359  };
360 
361  template <typename T, typename... Ts, std::size_t N>
362  struct drop_first_n<std::tuple<T, Ts...>, N, std::enable_if_t<N != 0>> {
363  using type = typename drop_first_n<std::tuple<Ts...>, N - 1>::type;
364  };
365 
366  template <typename T, typename... Ts, std::size_t N>
367  struct drop_first_n<typelist<T, Ts...>, N, std::enable_if_t<N != 0>> {
368  using type = typename drop_first_n<typelist<Ts...>, N - 1>::type;
369  };
370 
372  template <typename Typelist, std::size_t N>
373  struct take_first_n;
374 
375  template <typename ResultTuple, typename InputTuple, std::size_t N, typename Enabler = void>
377 
378  template <typename... Ts, typename... Us>
379  struct take_first_n_helper<std::tuple<Ts...>, std::tuple<Us...>, std::size_t(0)> {
380  using type = std::tuple<Ts...>;
381  };
382  template <typename... Ts, typename... Us>
383  struct take_first_n_helper<typelist<Ts...>, typelist<Us...>, std::size_t(0)> {
384  using type = typelist<Ts...>;
385  };
386 
387  template <typename... Ts, typename U, typename... Us, std::size_t N>
388  struct take_first_n_helper<std::tuple<Ts...>, std::tuple<U, Us...>, N, std::enable_if_t<N != 0>> {
389  using type = typename take_first_n_helper<std::tuple<Ts..., U>, std::tuple<Us...>, N - 1>::type;
390  };
391  template <typename... Ts, typename U, typename... Us, std::size_t N>
392  struct take_first_n_helper<typelist<Ts...>, typelist<U, Us...>, N, std::enable_if_t<N != 0>> {
393  using type = typename take_first_n_helper<typelist<Ts..., U>, typelist<Us...>, N - 1>::type;
394  };
395 
396  template <typename... Ts, std::size_t N>
397  struct take_first_n<std::tuple<Ts...>, N> {
398  using type = typename take_first_n_helper<std::tuple<>, std::tuple<Ts...>, N>::type;
399  };
400 
401  template <typename... Ts, std::size_t N>
402  struct take_first_n<typelist<Ts...>, N> {
403  using type = typename take_first_n_helper<typelist<>, typelist<Ts...>, N>::type;
404  };
405 
407  template <typename Typelist, std::size_t N, typename Enabler = void>
408  struct drop_last_n;
409 
410  template <typename... Ts, std::size_t N>
411  struct drop_last_n<std::tuple<Ts...>, N, std::enable_if_t<N <= sizeof...(Ts)>> {
412  using type = typename take_first_n<std::tuple<Ts...>, (sizeof...(Ts) - N)>::type;
413  };
414  template <typename... Ts, std::size_t N>
415  struct drop_last_n<typelist<Ts...>, N, std::enable_if_t<N <= sizeof...(Ts)>> {
416  using type = typename take_first_n<typelist<Ts...>, (sizeof...(Ts) - N)>::type;
417  };
418 
419  template <typename... Ts, std::size_t N>
420  struct drop_last_n<std::tuple<Ts...>, N, std::enable_if_t<!(N <= sizeof...(Ts))>> {
421  using type = std::tuple<>;
422  };
423  template <typename... Ts, std::size_t N>
424  struct drop_last_n<typelist<Ts...>, N, std::enable_if_t<!(N <= sizeof...(Ts))>> {
425  using type = typelist<>;
426  };
427 
429  template <typename T, typename Enabler = void>
430  struct decayed_typelist;
431 
432  template <typename... Ts>
433  struct decayed_typelist<std::tuple<Ts...>> {
434  using type = std::tuple<std::decay_t<Ts>...>;
435  };
436  template <typename... Ts>
437  struct decayed_typelist<typelist<Ts...>> {
438  using type = typelist<std::decay_t<Ts>...>;
439  };
440 
441  template <typename Tuple>
442  using decayed_typelist_t = typename decayed_typelist<Tuple>::type;
443 
445  template <typename T, template <typename...> typename Pred>
446  struct filter;
447 
448  template <typename FilteredTypelist, template <typename...> typename Pred, typename... ToBeFilteredTs>
449  struct filter_impl;
450 
451  template <typename... FilteredTs, template <typename...> typename Pred>
452  struct filter_impl<typelist<FilteredTs...>, Pred> {
453  using type = typelist<FilteredTs...>;
454  };
455  template <typename... FilteredTs, template <typename...> typename Pred>
456  struct filter_impl<std::tuple<FilteredTs...>, Pred> {
457  using type = std::tuple<FilteredTs...>;
458  };
459 
460  template <typename... FilteredTs, template <typename...> typename Pred, typename U, typename... RestOfUs>
461  struct filter_impl<typelist<FilteredTs...>, Pred, U, RestOfUs...>
462  : std::conditional_t<Pred<U>::value, filter_impl<typelist<FilteredTs..., U>, Pred, RestOfUs...>,
463  filter_impl<typelist<FilteredTs...>, Pred, RestOfUs...>> {};
464  template <typename... FilteredTs, template <typename...> typename Pred, typename U, typename... RestOfUs>
465  struct filter_impl<std::tuple<FilteredTs...>, Pred, U, RestOfUs...>
466  : std::conditional_t<Pred<U>::value, filter_impl<std::tuple<FilteredTs..., U>, Pred, RestOfUs...>,
467  filter_impl<std::tuple<FilteredTs...>, Pred, RestOfUs...>> {};
468 
469  template <typename... Ts, template <typename...> typename Pred>
470  struct filter<typelist<Ts...>, Pred> : filter_impl<typelist<>, Pred, Ts...> {};
471  template <typename... Ts, template <typename...> typename Pred>
472  struct filter<std::tuple<Ts...>, Pred> : filter_impl<std::tuple<>, Pred, Ts...> {};
473 
474  template <typename T, template <typename...> typename Pred>
475  using filter_t = typename filter<T, Pred>::type;
476 
477  template <typename T>
478  using drop_void = filter<T, is_nonvoid>;
479 
480  template <typename T>
481  using drop_void_t = typename drop_void<T>::type;
482 
483  template <typename T, typename S, typename U>
484  struct replace_nonvoid_helper;
485 
486  /* non-void S, replace with U */
487  template <typename... Ts, typename S, typename... Ss, typename U, typename... Us>
488  struct replace_nonvoid_helper<ttg::typelist<Ts...>, ttg::typelist<S, Ss...>, ttg::typelist<U, Us...>> {
489  using type =
490  typename replace_nonvoid_helper<ttg::typelist<Ts..., U>, ttg::typelist<Ss...>, ttg::typelist<Us...>>::type;
491  };
492 
493  /* void S, keep */
494  template <typename... Ts, typename... Ss, typename U, typename... Us>
495  struct replace_nonvoid_helper<ttg::typelist<Ts...>, ttg::typelist<void, Ss...>, ttg::typelist<U, Us...>> {
496  using type = typename replace_nonvoid_helper<ttg::typelist<Ts..., void>, ttg::typelist<Ss...>,
497  ttg::typelist<U, Us...>>::type;
498  };
499 
500  /* empty S, done */
501  template <typename... Ts, typename... Us>
502  struct replace_nonvoid_helper<ttg::typelist<Ts...>, ttg::typelist<>, ttg::typelist<Us...>> {
503  using type = ttg::typelist<Ts...>;
504  };
505 
506  /* empty U, done */
507  template <typename... Ts, typename... Ss>
508  struct replace_nonvoid_helper<ttg::typelist<Ts...>, ttg::typelist<Ss...>, ttg::typelist<>> {
509  using type = ttg::typelist<Ts..., Ss...>;
510  };
511 
512  /* empty S and U, done */
513  template <typename... Ts>
514  struct replace_nonvoid_helper<ttg::typelist<Ts...>, ttg::typelist<>, ttg::typelist<>> {
515  using type = ttg::typelist<Ts...>;
516  };
517 
518  /* Replace the first min(sizeof...(T), sizeof...(U)) non-void types in T with types in U; U does not contain void */
519  template <typename T, typename U>
520  struct replace_nonvoid;
521 
522  template <typename... T, typename... U>
523  struct replace_nonvoid<ttg::typelist<T...>, ttg::typelist<U...>> {
524  using type = typename replace_nonvoid_helper<ttg::typelist<>, ttg::typelist<T...>, ttg::typelist<U...>>::type;
525  };
526 
527  template <typename... T, typename... U>
528  struct replace_nonvoid<std::tuple<T...>, std::tuple<U...>> {
529  using type =
530  ttg::meta::typelist_to_tuple_t<typename replace_nonvoid<ttg::typelist<T...>, ttg::typelist<U...>>::type>;
531  };
532 
533  template <typename T, typename U>
534  using replace_nonvoid_t = typename replace_nonvoid<T, U>::type;
535 
537  // Tuple-element type conversions
539 
540  template <typename T>
541  struct void_to_Void_tuple;
542 
543  template <typename... Ts>
544  struct void_to_Void_tuple<std::tuple<Ts...>> {
545  using type = std::tuple<void_to_Void_t<Ts>...>;
546  };
547 
548  template <typename tupleT>
549  using void_to_Void_tuple_t = typename void_to_Void_tuple<std::decay_t<tupleT>>::type;
550 
551  template <typename T>
552  struct add_lvalue_reference_tuple;
553 
554  template <typename... Ts>
555  struct add_lvalue_reference_tuple<std::tuple<Ts...>> {
556  using type = std::tuple<std::add_lvalue_reference_t<Ts>...>;
557  };
558 
559  template <typename tupleT>
560  using add_lvalue_reference_tuple_t = typename add_lvalue_reference_tuple<tupleT>::type;
561 
562  template <typename T>
563  struct add_glvalue_reference_tuple;
564 
565  template <typename... Ts>
566  struct add_glvalue_reference_tuple<std::tuple<Ts...>> {
567  using type = std::tuple<std::conditional_t<std::is_const_v<Ts>, std::add_lvalue_reference_t<Ts>,
568  std::add_rvalue_reference_t<std::remove_const_t<Ts>>>...>;
569  };
570 
571  template <typename tupleT>
572  using add_glvalue_reference_tuple_t = typename add_glvalue_reference_tuple<tupleT>::type;
573 
574  template <typename T, typename... Ts>
575  struct none_has_reference {
576  static constexpr bool value = !std::is_reference_v<T> && none_has_reference<Ts...>::value;
577  };
578 
579  template <typename T>
580  struct none_has_reference<T> {
581  static constexpr bool value = !std::is_reference_v<T>;
582  };
583 
584  template <typename... T>
585  struct none_has_reference<ttg::typelist<T...>> : none_has_reference<T...> {};
586 
587  template <>
588  struct none_has_reference<ttg::typelist<>> : std::true_type {};
589 
590  template <typename... T>
591  constexpr bool none_has_reference_v = none_has_reference<T...>::value;
592 
593  template <typename T>
594  struct is_tuple : std::integral_constant<bool, false> {};
595 
596  template <typename... Ts>
597  struct is_tuple<std::tuple<Ts...>> : std::integral_constant<bool, true> {};
598 
599  template <typename T>
600  constexpr bool is_tuple_v = is_tuple<T>::value;
601 
602  template <typename>
603  struct is_span : std::false_type {};
604 
605  template <typename T, std::size_t S>
606  struct is_span<ttg::span<T, S>> : std::true_type {};
607 
608  template <typename T>
609  constexpr bool is_span_v = is_span<T>::value;
610 
611  template <template <class> class Pred, typename TupleT, std::size_t I, std::size_t... Is>
612  struct predicate_index_seq_helper;
613 
614  template <template <class> class Pred, typename T, typename... Ts, std::size_t I, std::size_t... Is>
615  struct predicate_index_seq_helper<Pred, std::tuple<T, Ts...>, I, Is...> {
616  using seq = std::conditional_t<Pred<T>::value,
617  typename predicate_index_seq_helper<Pred, std::tuple<Ts...>, I + 1, Is..., I>::seq,
618  typename predicate_index_seq_helper<Pred, std::tuple<Ts...>, I + 1, Is...>::seq>;
619  };
620 
621  template <template <class> class Pred, std::size_t I, std::size_t... Is>
622  struct predicate_index_seq_helper<Pred, std::tuple<>, I, Is...> {
623  using seq = std::index_sequence<Is...>;
624  };
625 
626  template <typename T>
627  struct is_none_void_pred : std::integral_constant<bool, is_none_void_v<T>> {};
628 
632  template <typename TupleT>
633  using nonvoid_index_seq = typename predicate_index_seq_helper<is_none_void_pred, TupleT, 0>::seq;
634 
635  template <typename T>
636  struct is_void_pred : std::integral_constant<bool, is_void_v<T>> {};
637 
641  template <typename TupleT>
642  using void_index_seq = typename predicate_index_seq_helper<is_void_pred, TupleT, 0>::seq;
643 
645  // is_empty_tuple
647 
648  // true if tuple is empty or contains only Void types, e.g. is_empty_tuple<std::tuple<>> or
649  // is_empty_tuple<std::tuple<Void>> evaluate to true
650  template <typename T, typename Enabler = void>
651  struct is_empty_tuple : std::false_type {};
652 
653  template <typename... Ts>
654  struct is_empty_tuple<std::tuple<Ts...>, std::enable_if_t<(is_Void_v<Ts> && ...)>> : std::true_type {};
655 
656  template <typename Tuple>
657  inline constexpr bool is_empty_tuple_v = is_empty_tuple<Tuple>::value;
658 
659  static_assert(!is_empty_tuple_v<std::tuple<int>>, "ouch");
660  static_assert(is_empty_tuple_v<std::tuple<>>, "ouch");
661  static_assert(is_empty_tuple_v<std::tuple<Void>>, "ouch");
662  static_assert(is_empty_tuple_v<std::tuple<Void, Void, Void>>, "ouch");
663 
665  // nonesuch struct from Library Fundamentals V2, source from https://en.cppreference.com/w/cpp/experimental/nonesuch
667 
668  struct nonesuch {
669  ~nonesuch() = delete;
670  nonesuch(nonesuch const &) = delete;
671  void operator=(nonesuch const &) = delete;
672  };
673 
675  // is_detected family from Library Fundamentals V2, source from
676  // https://en.cppreference.com/w/cpp/experimental/is_detected
678 
679  namespace detail {
680 
681  template <class Default, class Enabler, template <class...> class TT, class... Args>
682  struct detector {
683  using value_t = std::false_type;
684  using type = Default;
685  };
686 
687  template <class Default, template <class...> class TT, class... Args>
688  struct detector<Default, void_t<TT<Args...>>, TT, Args...> {
689  using value_t = std::true_type;
690  using type = TT<Args...>;
691  };
692 
693  } // namespace detail
694 
695  template <template <class...> class TT, class... Args>
696  using is_detected = typename detail::detector<nonesuch, void, TT, Args...>::value_t;
697 
698  template <template <class...> class TT, class... Args>
699  using detected_t = typename detail::detector<nonesuch, void, TT, Args...>::type;
700 
701  template <class Default, template <class...> class TT, class... Args>
702  using detected_or = detail::detector<Default, void, TT, Args...>;
703 
704  template <template <class...> class TT, class... Args>
705  constexpr bool is_detected_v = is_detected<TT, Args...>::value;
706 
707  template <class Default, template <class...> class TT, class... Args>
708  using detected_or_t = typename detected_or<Default, TT, Args...>::type;
709 
710  template <class Expected, template <class...> class TT, class... Args>
711  using is_detected_exact = std::is_same<Expected, detected_t<TT, Args...>>;
712 
713  template <class Expected, template <class...> class TT, class... Args>
714  constexpr bool is_detected_exact_v = is_detected_exact<Expected, TT, Args...>::value;
715 
716  template <class To, template <class...> class TT, class... Args>
717  using is_detected_convertible = std::is_convertible<detected_t<TT, Args...>, To>;
718 
719  template <class To, template <class...> class TT, class... Args>
720  constexpr bool is_detected_convertible_v = is_detected_convertible<To, TT, Args...>::value;
721 
723  // type_printer useful to print types in metaprograms
725 
726  template <typename T>
727  struct type_printer;
728 
730  // has_std_hash_specialization_v<T> evaluates to true if std::hash<T> is defined
732  template <typename T, typename Enabler = void>
733  struct has_std_hash_specialization : std::false_type {};
734  template <typename T>
735  struct has_std_hash_specialization<
736  T, ttg::meta::void_t<decltype(std::declval<std::hash<T>>()(std::declval<const T &>()))>> : std::true_type {};
737  template <typename T>
738  constexpr bool has_std_hash_specialization_v = has_std_hash_specialization<T>::value;
739 
740  namespace detail {
741 
743  // send_callback_t<key,value> = std::function<void(const key&, const value&>, protected against void key or value
745  template <typename Key, typename Value, typename Enabler = void>
746  struct send_callback;
747  template <typename Key, typename Value>
748  struct send_callback<Key, Value, std::enable_if_t<!is_void_v<Key> && !is_void_v<Value>>> {
749  using type = std::function<void(const Key &, const Value &)>;
750  };
751  template <typename Key, typename Value>
752  struct send_callback<Key, Value, std::enable_if_t<!is_void_v<Key> && is_void_v<Value>>> {
753  using type = std::function<void(const Key &)>;
754  };
755  template <typename Key, typename Value>
756  struct send_callback<Key, Value, std::enable_if_t<is_void_v<Key> && !is_void_v<Value>>> {
757  using type = std::function<void(const Value &)>;
758  };
759  template <typename Key, typename Value>
760  struct send_callback<Key, Value, std::enable_if_t<is_void_v<Key> && is_void_v<Value>>> {
761  using type = std::function<void()>;
762  };
763  template <typename Key, typename Value>
764  using send_callback_t = typename send_callback<Key, Value>::type;
765 
767  // move_callback_t<key,value> = std::function<void(const key&, value&&>, protected against void key or value
769  template <typename Key, typename Value, typename Enabler = void>
770  struct move_callback;
771  template <typename Key, typename Value>
772  struct move_callback<Key, Value, std::enable_if_t<!is_void_v<Key> && !is_void_v<Value>>> {
773  using type = std::function<void(const Key &, Value &&)>;
774  };
775  template <typename Key, typename Value>
776  struct move_callback<Key, Value, std::enable_if_t<!is_void_v<Key> && is_void_v<Value>>> {
777  using type = std::function<void(const Key &)>;
778  };
779  template <typename Key, typename Value>
780  struct move_callback<Key, Value, std::enable_if_t<is_void_v<Key> && !is_void_v<Value>>> {
781  using type = std::function<void(Value &&)>;
782  };
783  template <typename Key, typename Value>
784  struct move_callback<Key, Value, std::enable_if_t<is_void_v<Key> && is_void_v<Value>>> {
785  using type = std::function<void()>;
786  };
787  template <typename Key, typename Value>
788  using move_callback_t = typename move_callback<Key, Value>::type;
789 
791  // broadcast_callback_t<key,value> = std::function<void(const key&, value&&>, protected against void key or value
793  template <typename Key, typename Value, typename Enabler = void>
794  struct broadcast_callback;
795  template <typename Key, typename Value>
796  struct broadcast_callback<Key, Value, std::enable_if_t<!is_void_v<Key> && !is_void_v<Value>>> {
797  using type = std::function<void(const ttg::span<const Key> &, const Value &)>;
798  };
799  template <typename Key, typename Value>
800  struct broadcast_callback<Key, Value, std::enable_if_t<!is_void_v<Key> && is_void_v<Value>>> {
801  using type = std::function<void(const ttg::span<const Key> &)>;
802  };
803  template <typename Key, typename Value>
804  struct broadcast_callback<Key, Value, std::enable_if_t<is_void_v<Key> && !is_void_v<Value>>> {
805  using type = std::function<void(const Value &)>;
806  };
807  template <typename Key, typename Value>
808  struct broadcast_callback<Key, Value, std::enable_if_t<is_void_v<Key> && is_void_v<Value>>> {
809  using type = std::function<void()>;
810  };
811  template <typename Key, typename Value>
812  using broadcast_callback_t = typename broadcast_callback<Key, Value>::type;
813 
814 
815 
817  // setsize_callback_t<key> = std::function<void(const keyT &, std::size_t)> protected against void key
819  template <typename Key, typename Enabler = void>
820  struct setsize_callback;
821  template <typename Key>
822  struct setsize_callback<Key, std::enable_if_t<!is_void_v<Key>>> {
823  using type = std::function<void(const Key &, std::size_t)>;
824  };
825  template <typename Key>
826  struct setsize_callback<Key, std::enable_if_t<is_void_v<Key>>> {
827  using type = std::function<void(std::size_t)>;
828  };
829  template <typename Key>
830  using setsize_callback_t = typename setsize_callback<Key>::type;
831 
833  // finalize_callback_t<key> = std::function<void(const keyT &)> protected against void key
835  template <typename Key, typename Enabler = void>
836  struct finalize_callback;
837  template <typename Key>
838  struct finalize_callback<Key, std::enable_if_t<!is_void_v<Key>>> {
839  using type = std::function<void(const Key &)>;
840  };
841  template <typename Key>
842  struct finalize_callback<Key, std::enable_if_t<is_void_v<Key>>> {
843  using type = std::function<void()>;
844  };
845  template <typename Key>
846  using finalize_callback_t = typename finalize_callback<Key>::type;
847 
849  // keymap_t<key,value> = std::function<int(const key&>, protected against void key
851  template <typename Key, typename Return, typename Enabler = void>
852  struct keymap;
853  template <typename Key, typename Return>
854  struct keymap<Key, Return, std::enable_if_t<!is_void_v<Key>>> {
855  using type = std::function<Return(const Key &)>;
856  };
857  template <typename Key, typename Return>
858  struct keymap<Key, Return, std::enable_if_t<is_void_v<Key>>> {
859  using type = std::function<Return()>;
860  };
861  template <typename Key, typename Return = int>
862  using keymap_t = typename keymap<Key, Return>::type;
863 
865  // input_reducers_t<valueTs...> = std::tuple<
866  // std::function<std::decay_t<input_valueTs>(std::decay_t<input_valueTs> &&, std::decay_t<input_valueTs>
867  // &&)>...>
868  // protected against void valueTs
870  template <typename T, typename Enabler = void>
871  struct input_reducer_type;
872  template <typename T>
873  struct input_reducer_type<T, std::enable_if_t<!is_void_v<T>>> {
874  using type = std::function<void(std::decay_t<T> &, const std::decay_t<T> &)>;
875  };
876  template <typename T>
877  struct input_reducer_type<T, std::enable_if_t<is_void_v<T>>> {
878  using type = std::function<void()>;
879  };
880  template <typename... valueTs>
881  struct input_reducers {
882  using type = std::tuple<typename input_reducer_type<valueTs>::type...>;
883  };
884  template <typename... valueTs>
885  struct input_reducers<std::tuple<valueTs...>> {
886  using type = std::tuple<typename input_reducer_type<valueTs>::type...>;
887  };
888  template <typename... valueTs>
889  using input_reducers_t = typename input_reducers<valueTs...>::type;
890 
892  // prepare_send_callback_t<Key, Value> = std::function<int(const ttg::span<Key> &, const Value &)> protected against void key
894  template <typename Key, typename Value, typename Enabler = void>
895  struct prepare_send_callback;
896  template <typename Key, typename Value>
897  struct prepare_send_callback<Key, Value, std::enable_if_t<!is_void_v<Key> && !is_void_v<Value>>> {
898  using type = std::function<void(const ttg::span<const Key> &, const Value &)>;
899  };
900  template <typename Key, typename Value>
901  struct prepare_send_callback<Key, Value, std::enable_if_t<!is_void_v<Key> && is_void_v<Value>>> {
902  using type = std::function<void(const ttg::span<const Key> &)>;
903  };
904  template <typename Key, typename Value>
905  struct prepare_send_callback<Key, Value, std::enable_if_t<is_void_v<Key> && !is_void_v<Value>>> {
906  using type = std::function<void(const Value &)>;
907  };
908  template <typename Key, typename Value>
909  struct prepare_send_callback<Key, Value, std::enable_if_t<is_void_v<Key> && is_void_v<Value>>> {
910  using type = std::function<void()>;
911  };
912  template <typename Key, typename Value>
913  using prepare_send_callback_t = typename prepare_send_callback<Key, Value>::type;
914 
915 
916  } // namespace detail
917 
919  // check whether a type is iterable
920  // Taken from https://en.cppreference.com/w/cpp/types/void_t
922  template <typename T, typename = void>
923  struct is_iterable : std::false_type {};
924 
925  // this gets used only when we can call std::begin() and std::end() on that type
926  template <typename T>
927  struct is_iterable<T, std::void_t<decltype(std::begin(std::declval<T>())), decltype(std::end(std::declval<T>()))>>
928  : std::true_type {};
929 
930  template <typename T>
931  constexpr bool is_iterable_v = is_iterable<T>::value;
932 
934  // check whether a Callable is invocable with the arguments given as a typelist
936  template <typename Callable, typename Typelist>
937  constexpr bool is_invocable_typelist_v = false;
938  template <typename Callable, typename... Args>
939  constexpr bool is_invocable_typelist_v<Callable, ttg::typelist<Args...>> = std::is_invocable_v<Callable, Args...>;
940  template <typename ReturnType, typename Callable, typename Typelist>
941  constexpr bool is_invocable_typelist_r_v = false;
942  template <typename ReturnType, typename Callable, typename... Args>
943  constexpr bool is_invocable_typelist_r_v<ReturnType, Callable, ttg::typelist<Args...>> =
944  std::is_invocable_r_v<ReturnType, Callable, Args...>;
945 
947  // detects the return result of a Callable when invoked with the arguments given as a typelist
949  template <typename Callable, typename Typelist>
950  struct invoke_result_typelist {};
951  template <typename Callable, typename... Args>
952  struct invoke_result_typelist<Callable, ttg::typelist<Args...>> : std::invoke_result<Callable, Args...> {};
953  template <class F, class... ArgTypes>
954  using invoke_result_typelist_t = typename invoke_result_typelist<F, ArgTypes...>::type;
955 
956  } // namespace meta
957 } // namespace ttg
958 
959 #endif // TTG_UTIL_META_H
A complete version of void.
Definition: void.h:11
constexpr BOOST_CLBL_TRAITS_INLINE_VAR bool is_invocable_r_v
constexpr BOOST_CLBL_TRAITS_INLINE_VAR bool is_invocable_v
constexpr bool is_none_Void_v
Definition: meta.h:251
typename void_to_Void< T >::type void_to_Void_t
Definition: meta.h:271
constexpr bool is_Void_v
Definition: meta.h:206
constexpr bool is_any_nonconst_lvalue_reference_v
Definition: meta.h:288
constexpr bool probe_last_v
Definition: meta.h:120
constexpr bool is_any_void_v
Definition: meta.h:233
constexpr bool probe_any_v
Definition: meta.h:172
constexpr bool probe_all_v
Definition: meta.h:194
constexpr bool is_all_Void_v
Definition: meta.h:227
void void_t
Definition: meta.h:23
typename nonref_tuple< Tuple >::type nonref_tuple_t
Definition: meta.h:43
constexpr bool is_any_Void_v
Definition: meta.h:239
constexpr bool is_devicescratch_v
Definition: meta.h:340
std::remove_cv_t< std::remove_reference_t< T > > remove_cvr_t
Definition: meta.h:27
constexpr bool is_last_void_v
Definition: meta.h:260
constexpr bool is_nonconst_lvalue_reference_v
Definition: meta.h:281
constexpr bool is_const_lvalue_reference_v
Definition: meta.h:274
constexpr bool probe_first_v
Definition: meta.h:150
constexpr bool is_buffer_v
Definition: meta.h:325
constexpr bool is_ptr_v
Definition: meta.h:310
typename filtered_tuple< Tuple, Pred >::type filtered_tuple_t
Definition: meta.h:87
constexpr bool is_nonvoid_v
Definition: meta.h:215
typename tuple_concat< TupleTs... >::type tuple_concat_t
Definition: meta.h:60
constexpr bool is_none_void_v
Definition: meta.h:245
typename typelist_to_tuple< T >::type typelist_to_tuple_t
Definition: typelist.h:52
constexpr bool is_all_void_v
Definition: meta.h:221
constexpr bool is_void_v
Definition: meta.h:209
top-level TTG namespace contains runtime-neutral functionality
Definition: keymap.h:8
meta::typelist< Ts... > typelist
Definition: typelist.h:81
std::tuple< E > type
Definition: meta.h:70
typename drop_first_n< std::tuple< Ts... >, N - 1 >::type type
Definition: meta.h:363
typename drop_first_n< typelist< Ts... >, N - 1 >::type type
Definition: meta.h:368
drops N elements from the front
Definition: meta.h:349
drops N trailing elements from a typelist
Definition: meta.h:408
decltype(std::tuple_cat(std::declval< typename detail::keep_or_drop< Pred< Es >::value >::template type< Es > >()...)) type
Definition: meta.h:83
std::tuple< typename std::remove_reference< Ts >::type... > type
Definition: meta.h:39
typename take_first_n_helper< std::tuple<>, std::tuple< Ts... >, N >::type type
Definition: meta.h:398
typename take_first_n_helper< typelist<>, typelist< Ts... >, N >::type type
Definition: meta.h:403
typename take_first_n_helper< std::tuple< Ts..., U >, std::tuple< Us... >, N - 1 >::type type
Definition: meta.h:389
typename take_first_n_helper< typelist< Ts..., U >, typelist< Us... >, N - 1 >::type type
Definition: meta.h:393
take first N elements of a type list
Definition: meta.h:373
typename tuple_concat< decltype(std::tuple_cat(std::declval< std::tuple< Ts... > >(), std::declval< std::tuple< Us... > >())), R... >::type type
Definition: meta.h:56
A container for types.
Definition: typelist.h:24