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