Actual source code: functional.hpp

      1: #pragma once

      3: #include <petsc/private/cpp/macros.hpp>
      4: #include <petsc/private/cpp/utility.hpp>
      5: #include <petsc/private/cpp/type_traits.hpp>
      6: #include <petsc/private/cpp/tuple.hpp>

      8: #include <functional>

     10: namespace Petsc
     11: {

     13: namespace util
     14: {

     16: namespace detail
     17: {

     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);

     23:   template <typename F, typename... A>
     24:   static std::false_type f(...);
     25: };

     27: // generic template
     28: template <typename T>
     29: struct func_traits_impl : func_traits_impl<decltype(&T::operator())> { };

     31: // function pointers
     32: template <typename Ret, typename... Args>
     33: struct func_traits_impl<Ret (*)(Args...)> {
     34:   using result_type = Ret;

     36:   template <std::size_t ix>
     37:   struct arg {
     38:     using type = util::tuple_element_t<ix, std::tuple<Args...>>;
     39:   };
     40: };

     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;

     47:   template <std::size_t ix>
     48:   struct arg {
     49:     using type = util::tuple_element_t<ix, std::tuple<Args...>>;
     50:   };
     51: };

     53: template <typename C, typename Ret, typename... Args>
     54: struct func_traits_impl<Ret (C::*)(Args...)> {
     55:   using result_type = Ret;

     57:   template <std::size_t ix>
     58:   struct arg {
     59:     using type = util::tuple_element_t<ix, std::tuple<Args...>>;
     60:   };
     61: };

     63: } // namespace detail

     65: template <typename F, typename... A>
     66: struct can_call : decltype(detail::can_call_test::f<F, A...>(0)) { };

     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: }

     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: };

     80: } // namespace util

     82: } // namespace Petsc

     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:   }

     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))

    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)>{}))

    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)

    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)