summaryrefslogtreecommitdiffstatshomepage
path: root/src/lib/netlist/plib/ppmf.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/netlist/plib/ppmf.h')
-rw-r--r--src/lib/netlist/plib/ppmf.h568
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);