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