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