diff options
Diffstat (limited to 'src/lib/netlist/plib/ppmf.h')
-rw-r--r-- | src/lib/netlist/plib/ppmf.h | 568 |
1 files changed, 295 insertions, 273 deletions
diff --git a/src/lib/netlist/plib/ppmf.h b/src/lib/netlist/plib/ppmf.h index 25e88a22eec..982ef573e70 100644 --- a/src/lib/netlist/plib/ppmf.h +++ b/src/lib/netlist/plib/ppmf.h @@ -8,7 +8,7 @@ /// \file ppmf.h /// /// -/// PMF_TYPE_GNUC_PMF +/// PMF_TYPE_PMF /// Use standard pointer to member function syntax C++11 /// /// PMF_TYPE_GNUC_PMF_CONV @@ -16,20 +16,16 @@ /// This is not standard compliant and needs /// -Wno-pmf-conversions to compile. /// -/// PMF_TYPE_INTERNAL +/// PMF_TYPE_INTERNAL_* /// Use the same approach as MAME for deriving the function pointer. /// This is compiler-dependent as well /// -/// Benchmarks for ./nltool -c run -f src/mame/machine/nl_pong.cpp -t 10 -n pong_fast +/// Benchmarks for ./nltool -c run -t 10 -n pongf src/mame/machine/nl_pongf.cpp /// -/// PMF_TYPE_INTERNAL: 215% 215% -/// PMF_TYPE_GNUC_PMF: 163% 196% -/// PMF_TYPE_GNUC_PMF_CONV: 215% 215% +/// PMF_TYPE_INTERNAL: 215% 215% 564% 580% +/// PMF_TYPE_GNUC_PMF: 163% 196% 516% 490% +/// PMF_TYPE_GNUC_PMF_CONV: 215% 215% 560% 575% /// -/// The whole exercise was done to avoid virtual calls. In prior versions of -/// netlist, the INTERNAL and GNUC_PMF_CONV approach provided significant improvement. -/// Since than, "hot" was removed from functions declared as virtual. -/// This may explain that the recent benchmarks show no difference at all. /// #include "pconfig.h" @@ -37,67 +33,29 @@ #include <algorithm> #include <cstdint> // uintptr_t +#include <type_traits> #include <utility> //============================================================ // Macro magic //============================================================ -//#define PPMF_TYPE 2 - -#define PPMF_TYPE_PMF 0 -#define PPMF_TYPE_GNUC_PMF_CONV 1 -#define PPMF_TYPE_INTERNAL 2 - -// FIXME: Remove this macro madmess latest after September, 2020 -// FIXME: Do we still need to support MINGW <= 4.6? - -#if defined(__clang__) && defined(__i386__) && defined(_WIN32) - #define PHAS_PMF_INTERNAL 0 -#elif defined(__GNUC__) || defined(__clang__) - // does not work in versions over 4.7.x of 32bit MINGW - #if defined(__MINGW32__) && !defined(__x86_64) && defined(__i386__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7))) - #define PHAS_PMF_INTERNAL 0 - #elif defined(__MINGW32__) && !defined(__x86_64) && defined(__i386__) - #define PHAS_PMF_INTERNAL 1 - #define MEMBER_ABI _thiscall - #elif defined(__arm__) || defined(__ARMEL__) || defined(__aarch64__) || defined(__MIPSEL__) || defined(__mips_isa_rev) || defined(__mips64) || defined(__EMSCRIPTEN__) - #define PHAS_PMF_INTERNAL 2 - #else - #define PHAS_PMF_INTERNAL 1 - #endif -#elif defined(_MSC_VER) && defined (_M_X64) - #define PHAS_PMF_INTERNAL 3 -#else - #define PHAS_PMF_INTERNAL 0 -#endif - -#ifndef MEMBER_ABI - #define MEMBER_ABI -#endif +//#define PPMF_FORCE_TYPE 0 -#ifndef PPMF_TYPE - #if (PHAS_PMF_INTERNAL > 0) - #define PPMF_TYPE PPMF_TYPE_INTERNAL - #else - #define PPMF_TYPE PPMF_TYPE_PMF - #endif -#else - #if (PPMF_TYPE == PPMF_TYPE_INTERNAL) - #if (PHAS_PMF_INTERNAL == 0) - #error "Internal type not supported" - #endif - #else - #undef PHAS_PMF_INTERNAL - #define PHAS_PMF_INTERNAL 0 - #undef MEMBER_ABI - #define MEMBER_ABI - #endif -#endif +#define PPMF_TYPE_PMF 0 +#define PPMF_TYPE_GNUC_PMF_CONV 1 +#define PPMF_TYPE_INTERNAL_ITANIUM 2 +#define PPMF_TYPE_INTERNAL_ARM 3 +#define PPMF_TYPE_INTERNAL_MSC 4 #if defined(__GNUC__) && !defined(__clang__) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wpmf-conversions" +#pragma GCC diagnostic ignored "-Wpedantic" +#endif + +#ifndef PPMF_FORCE_TYPE +#define PPMF_FORCE_TYPE -1 #endif namespace plib { @@ -106,28 +64,34 @@ namespace plib { { using ci = compile_info; enum { value = + (PPMF_FORCE_TYPE >= 0) ? PPMF_FORCE_TYPE : (ci::type() == ci_compiler::CLANG && !ci::m64() - && ci::os() == ci_os::WINDOWS) ? 0 : - (ci::mingw() && !ci::m64() && ci::version() >= 407) ? 0 : - (ci::mingw() && !ci::m64()) ? 1 : + && ci::os() == ci_os::WINDOWS) ? PPMF_TYPE_PMF : + (ci::mingw() && !ci::m64() && ci::version() >= 407) ? PPMF_TYPE_PMF : + (ci::mingw() && !ci::m64()) ? PPMF_TYPE_PMF : // Dropped support for mingw32 < 407 PPMF_TYPE_INTERNAL_ITANIUM : ((ci::type() == ci_compiler::CLANG || ci::type() == ci_compiler::GCC) && (ci::arch() == ci_arch::MIPS || ci::arch() == ci_arch::ARM - || ci::os() == ci_os::EMSCRIPTEN)) ? 2 : - (ci::type() == ci_compiler::CLANG || ci::type() == ci_compiler::GCC) ? 1 : - (ci::type() == ci_compiler::MSC && ci::m64()) ? 3 : - 0 + || ci::os() == ci_os::EMSCRIPTEN)) ? PPMF_TYPE_INTERNAL_ARM : + (ci::type() == ci_compiler::MSC && ci::m64()) ? PPMF_TYPE_INTERNAL_MSC : + (ci::type() == ci_compiler::CLANG || ci::type() == ci_compiler::GCC) ? PPMF_TYPE_INTERNAL_ITANIUM : + PPMF_TYPE_PMF }; }; - // FIXME: on supported platforms we should consider using GNU PMF extensions - // if no internal solution exists + static_assert(!(compile_info::type() == ci_compiler::CLANG && (PPMF_FORCE_TYPE) == (PPMF_TYPE_GNUC_PMF_CONV)), "clang does not support PPMF_TYPE_GNUC_PMF_CONV"); + static_assert(!(compile_info::type() == ci_compiler::NVCC && (PPMF_FORCE_TYPE) == (PPMF_TYPE_GNUC_PMF_CONV)), "nvcc does not support PPMF_TYPE_GNUC_PMF_CONV"); - using ppmf_type = std::integral_constant<int, (ppmf_internal::value > 0 ? PPMF_TYPE_INTERNAL : PPMF_TYPE_PMF)>; + template<typename R, typename... Targs> + struct mfp_traits + { + template<typename C> using specific_member_function = R (C::*)(Targs...); + template<typename C> using const_specific_member_function = R (C::*)(Targs...) const; + template<typename C> using member_static_ref = R (*)(C &, Targs...); + template<typename C> using member_static_ptr = R (*)(C *, Targs...); + }; - // check against previous implementation - static_assert(ppmf_internal::value == PHAS_PMF_INTERNAL, "internal mismatch"); - static_assert(ppmf_type::value == PPMF_TYPE, "type mismatch"); + class mfp_generic_class; /// /// \brief Used to derive a pointer to a member function. @@ -135,16 +99,18 @@ namespace plib { /// The following class was derived from the MAME delegate.h code. /// template <int PMFINTERNAL> - class mfp_raw + class mfp_raw; + + template <> + class mfp_raw<PPMF_TYPE_INTERNAL_ITANIUM> { public: // construct from any member function pointer - class generic_class; using generic_function = void (*)(); template<typename MemberFunctionType> mfp_raw(MemberFunctionType mftp) - : m_function(0), m_this_delta(0), m_dummy1(0), m_dummy2(0), m_size(sizeof(mfp_raw)) + : m_function(0), m_this_delta(0) { static_assert(sizeof(*this) >= sizeof(MemberFunctionType), "size mismatch"); *reinterpret_cast<MemberFunctionType *>(this) = mftp; // NOLINT @@ -153,60 +119,72 @@ namespace plib { //private: // extract the generic function and adjust the object pointer - void convert_to_generic(generic_function &func, generic_class *&object) const + void convert_to_generic(generic_function &func, mfp_generic_class *&object) const { - if (PMFINTERNAL == 1) + // apply the "this" delta to the object first + // NOLINTNEXTLINE(clang-analyzer-core.UndefinedBinaryOperatorResult,cppcoreguidelines-pro-type-reinterpret-cast) + auto *o_p_delta = reinterpret_cast<mfp_generic_class *>(reinterpret_cast<std::uint8_t *>(object) + m_this_delta); + + // if the low bit of the vtable index is clear, then it is just a raw function pointer + if ((m_function & 1) == 0) { - // apply the "this" delta to the object first - // NOLINTNEXTLINE(clang-analyzer-core.UndefinedBinaryOperatorResult,cppcoreguidelines-pro-type-reinterpret-cast) - generic_class *o_p_delta = reinterpret_cast<generic_class *>(reinterpret_cast<std::uint8_t *>(object) + m_this_delta); - - // if the low bit of the vtable index is clear, then it is just a raw function pointer - if ((m_function & 1) == 0) - { - // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) - func = reinterpret_cast<generic_function>(m_function); - } - else - { - // otherwise, it is the byte index into the vtable where the actual function lives - // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) - std::uint8_t *vtable_base = *reinterpret_cast<std::uint8_t **>(o_p_delta); - // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) - func = *reinterpret_cast<generic_function *>(vtable_base + m_function - 1); - } - object = o_p_delta; + // NOLINTNEXTLINE(performance-no-int-to-ptr,cppcoreguidelines-pro-type-reinterpret-cast) + func = reinterpret_cast<generic_function>(m_function); } - else if (PMFINTERNAL == 2) + else { - if ((m_this_delta & 1) == 0) - { - // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) - object = reinterpret_cast<generic_class *>(reinterpret_cast<std::uint8_t *>(object) + m_this_delta); - // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) - func = reinterpret_cast<generic_function>(m_function); - } - else - { - // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) - object = reinterpret_cast<generic_class *>(reinterpret_cast<std::uint8_t *>(object)); - - // otherwise, it is the byte index into the vtable where the actual function lives - // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) - std::uint8_t *vtable_base = *reinterpret_cast<std::uint8_t **>(object); - // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) - func = *reinterpret_cast<generic_function *>(vtable_base + m_function + m_this_delta - 1); - } + // otherwise, it is the byte index into the vtable where the actual function lives + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) + std::uint8_t *vtable_base = *reinterpret_cast<std::uint8_t **>(o_p_delta); + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) + func = *reinterpret_cast<generic_function *>(vtable_base + m_function - 1); } - else if (PMFINTERNAL == 3) - { - const int SINGLE_MEMFUNCPTR_SIZE = sizeof(void (generic_class::*)()); + object = o_p_delta; + } + + // actual state + uintptr_t m_function; // first item can be one of two things: + // if even, it's a pointer to the function + // if odd, it's the byte offset into the vtable + ptrdiff_t m_this_delta; // delta to apply to the 'this' pointer + }; + + template <> + class mfp_raw<PPMF_TYPE_INTERNAL_ARM> + { + public: + // construct from any member function pointer + using generic_function = void (*)(); + + template<typename MemberFunctionType> + mfp_raw(MemberFunctionType mftp) + : m_function(0), m_this_delta(0) + { + static_assert(sizeof(*this) >= sizeof(MemberFunctionType), "size mismatch"); + *reinterpret_cast<MemberFunctionType *>(this) = mftp; // NOLINT + } + //private: + // extract the generic function and adjust the object pointer + void convert_to_generic(generic_function &func, mfp_generic_class *&object) const + { + if ((m_this_delta & 1) == 0) + { // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) + object = reinterpret_cast<mfp_generic_class *>(reinterpret_cast<std::uint8_t *>(object) + (m_this_delta >> 1)); + // NOLINTNEXTLINE(performance-no-int-to-ptr,cppcoreguidelines-pro-type-reinterpret-cast) func = reinterpret_cast<generic_function>(m_function); - if (m_size == SINGLE_MEMFUNCPTR_SIZE + sizeof(int)) - // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) - object = reinterpret_cast<generic_class *>(reinterpret_cast<std::uint8_t *>(object) + m_this_delta); + } + else + { + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) + object = reinterpret_cast<mfp_generic_class *>(reinterpret_cast<std::uint8_t *>(object)); + + // otherwise, it is the byte index into the vtable where the actual function lives + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) + std::uint8_t *vtable_base = *reinterpret_cast<std::uint8_t **>(object); + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) + func = *reinterpret_cast<generic_function *>(vtable_base + m_function + m_this_delta - 1); } } @@ -214,133 +192,179 @@ namespace plib { uintptr_t m_function; // first item can be one of two things: // if even, it's a pointer to the function // if odd, it's the byte offset into the vtable - int m_this_delta; // delta to apply to the 'this' pointer + ptrdiff_t m_this_delta; // delta to apply to the 'this' pointer + }; + + template <> + class mfp_raw<PPMF_TYPE_INTERNAL_MSC> + { + public: + // construct from any member function pointer + using generic_function = void (*)(); + struct unknown_base_equiv { generic_function fptr; int thisdisp, vptrdisp, vtdisp; }; + struct single_base_equiv { generic_function fptr; }; + + template<typename MemberFunctionType> + mfp_raw(MemberFunctionType mftp) + : m_function(0), m_this_delta(0), m_vptr_offs(0), m_vt_index(0), m_size(0) + { + static_assert(sizeof(*this) >= sizeof(MemberFunctionType), "size mismatch"); + *reinterpret_cast<MemberFunctionType *>(this) = mftp; // NOLINT + m_size = sizeof(mftp); //NOLINT + } + + //private: + // extract the generic function and adjust the object pointer + void convert_to_generic(generic_function &func, mfp_generic_class *&object) const + { + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) + auto *byteptr = reinterpret_cast<std::uint8_t *>(object); + + // test for pointer to member function cast across virtual inheritance relationship + if ((sizeof(unknown_base_equiv) == m_size) && m_vt_index) + { + // add offset from "this" pointer to location of vptr, and add offset to virtual base from vtable + byteptr += m_vptr_offs; + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) + std::uint8_t const *const vptr = *reinterpret_cast<std::uint8_t const *const *>(byteptr); + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) + byteptr += *reinterpret_cast<int const *>(vptr + m_vt_index); + } + + // add "this" pointer displacement if present in the pointer to member function + if (sizeof(single_base_equiv) < m_size) + byteptr += m_this_delta; + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) + object = reinterpret_cast<mfp_generic_class *>(byteptr); + + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast,performance-no-int-to-ptr) + auto const *funcx = reinterpret_cast<std::uint8_t const *>(m_function); + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast,performance-no-int-to-ptr) + func = reinterpret_cast<generic_function>(std::uintptr_t(funcx)); + } + + // actual state + uintptr_t m_function; // first item can be one of two things: + // if even, it's a pointer to the function + // if odd, it's the byte offset into the vtable + int m_this_delta; // delta to apply to the 'this' pointer - int m_dummy1; // only used for visual studio x64 - int m_dummy2; - int m_size; + int m_vptr_offs; // only used for visual studio x64 + int m_vt_index; + unsigned m_size; }; - template<int PMFTYPE, int PMFINTERNAL, typename R, typename... Targs> + template<int PMFINTERNAL, typename R, typename... Targs> struct mfp_helper { - static_assert(PMFTYPE == 2 && PMFINTERNAL >= 1 && PMFINTERNAL <=3, "Invalid PMF type"); + protected: + static_assert(PMFINTERNAL >= PPMF_TYPE_INTERNAL_ITANIUM && PMFINTERNAL <= PPMF_TYPE_INTERNAL_MSC, "Invalid PMF type"); + + using traits = mfp_traits<R, Targs...>; + using generic_member_function = typename traits::template specific_member_function<mfp_generic_class>; + using generic_member_abi_function = typename traits::template member_static_ptr<mfp_generic_class>; using raw_type = mfp_raw<PMFINTERNAL>; using generic_function_storage = typename raw_type::generic_function; - using generic_class = typename raw_type::generic_class; - - template <class C> - using specific_member_function = R (C::*)(Targs...); - template <class C> - using const_specific_member_function = R (C::*)(Targs...) const; - - using generic_member_function = specific_member_function<generic_class>; - - template <class C> - using member_abi_function = MEMBER_ABI R (*)(C *obj, Targs... args); + mfp_helper() + : m_obj(nullptr) + { + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) + auto *s = reinterpret_cast<std::uint8_t *>(&m_resolved); + std::fill(s, s + sizeof(m_resolved), 0); + } - template<typename FunctionType, typename MemberFunctionType, typename ObjectType> - static std::pair<FunctionType, ObjectType *> get(MemberFunctionType mftp, ObjectType *object) + template<typename O, typename F> + void bind(O *object, F *mftp) { - raw_type mfpo(mftp); + typename traits::template specific_member_function<O> pFunc; + static_assert(sizeof(pFunc) >= sizeof(F), "size error"); + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) + //*reinterpret_cast<F *>(&pFunc) = *mftp; + reinterpret_copy(*mftp, pFunc); + raw_type mfpo(pFunc); generic_function_storage rfunc(nullptr); // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) - auto *robject = reinterpret_cast<generic_class *>(object); + auto *robject = reinterpret_cast<mfp_generic_class *>(object); mfpo.convert_to_generic(rfunc, robject); + reinterpret_copy(rfunc, this->m_resolved); // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) - return std::make_pair(reinterpret_cast<FunctionType>(rfunc), reinterpret_cast<ObjectType *>(robject)); + m_obj = reinterpret_cast<mfp_generic_class *>(robject); } - template<typename O> - static R call(const member_abi_function<O> *func, O *obj, Targs&&... args) noexcept(true) + + R call(Targs&&... args) const noexcept(true) { - return (*func)(obj, std::forward<Targs>(args)...); + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) + const auto* func = reinterpret_cast<const generic_member_abi_function *>(&m_resolved); + return (*func)(m_obj, std::forward<Targs>(args)...); } + generic_function_storage m_resolved; + mfp_generic_class *m_obj; }; template<typename R, typename... Targs> - struct mfp_helper<PPMF_TYPE_PMF, 0, R, Targs...> + struct mfp_helper<PPMF_TYPE_PMF, R, Targs...> { - template <class C> - using specific_member_function = R (C::*)(Targs...); + protected: + using traits = mfp_traits<R, Targs...>; + using generic_member_function = typename traits::template specific_member_function<mfp_generic_class>; template <class C> - using const_specific_member_function = R (C::*)(Targs...) const; + using member_abi_function = typename traits::template specific_member_function<C>; - class generic_class; - using generic_member_function = specific_member_function<generic_class>; - - template <class C> - using member_abi_function = specific_member_function<C>; - - using generic_function_storage = generic_member_function; - - template<typename FunctionType, typename MemberFunctionType, typename ObjectType> - static std::pair<FunctionType, ObjectType *> get(MemberFunctionType mftp, ObjectType *object) + mfp_helper() + : m_obj(nullptr) + , m_stub(nullptr) { // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) - return std::make_pair(reinterpret_cast<FunctionType>(mftp), reinterpret_cast<ObjectType *>(object)); + auto *s = reinterpret_cast<std::uint8_t *>(&m_resolved); + std::fill(s, s + sizeof(m_resolved), 0); } - template<typename O> - static R call(const member_abi_function<O> *func, O *obj, Targs&&... args) noexcept(true) + template<typename O, typename F> + void bind(O *object, F *mftp) { - return (obj->*(*func))(std::forward<Targs>(args)...); + reinterpret_copy(*mftp, this->m_resolved); + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) + m_obj = reinterpret_cast<mfp_generic_class *>(object); + m_stub = &stub<O>; } - }; - - template<typename R, typename... Targs> - struct mfp_helper<PPMF_TYPE_GNUC_PMF_CONV, 0, R, Targs...> - { - template <class C> - using specific_member_function = R (C::*)(Targs...); - - template <class C> - using const_specific_member_function = R (C::*)(Targs...) const; - - class generic_class; - using generic_member_function = specific_member_function<generic_class>; - - template <class C> - using member_abi_function = MEMBER_ABI R (*)(C *obj, Targs... args); - - using generic_function_storage = void (*)(); - template<typename FunctionType, typename MemberFunctionType, typename ObjectType> - static std::pair<FunctionType, ObjectType *> get(MemberFunctionType mftp, ObjectType *object) + R call(Targs&&... args) const noexcept(true) { // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) - return std::make_pair(reinterpret_cast<FunctionType>(object->*mftp), reinterpret_cast<ObjectType *>(object)); + auto* func = reinterpret_cast<const generic_member_function *>(&m_resolved); + return (*m_stub)(func, m_obj, std::forward<Targs>(args)...); } + + generic_member_function m_resolved; + mfp_generic_class *m_obj; + R (*m_stub)(const generic_member_function *funci, mfp_generic_class *obji, Targs&&... args); + + private: template<typename O> - static R call(const member_abi_function<O> *func, O *obj, Targs&&... args) noexcept(true) + static R stub(const generic_member_function *funci, mfp_generic_class *obji, Targs&&... args) noexcept(true) { - return (*func)(obj, std::forward<Targs>(args)...); + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) + auto *obj = reinterpret_cast<O *>(obji); + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) + auto *func = reinterpret_cast<const member_abi_function<O> *>(funci); + return (obj->*(*func))(std::forward<Targs>(args)...); } }; - template<int PMFTYPE, int PMFINTERNAL, typename R, typename... Targs> - class pmfp_base +#if NVCCBUILD == 0 + template<typename R, typename... Targs> + struct mfp_helper<PPMF_TYPE_GNUC_PMF_CONV, R, Targs...> { - public: - using helper = mfp_helper<PMFTYPE, PMFINTERNAL, R, Targs...>; + protected: + using traits = mfp_traits<R, Targs...>; template <class C> - using specific_member_function = typename helper::template specific_member_function<C>; - - template <class C> - using const_specific_member_function = typename helper::template const_specific_member_function<C>; - - using generic_class = typename helper::generic_class; - using generic_member_function = typename helper::generic_member_function; + using member_abi_function = typename traits::template member_static_ptr<C>; - template <class C> - using member_abi_function = typename helper::template member_abi_function<C>; - - using generic_function_storage = typename helper::generic_function_storage; - - pmfp_base() + mfp_helper() : m_obj(nullptr) { // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) @@ -348,82 +372,88 @@ namespace plib { std::fill(s, s + sizeof(m_resolved), 0); } - template<typename O> - pmfp_base(specific_member_function<O> mftp, O *object) - : m_obj(nullptr) + template<typename O, typename F> + void bind(O *object, F *mftp) { // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) - auto *s = reinterpret_cast<std::uint8_t *>(&m_resolved); - std::fill(s, s + sizeof(m_resolved), 0); - bind<specific_member_function<O>>(object, &mftp); + member_abi_function<O> t = reinterpret_cast<member_abi_function<O>>(object->*(*mftp)); + reinterpret_copy(t, this->m_resolved); + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) + m_obj = reinterpret_cast<mfp_generic_class *>(object); } - template<typename O> - pmfp_base(const_specific_member_function<O> mftp, O *object) - : m_obj(nullptr) + R call(Targs&&... args) const noexcept(true) { // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) - auto *s = reinterpret_cast<std::uint8_t *>(&m_resolved); - std::fill(s, s + sizeof(m_resolved), 0); - bind<const_specific_member_function<O>>(object, &mftp); + auto* func = reinterpret_cast<const member_abi_function<mfp_generic_class> *>(&m_resolved); + return (*func)(m_obj, std::forward<Targs>(args)...); } - generic_class *object() const noexcept { return m_obj; } - bool has_object() const noexcept { return m_obj != nullptr; } + member_abi_function<mfp_generic_class> m_resolved; + mfp_generic_class *m_obj; + }; +#endif + + template <int PMFINTERNAL, typename R, typename... Targs> + using pmfp_helper_select = std::conditional< + std::is_void_v<R> || + std::is_scalar_v<R> || + std::is_reference_v<R> || PMFINTERNAL != PPMF_TYPE_INTERNAL_MSC, + mfp_helper<PMFINTERNAL, R, Targs...>, mfp_helper<PPMF_TYPE_PMF, R, Targs...>>; - template<typename O> - void set(specific_member_function<O> mftp, O *object) + template<int PMFINTERNAL, typename SIGNATURE> class pmfp_base; + + template<int PMFINTERNAL, typename R, typename... Targs> + class pmfp_base<PMFINTERNAL, R (Targs...)> : public pmfp_helper_select<PMFINTERNAL, R, Targs...>::type + { + public: + using helper = typename pmfp_helper_select<PMFINTERNAL, R, Targs...>::type; + + using traits = mfp_traits<R, Targs...>; + + pmfp_base() + : helper() { - bind<specific_member_function<O>>(object, &mftp); } - R operator()(Targs... args) const noexcept(true) + template<typename O, typename P> + pmfp_base(typename traits::template specific_member_function<O> mftp, P *object) + : helper() { - return this->call(std::forward<Targs>(args)...); + this->bind(static_cast<O*>(object), &mftp); } - operator bool() const noexcept { return m_resolved != nullptr; } - private: - template<typename SPC, typename O, typename MF> - void bind(O * object, MF *fraw) + template<typename O, typename P> + pmfp_base(typename traits::template const_specific_member_function<O> mftp, P *object) + : helper() { - SPC pFunc; - static_assert(sizeof(pFunc) >= sizeof(MF), "size error"); - // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) - *reinterpret_cast<MF *>(&pFunc) = *fraw; - - auto r = helper::template get<member_abi_function<O>>(pFunc, object); - - static_assert(sizeof(m_resolved) >= sizeof(r.first), "size mismatch 1"); - static_assert(sizeof(m_resolved) >= sizeof(member_abi_function<O>), "size mismatch 2"); - - //*reinterpret_cast<member_abi_function<O> *>(&m_resolved) = r.first; - reinterpret_copy(r.first, m_resolved); - // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) - m_obj = reinterpret_cast<generic_class *>(r.second); + this->bind(static_cast<O*>(object), &mftp); } + mfp_generic_class *object() const noexcept { return this->m_obj; } + template<typename O> - R call(O *obj, Targs&&... args) const noexcept(true) + void set(typename traits::template specific_member_function<O> mftp, O *object) { - // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) - return helper::call(reinterpret_cast<member_abi_function<O> *>(&m_resolved), - obj, std::forward<Targs>(args)...); + this->bind(object, &mftp); } - R call(Targs&&... args) const noexcept(true) + R operator()(Targs... args) const noexcept(true) { - // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) - return helper::call(reinterpret_cast<const member_abi_function<generic_class> *>(&m_resolved), - m_obj, std::forward<Targs>(args)...); + return this->call(std::forward<Targs>(args)...); } - generic_function_storage m_resolved; - generic_class *m_obj; + bool isnull() const noexcept { return this->m_resolved == nullptr; } + explicit operator bool() const noexcept { return !isnull(); } + bool has_object() const noexcept { return this->m_obj != nullptr; } + bool operator==(const pmfp_base &rhs) const { return this->m_resolved == rhs.m_resolved; } + bool operator!=(const pmfp_base &rhs) const { return !(*this == rhs); } + + private: }; - template<typename R, typename... Targs> - using pmfp = pmfp_base<ppmf_type::value, ppmf_internal::value, R, Targs...>; + template<typename Signature> + using pmfp = pmfp_base<ppmf_internal::value, Signature>; /// /// \brief Class to support delegate late binding @@ -437,8 +467,8 @@ namespace plib { /// /// // After full construction ... /// - /// auto dele = a(this); - /// dele(pstring("Hello World!")); + /// auto delegate_obj = a(this); + /// delegate_obj(pstring("Hello World!")); /// template<typename T> class late_pmfp @@ -446,41 +476,33 @@ namespace plib { public: using return_type = T; - - template <class C> - using specific_member_function = typename return_type::template specific_member_function<C>; // noexcept(true) --> c++-17 - - using generic_member_function = typename return_type::generic_member_function; - - class generic_class; - - using static_creator = return_type (*)(const generic_member_function *, generic_class *); - - late_pmfp() = default; + using traits = typename return_type::traits; + using generic_member_function = typename traits::template specific_member_function<mfp_generic_class>; + using static_creator = return_type (*)(const generic_member_function *, mfp_generic_class *); template<typename O> - late_pmfp(specific_member_function<O> mftp) + late_pmfp(typename traits::template specific_member_function<O> mftp) : m_creator(creator<O>) { - static_assert(sizeof(m_raw) >= sizeof(specific_member_function<O>), "size issue"); + static_assert(sizeof(m_raw) >= sizeof(typename traits::template specific_member_function<O>), "size issue"); // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) - *reinterpret_cast<specific_member_function<O> *>(&m_raw) = mftp; + *reinterpret_cast<typename traits::template specific_member_function<O> *>(&m_raw) = mftp; } template<typename O> return_type operator()(O *object) const { // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) - return m_creator(&m_raw, reinterpret_cast<generic_class *>(object)); + return m_creator(&m_raw, reinterpret_cast<mfp_generic_class *>(object)); } private: template <typename O> - static return_type creator(const generic_member_function *raw, generic_class *obj) + static return_type creator(const generic_member_function *raw, mfp_generic_class *obj) { // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) - auto p = reinterpret_cast<const specific_member_function<O> *>(raw); + auto p = reinterpret_cast<const typename traits::template specific_member_function<O> *>(raw); // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) auto o = reinterpret_cast<O *>(obj); return return_type(*p, o); |