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, prologue, epilogue) \ 87 template <typename... Args> \ 88 PETSC_NODISCARD auto alias(Args &&...args) PETSC_DECLTYPE_NOEXCEPT_AUTO(original(std::forward<Args>(args)...)) \ 89 { \ 90 prologue; \ 91 auto ret = original(std::forward<Args>(args)...); \ 92 epilogue; \ 93 return ret; \ 94 } 95 96 // PETSC_ALIAS_FUNCTION() - Alias a function 97 // 98 // input params: 99 // alias - the new name for the function 100 // original - the name of the function you would like to alias 101 // 102 // notes: 103 // Using this macro in effect creates 104 // 105 // template <typename... T> 106 // auto alias(T&&... args) 107 // { 108 // return original(std::forward<T>(args)...); 109 // } 110 // 111 // meaning it will transparently work for any kind of alias (including overloads). 112 // 113 // example usage: 114 // PETSC_ALIAS_FUNCTION(bar,foo); 115 #define PETSC_ALIAS_FUNCTION(alias, original) PETSC_ALIAS_FUNCTION_WITH_PROLOGUE_AND_EPILOGUE_(alias, original, ((void)0), ((void)0)) 116 117 // Similar to PETSC_ALIAS_FUNCTION() this macro creates a thin wrapper which passes all 118 // arguments to the target function ~except~ the last N arguments. So 119 // 120 // PETSC_ALIAS_FUNCTION_GOBBLE_NTH_ARGS(bar,foo,3); 121 // 122 // creates a function with the effect of 123 // 124 // returnType bar(argType1 arg1, argType2 arg2, ..., argTypeN argN) 125 // { 126 // IGNORE(argN); 127 // IGNORE(argN-1); 128 // IGNORE(argN-2); 129 // return foo(arg1,arg2,...,argN-3); 130 // } 131 // 132 // for you. 133 #define PETSC_ALIAS_FUNCTION_GOBBLE_NTH_LAST_ARGS_(alias, original, gobblefn, N) \ 134 static_assert(std::is_integral<decltype(N)>::value && ((N) >= 0), ""); \ 135 template <typename TupleT, std::size_t... idx> \ 136 static inline auto gobblefn(TupleT &&tuple, Petsc::util::index_sequence<idx...>) PETSC_DECLTYPE_NOEXCEPT_AUTO_RETURNS(original(std::get<idx>(tuple)...)) \ 137 template <typename... Args> \ 138 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)>{})) 139 140 // makes prefix_lineno_name 141 #define PETSC_ALIAS_UNIQUE_NAME_INTERNAL_(a, b, c, d, e) a##b##c##d##e 142 #define PETSC_ALIAS_UNIQUE_NAME_INTERNAL(prefix, name) PETSC_ALIAS_UNIQUE_NAME_INTERNAL_(prefix, _, __LINE__, _, name) 143 144 #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) 145 146 #endif // __cplusplus 147 148 #endif // PETSC_CPP_FUNCTIONAL_HPP 149