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