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