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