xref: /petsc/include/petsc/private/cpp/functional.hpp (revision 9dd11ecf0918283bb567d8b33a92f53ac4ea7840)
1 #pragma once
2 
3 #include <petsc/private/cpp/macros.hpp>
4 #include <petsc/private/cpp/utility.hpp>     // index_sequence
5 #include <petsc/private/cpp/type_traits.hpp> // decay_t
6 #include <petsc/private/cpp/tuple.hpp>       // tuple_element_t
7 
8 #include <functional>
9 
10 namespace Petsc
11 {
12 
13 namespace util
14 {
15 
16 namespace detail
17 {
18 
19 struct can_call_test {
20   template <typename F, typename... A>
21   static decltype(std::declval<F>()(std::declval<A>()...), std::true_type()) f(int);
22 
23   template <typename F, typename... A>
24   static std::false_type f(...);
25 };
26 
27 // generic template
28 template <typename T>
29 struct func_traits_impl : func_traits_impl<decltype(&T::operator())> { };
30 
31 // function pointers
32 template <typename Ret, typename... Args>
33 struct func_traits_impl<Ret (*)(Args...)> {
34   using result_type = Ret;
35 
36   template <std::size_t ix>
37   struct arg {
38     using type = util::tuple_element_t<ix, std::tuple<Args...>>;
39   };
40 };
41 
42 // class-like operator()
43 template <typename C, typename Ret, typename... Args>
44 struct func_traits_impl<Ret (C::*)(Args...) const> {
45   using result_type = Ret;
46 
47   template <std::size_t ix>
48   struct arg {
49     using type = util::tuple_element_t<ix, std::tuple<Args...>>;
50   };
51 };
52 
53 template <typename C, typename Ret, typename... Args>
54 struct func_traits_impl<Ret (C::*)(Args...)> {
55   using result_type = Ret;
56 
57   template <std::size_t ix>
58   struct arg {
59     using type = util::tuple_element_t<ix, std::tuple<Args...>>;
60   };
61 };
62 
63 } // namespace detail
64 
65 template <typename F, typename... A>
66 struct can_call : decltype(detail::can_call_test::f<F, A...>(0)) { };
67 
68 template <typename... A, typename F>
is_callable_with(F &&)69 inline constexpr can_call<F, A...> is_callable_with(F &&) noexcept
70 {
71   return can_call<F, A...>{};
72 }
73 
74 template <typename T>
75 struct func_traits : detail::func_traits_impl<decay_t<T>> {
76   template <std::size_t idx>
77   using arg_t = typename detail::func_traits_impl<decay_t<T>>::template arg<idx>::type;
78 };
79 
80 } // namespace util
81 
82 } // namespace Petsc
83 
84 #define PETSC_ALIAS_FUNCTION_WITH_PROLOGUE_AND_EPILOGUE_(alias, original, prologue, epilogue) \
85   template <typename... Args> \
86   PETSC_NODISCARD auto alias(Args &&...args) PETSC_DECLTYPE_NOEXCEPT_AUTO(original(std::forward<Args>(args)...)) \
87   { \
88     prologue; \
89     auto ret = original(std::forward<Args>(args)...); \
90     epilogue; \
91     return ret; \
92   }
93 
94 // PETSC_ALIAS_FUNCTION() - Alias a function
95 //
96 // input params:
97 // alias    - the new name for the function
98 // original - the name of the function you would like to alias
99 //
100 // notes:
101 // Using this macro in effect creates
102 //
103 // template <typename... T>
104 // auto alias(T&&... args)
105 // {
106 //   return original(std::forward<T>(args)...);
107 // }
108 //
109 // meaning it will transparently work for any kind of alias (including overloads).
110 //
111 // example usage:
112 // PETSC_ALIAS_FUNCTION(bar,foo);
113 #define PETSC_ALIAS_FUNCTION(alias, original) PETSC_ALIAS_FUNCTION_WITH_PROLOGUE_AND_EPILOGUE_(alias, original, ((void)0), ((void)0))
114 
115 // Similar to PETSC_ALIAS_FUNCTION() this macro creates a thin wrapper which passes all
116 // arguments to the target function ~except~ the last N arguments. So
117 //
118 // PETSC_ALIAS_FUNCTION_GOBBLE_NTH_ARGS(bar,foo,3);
119 //
120 // creates a function with the effect of
121 //
122 // returnType bar(argType1 arg1, argType2 arg2, ..., argTypeN argN)
123 // {
124 //   IGNORE(argN);
125 //   IGNORE(argN-1);
126 //   IGNORE(argN-2);
127 //   return foo(arg1,arg2,...,argN-3);
128 // }
129 //
130 // for you.
131 #define PETSC_ALIAS_FUNCTION_GOBBLE_NTH_LAST_ARGS_(alias, original, gobblefn, N) \
132   static_assert(std::is_integral<decltype(N)>::value && ((N) >= 0), ""); \
133   template <typename TupleT, std::size_t... idx> \
134   static inline auto gobblefn(TupleT &&tuple, Petsc::util::index_sequence<idx...>) PETSC_DECLTYPE_NOEXCEPT_AUTO_RETURNS(original(std::get<idx>(tuple)...)) \
135   template <typename... Args> \
136   PETSC_NODISCARD auto alias(Args &&...args) PETSC_DECLTYPE_NOEXCEPT_AUTO_RETURNS(gobblefn(std::forward_as_tuple(args...), Petsc::util::make_index_sequence<sizeof...(Args) - (N)>{}))
137 
138 // makes prefix_lineno_name
139 #define PETSC_ALIAS_UNIQUE_NAME_INTERNAL_(a, b, c, d, e) a##b##c##d##e
140 #define PETSC_ALIAS_UNIQUE_NAME_INTERNAL(prefix, name)   PETSC_ALIAS_UNIQUE_NAME_INTERNAL_(prefix, _, __LINE__, _, name)
141 
142 #define PETSC_ALIAS_FUNCTION_GOBBLE_NTH_LAST_ARGS(alias, original, N) PETSC_ALIAS_FUNCTION_GOBBLE_NTH_LAST_ARGS_(alias, original, PETSC_ALIAS_UNIQUE_NAME_INTERNAL(PetscAliasFunctionGobbleDispatch, original), N)
143