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.h721
1 files changed, 514 insertions, 207 deletions
diff --git a/src/lib/netlist/plib/ppmf.h b/src/lib/netlist/plib/ppmf.h
index 9ee759befa4..56f40bde922 100644
--- a/src/lib/netlist/plib/ppmf.h
+++ b/src/lib/netlist/plib/ppmf.h
@@ -1,280 +1,587 @@
-// license:GPL-2.0+
+// license:BSD-3-Clause
// copyright-holders:Couriersud
-/*
- * ppmf.h
- *
- */
#ifndef PPMF_H_
#define PPMF_H_
+///
+/// \file ppmf.h
+///
+///
+/// PMF_TYPE_PMF
+/// Use standard pointer to member function syntax C++11
+///
+/// PMF_TYPE_GNUC_PMF_CONV
+/// Use gnu extension and convert the pmf to a function pointer.
+/// This is not standard compliant and needs
+/// -Wno-pmf-conversions to compile.
+///
+/// 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 -t 10 -n pong src/mame/machine/nl_pong.cpp`
+///
+/// PMF_TYPE_INTERNAL: 215% 215% 564% 580%
+/// PMF_TYPE_GNUC_PMF: 163% 196% 516% 490%
+/// PMF_TYPE_GNUC_PMF_CONV: 215% 215% 560% 575%
+///
+///
+
+/// \brief Enable experimental code on Visual Studio builds and VS clang llvm builds
+///
+/// This enables experimental code which uses optimized builds the
+/// ppmf_type::INTERNAL_MSC path also for complex (struct/union) return types.
+/// This currently depends on whether the code can adequately determine on
+/// x64 builds if the return type is returned through registers or passed as a
+/// second argument as a pointer to the member function.
+///
+/// The experimental code uses a temporary storage for the return value. This a
+/// copy overhead for causes for large sized return types a copy overhead.
+/// It would be easier if we would be able to obtain the RDX register on entry
+/// to the call. On MSVC this seems not to be possible since on x64 inline
+/// assembly is not supported. Even with clang-cl inline assembly this was not
+/// successful when optimized code was compiled. Therefore we have to live with
+/// the limitations.
+///
+/// This code path is disabled by default currently.
+///
+#if !defined(PPMF_EXPERIMENTAL)
+#define PPMF_EXPERIMENTAL 0
+#endif
+
+/// brief Enable using MAME delegates as a replacement for ppmf.
+///
+/// This define enables the use of MAME delegates (src/lib/util/delegate.h
+/// as a replacement to ppmf. Enable this setting if you want to use the nltool
+/// test suite (nltool -c tests) to produce comparisons to ppmf.
+///
+#if !defined(PPMF_USE_MAME_DELEGATES)
+#define PPMF_USE_MAME_DELEGATES 0
+#endif
+
+#if PPMF_USE_MAME_DELEGATES
+
+#include "../../util/delegate.h"
+
+namespace plib {
+ template<typename Signature>
+ class pmfp : public delegate<Signature>
+ {
+ public:
+ using basetype = delegate<Signature>;
+ using basetype::basetype;
+ using basetype::object;
+ explicit operator bool() const { return !this->isnull(); }
+ };
+}
+#else
+
#include "pconfig.h"
+#include "ptypes.h"
+#include <algorithm>
+#include <cstddef> // ptrdiff_t
#include <cstdint> // uintptr_t
+#include <type_traits>
#include <utility>
-/*
- *
- * NL_PMF_TYPE_GNUC_PMF
- * Use standard pointer to member function syntax C++11
- *
- * NL_PMF_TYPE_GNUC_PMF_CONV
- * Use gnu extension and convert the pmf to a function pointer.
- * This is not standard compliant and needs
- * -Wno-pmf-conversions to compile.
- *
- * NL_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
- *
- * NL_PMF_TYPE_INTERNAL: 215% 215%
- * NL_PMF_TYPE_GNUC_PMF: 163% 196%
- * NL_PMF_TYPE_GNUC_PMF_CONV: 215% 215%
- * NL_PMF_TYPE_VIRTUAL: 213% 209%
- *
- * 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.
- *
- */
-
-#if (PPMF_TYPE == PPMF_TYPE_GNUC_PMF_CONV)
-#pragma GCC diagnostic ignored "-Wpmf-conversions"
-#endif
+//============================================================
+// Macro magic
+//============================================================
-#if defined(__GNUC__) && (__GNUC__ > 6)
-#pragma GCC diagnostic ignored "-Wnoexcept-type"
+//#define PPMF_FORCE_TYPE 1
+
+#ifndef PPMF_FORCE_TYPE
+#define PPMF_FORCE_TYPE -1
#endif
namespace plib {
-/*
- * The following class was derived from the MAME delegate.h code.
- * It derives a pointer to a member function.
- */
-#if (PHAS_PMF_INTERNAL > 0)
- class mfp
+ enum class ppmf_type
+ {
+ PMF,
+ GNUC_PMF_CONV,
+ INTERNAL_ITANIUM,
+ INTERNAL_ARM,
+ INTERNAL_MSC
+ };
+
+
+ struct ppmf_internal_selector
+ {
+ using ci = compile_info;
+ constexpr static ppmf_type value =
+ (PPMF_FORCE_TYPE >= 0) ? static_cast<ppmf_type>(PPMF_FORCE_TYPE) :
+ (ci::type() == ci_compiler::CLANG && !ci::m64()
+ && ci::os() == ci_os::WINDOWS) ? ppmf_type::PMF :
+ (ci::mingw() && !ci::m64() && ci::version::full() >= typed_version<4,7>::full()) ? ppmf_type::PMF :
+ (ci::mingw() && !ci::m64()) ? ppmf_type::PMF : // Dropped support for mingw32 < 407 ppmf_type::INTERNAL_ITANIUM :
+ (ci::env() == ci_env::MSVC && ci::m64()) ? ppmf_type::INTERNAL_MSC :
+ ((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)) ? ppmf_type::INTERNAL_ARM :
+ (ci::type() == ci_compiler::CLANG || ci::type() == ci_compiler::GCC) ? ppmf_type::INTERNAL_ITANIUM :
+ ppmf_type::PMF
+ ;
+ };
+
+ static_assert(!(compile_info::type() == ci_compiler::CLANG && ppmf_internal_selector::value == (ppmf_type::GNUC_PMF_CONV)), "clang does not support ppmf_type::GNUC_PMF_CONV");
+ static_assert(!(compile_info::env() == ci_env::NVCC && ppmf_internal_selector::value == (ppmf_type::GNUC_PMF_CONV)), "nvcc does not support ppmf_type::GNUC_PMF_CONV");
+
+ 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...);
+ };
+
+ class mfp_generic_class;
+
+
+ ///
+ /// \brief Used to derive a pointer to a member function.
+ ///
+ /// The following class was derived from the MAME delegate.h code.
+ ///
+ template <ppmf_type PMFINTERNAL>
+ class mfp_raw;
+
+ template <>
+ class mfp_raw<ppmf_type::INTERNAL_ITANIUM>
{
public:
// construct from any member function pointer
-#ifdef _MSC_VER
- class __single_inheritance si_generic_class;
- class generic_class { };
-#else
- class generic_class;
-#endif
using generic_function = void (*)();
template<typename MemberFunctionType>
- mfp(MemberFunctionType mftp) // NOLINT(cppcoreguidelines-pro-type-member-init)
+ mfp_raw(MemberFunctionType mftp);
- : m_function(0), m_this_delta(0), m_size(sizeof(mfp))
- {
- *reinterpret_cast<MemberFunctionType *>(this) = mftp;
- }
+ // extract the generic function and adjust the object pointer
+ void convert_to_generic(generic_function &func, mfp_generic_class *&object) const;
+
+ /// \brief Byte offset into the vtable
+ ///
+ /// On x86-64, the vtable contains pointers to code, and function pointers
+ /// are pointers to code. To obtain a function pointer for a virtual
+ /// member function, you fetch a pointer to code from the vtable.
+ ///
+ /// On traditional PPC64, the vtable contains pointers to function
+ /// descriptors, and function pointers are pointers to function descriptors.
+ /// To obtain a function pointer for a virtual member function, you
+ /// fetch a pointer to a function descriptor from the vtable.
+ ///
+ /// On IA64, the vtable contains function descriptors, and function
+ /// pointers are pointers to function descriptors. To obtain a
+ /// function pointer for a virtual member function, you calculate
+ /// the address of the function descriptor in the vtable.
+ ///
+ /// Simply adding the byte offset to the vtable pointer creates a
+ /// function pointer on IA64 because the vtable contains function
+ /// descriptors; on most other targets, the vtable contains function
+ /// pointers, so you need to fetch the function pointer after
+ /// calculating its address in the vtable.
+ ///
+ uintptr_t m_function; // first item can be one of two things:
+ // if even, it's a function pointer
+ // if odd, it's the byte offset into the vtable
+ ptrdiff_t m_this_delta; // delta to apply to the 'this' pointer
+ };
- template<typename MemberFunctionType, typename FunctionType, typename ObjectType>
- static void get_mfp(MemberFunctionType mftp, FunctionType &func, ObjectType *&object)
- {
- mfp mfpo(mftp);
- //return mfpo.update_after_bind<FunctionType>(object);
- generic_function rfunc(nullptr);
- auto robject = reinterpret_cast<generic_class *>(object);
- mfpo.convert_to_generic(rfunc, robject);
- func = reinterpret_cast<FunctionType>(rfunc);
- object = reinterpret_cast<ObjectType *>(robject);
- }
+ 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);
+
+ // extract the generic function and adjust the object pointer
+ void convert_to_generic(generic_function &func, mfp_generic_class *&object) const;
+
+ // actual state
+ uintptr_t m_function; // first item can be a function pointer or a byte offset into the vtable
+ ptrdiff_t m_this_delta; // delta to apply to the 'this' pointer after right shifting by one bit
+ // if even, m_function is a fuction pointer
+ // if odd, m_function is the byte offset into the vtable
+ };
+
+ 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);
- 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;
+
+ // actual state
+ uintptr_t m_function; // pointer to the function
+ int m_this_delta; // delta to apply to the 'this' pointer
+
+ int m_vptr_index; // index into the vptr table.
+ int m_vt_index; // offset to be applied after vptr table lookup.
+ unsigned m_size;
+ };
+
+ template <typename R>
+ using pmf_is_register_return_type = std::integral_constant<bool,
+ std::is_void_v<R> ||
+ std::is_scalar_v<R> ||
+ std::is_reference_v<R> ||
+ std::is_same_v<std::remove_cv_t<R>, compile_info::int128_type> ||
+ std::is_same_v<std::remove_cv_t<R>, compile_info::uint128_type> >;
+
+ template<ppmf_type PMFINTERNAL, typename R, typename... Targs>
+ struct mfp_helper
+ {
+ 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;
+
+ mfp_helper();
+
+ template<typename O, typename F>
+ void bind(O *object, F *mftp);
+
+ R call(Targs&&... args) const noexcept(true)
{
- if (PHAS_PMF_INTERNAL == 1)
+#if defined(_MSC_VER) && (PPMF_EXPERIMENTAL)
+ if constexpr (pmf_is_register_return_type<R>::value)
{
- // apply the "this" delta to the object first
- // NOLINTNEXTLINE(clang-analyzer-core.UndefinedBinaryOperatorResult)
- auto 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))
- func = reinterpret_cast<generic_function>(m_function);
- else
- {
- // otherwise, it is the byte index into the vtable where the actual function lives
- std::uint8_t *vtable_base = *reinterpret_cast<std::uint8_t **>(o_p_delta);
- func = *reinterpret_cast<generic_function *>(vtable_base + m_function - 1);
- }
- object = o_p_delta;
+ // 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)...);
}
- else if (PHAS_PMF_INTERNAL == 2)
+ else
{
- if ((m_this_delta & 1) == 0) {
- object = reinterpret_cast<generic_class *>(reinterpret_cast<std::uint8_t *>(object) + m_this_delta);
- func = reinterpret_cast<generic_function>(m_function);
- }
- else
- {
- 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
- std::uint8_t *vtable_base = *reinterpret_cast<std::uint8_t **>(object);
- func = *reinterpret_cast<generic_function *>(vtable_base + m_function + m_this_delta - 1);
- }
+ using generic_member_abi_function_alt = void (*)(mfp_generic_class *,void *, Targs...);
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
+ const auto* func = reinterpret_cast<const generic_member_abi_function_alt*>(&m_resolved);
+ std::uint8_t temp[sizeof(typename std::conditional<std::is_void_v<R>, void *, R>::type)];
+ (*func)(m_obj, &temp[0], std::forward<Targs>(args)...);
+ return *reinterpret_cast<R *>(&temp);
}
- else if (PHAS_PMF_INTERNAL == 3)
- {
- const int SINGLE_MEMFUNCPTR_SIZE = sizeof(void (generic_class::*)());
+#else
+ // 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)...);
+#endif
+ }
- func = reinterpret_cast<generic_function>(m_function);
- if (m_size == SINGLE_MEMFUNCPTR_SIZE + sizeof(int))
- object = reinterpret_cast<generic_class *>(reinterpret_cast<std::uint8_t *>(object) + m_this_delta);
- }
+ generic_function_storage m_resolved;
+ mfp_generic_class *m_obj;
+ };
+
+ template<typename R, typename... Targs>
+ struct mfp_helper<ppmf_type::PMF, R, 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 member_abi_function = typename traits::template specific_member_function<C>;
+ mfp_helper();
+
+ template<typename O, typename F>
+ void bind(O *object, F *mftp);
+
+ R call(Targs&&... args) const noexcept(true)
+ {
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
+ auto* func = reinterpret_cast<const generic_member_function *>(&m_resolved);
+ return (*m_stub)(func, m_obj, std::forward<Targs>(args)...);
}
- // 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;
+ 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 stub(const generic_member_function* funci, mfp_generic_class* obji, Targs&&... args) noexcept(true);
};
-#endif
-#if (PPMF_TYPE == PPMF_TYPE_PMF)
template<typename R, typename... Targs>
- class pmfp_base
+ struct mfp_helper<ppmf_type::GNUC_PMF_CONV, R, Targs...>
{
+ protected:
+ using traits = mfp_traits<R, Targs...>;
+
+ template <class C>
+ using member_abi_function = typename traits::template member_static_ptr<C>;
+
+ mfp_helper();
+
+ template<typename O, typename F>
+ void bind(O *object, F *mftp);
+
+ R call(Targs&&... args) const noexcept(true)
+ {
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
+ auto* func = reinterpret_cast<const member_abi_function<mfp_generic_class> *>(&m_resolved);
+ return (*func)(m_obj, std::forward<Targs>(args)...);
+ }
+
+ member_abi_function<mfp_generic_class> m_resolved;
+ mfp_generic_class *m_obj;
+ };
+
+ template <ppmf_type PMFINTERNAL, typename R, typename... Targs>
+ using pmfp_helper_select = std::conditional<
+ pmf_is_register_return_type<R>::value
+ || PMFINTERNAL != ppmf_type::INTERNAL_MSC || (PPMF_EXPERIMENTAL),
+ mfp_helper<PMFINTERNAL, R, Targs...>, mfp_helper<ppmf_type::PMF, R, Targs...>>;
+
+ template<ppmf_type PMFINTERNAL, typename SIGNATURE> class pmfp_base;
+
+ template<ppmf_type PMFINTERNAL, typename R, typename... Targs>
+ class pmfp_base<PMFINTERNAL, R (Targs...)> : public pmfp_helper_select<PMFINTERNAL, R, Targs...>::type
+ {
+ static_assert((compile_info::env::value != ci_env::NVCC) || (PMFINTERNAL != ppmf_type::GNUC_PMF_CONV), "GNUC_PMF_CONV not supported by nvcc");
public:
- class generic_class;
-#if defined (__INTEL_COMPILER) && defined (_M_X64) // needed for "Intel(R) C++ Intel(R) 64 Compiler XE for applications running on Intel(R) 64, Version 14.0.2.176 Build 20140130" at least
- using generic_function = int [((sizeof(void *) + 4 * sizeof(int)) + (sizeof(int) - 1)) / sizeof(int)];
-#elif defined(_MSC_VER) // all other cases - for MSVC maximum size is one pointer, plus 3 ints; all other implementations seem to be smaller
- using generic_function = int[((sizeof(void *) + 3 * sizeof(int)) + (sizeof(int) - 1)) / sizeof(int)];
-#else
- using generic_function = R (generic_class::*)(Targs...);
-#endif
+ using helper = typename pmfp_helper_select<PMFINTERNAL, R, Targs...>::type;
+
+ using traits = mfp_traits<R, Targs...>;
+
pmfp_base()
+ : helper()
{
- int *p = reinterpret_cast<int *>(&m_func);
- int *e = p + sizeof(generic_function) / sizeof(int);
- for (; p < e; p++)
- *p = 0;
}
- template<typename MemberFunctionType, typename O>
- void set_base(MemberFunctionType mftp, O *object)
+ template<typename O, typename P>
+ pmfp_base(typename traits::template specific_member_function<O> mftp, P *object)
+ : helper()
{
- using function_ptr = R (O::*)(Targs...);
- function_ptr t = mftp;
- *reinterpret_cast<function_ptr *>(&m_func) = t;
+ this->bind(static_cast<O*>(object), &mftp);
}
+
+ template<typename O, typename P>
+ pmfp_base(typename traits::template const_specific_member_function<O> mftp, P *object)
+ : helper()
+ {
+ this->bind(static_cast<O*>(object), &mftp);
+ }
+
+ mfp_generic_class *object() const noexcept { return this->m_obj; }
+
template<typename O>
- inline R call(O *obj, Targs... args)
+ void set(typename traits::template specific_member_function<O> mftp, O *object)
{
- using function_ptr = R (O::*)(Targs...);
- function_ptr t = *reinterpret_cast<function_ptr *>(&m_func);
- return (obj->*t)(std::forward<Targs>(args)...);
+ this->bind(object, &mftp);
}
- bool is_set() {
-#if defined(_MSC_VER) || (defined (__INTEL_COMPILER) && defined (_M_X64))
- int *p = reinterpret_cast<int *>(&m_func);
- int *e = p + sizeof(generic_function) / sizeof(int);
- for (; p < e; p++)
- if (*p != 0)
- return true;
-
- return false;
-#else
- return m_func != nullptr;
-#endif
+
+ R operator()(Targs... args) const noexcept(true)
+ {
+ return this->call(std::forward<Targs>(args)...);
}
+
+ 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:
- generic_function m_func;
-#if 0 && defined(_MSC_VER)
- int dummy[4];
-#endif
};
-#elif ((PPMF_TYPE == PPMF_TYPE_GNUC_PMF_CONV) || (PPMF_TYPE == PPMF_TYPE_INTERNAL))
- template<typename R, typename... Targs>
- class pmfp_base
+ template<typename Signature>
+ using pmfp = pmfp_base<ppmf_internal_selector::value, Signature>;
+
+ ///
+ /// \brief Class to support delegate late binding
+ ///
+ /// When constructing delegates in constructors AND the referenced function
+ /// is virtual, the vtable may not yet be fully constructed. In these cases
+ /// the following class allows to construct the delegate later.
+ ///
+ /// ```
+ /// plib::late_pmfp<plib::pmfp<void, pstring>> a(&nld_7493::printer);
+ /// // Store the a object somewhere
+ ///
+ /// // After full construction ...
+ ///
+ /// auto delegate_obj = a(this);
+ /// delegate_obj(pstring("Hello World!"));
+ /// ```
+ template<typename T>
+ class late_pmfp
{
public:
- using generic_function = void (*)();
- pmfp_base() : m_func(nullptr) {}
+ using return_type = T;
+ 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 MemberFunctionType, typename O>
- void set_base(MemberFunctionType mftp, O *object)
- {
- #if (PPMF_TYPE == PPMF_TYPE_INTERNAL)
- using function_ptr = MEMBER_ABI R (*)(O *obj, Targs... args);
- function_ptr func(nullptr);
- plib::mfp::get_mfp(mftp, func, object);
- m_func = reinterpret_cast<generic_function>(func);
- #elif (PPMF_TYPE == PPMF_TYPE_GNUC_PMF_CONV)
- R (O::* pFunc)(Targs...) = mftp;
- m_func = reinterpret_cast<generic_function>((object->*pFunc));
- #endif
- }
template<typename O>
- R call(O *obj, Targs... args) const
+ late_pmfp(typename traits::template specific_member_function<O> mftp);
+
+ template<typename O>
+ return_type operator()(O *object) const
{
- using function_ptr = MEMBER_ABI R (*)(O *obj, Targs... args);
- return (reinterpret_cast<function_ptr>(m_func))(obj, std::forward<Targs>(args)...);
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
+ return m_creator(&m_raw, reinterpret_cast<mfp_generic_class *>(object));
}
- bool is_set() noexcept { return m_func != nullptr; }
- generic_function get_function() const noexcept { return m_func; }
+
private:
- generic_function m_func;
+
+ template <typename O>
+ static return_type creator(const generic_member_function *raw, mfp_generic_class *obj);
+
+ generic_member_function m_raw;
+ static_creator m_creator;
};
-#endif
- template<typename R, typename... Targs>
- class pmfp : public pmfp_base<R, Targs...>
+ template<typename MemberFunctionType>
+ mfp_raw<ppmf_type::INTERNAL_ITANIUM>::mfp_raw(MemberFunctionType mftp)
+ : m_function(0), m_this_delta(0)
{
- public:
- class generic_class;
+ static_assert(sizeof(*this) >= sizeof(MemberFunctionType), "size mismatch");
+ *reinterpret_cast<MemberFunctionType *>(this) = mftp; // NOLINT
+ // NOLINTNEXTLINE(clang-analyzer-optin.cplusplus.UninitializedObject)
+ }
+
+ template<typename MemberFunctionType>
+ mfp_raw<ppmf_type::INTERNAL_ARM>::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
+ }
- template <class C>
- using MemberFunctionType = R (C::*)(Targs...);
+ template<typename MemberFunctionType>
+ mfp_raw<ppmf_type::INTERNAL_MSC>::mfp_raw(MemberFunctionType mftp)
+ : m_function(0), m_this_delta(0), m_vptr_index(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
+ }
+
+ template<ppmf_type PMFINTERNAL, typename R, typename... Targs>
+ mfp_helper<PMFINTERNAL, R, Targs...>::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<ppmf_type PMFINTERNAL, typename R, typename... Targs>
+ template<typename O, typename F>
+ void mfp_helper<PMFINTERNAL, R, Targs...>::bind(O *object, F *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<mfp_generic_class *>(object);
+ mfpo.convert_to_generic(rfunc, robject);
+ reinterpret_copy(rfunc, this->m_resolved);
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
+ m_obj = reinterpret_cast<mfp_generic_class *>(robject);
+ }
- pmfp() : pmfp_base<R, Targs...>(), m_obj(nullptr) {}
+ template<typename R, typename... Targs>
+ mfp_helper<ppmf_type::PMF, R, Targs...>::mfp_helper()
+ : m_obj(nullptr)
+ , m_stub(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 O>
- pmfp(MemberFunctionType<O> mftp, O *object)
- : pmfp_base<R, Targs...>()
- {
- this->set_base(mftp, object);
- m_obj = reinterpret_cast<generic_class *>(object);
- }
+ template<typename R, typename... Targs>
+ template<typename O, typename F>
+ void mfp_helper<ppmf_type::PMF, R, Targs...>::bind(O *object, F *mftp)
+ {
+ 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 O>
- void set(MemberFunctionType<O> mftp, O *object)
- {
- this->set_base(mftp, object);
- m_obj = reinterpret_cast<generic_class *>(object);
- }
+ template<typename R, typename... Targs>
+ template<typename O>
+ R mfp_helper<ppmf_type::PMF, R, Targs...>::stub(const generic_member_function* funci, mfp_generic_class* obji, Targs&&... args) noexcept(true)
+ {
+ // 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)...);
+ }
- inline R operator()(Targs ... args)
- {
- return this->call(m_obj, std::forward<Targs>(args)...);
- }
+ template<typename R, typename... Targs>
+ mfp_helper<ppmf_type::GNUC_PMF_CONV, R, Targs...>::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);
+ }
- generic_class *object() const noexcept { return m_obj; }
- bool has_object() const noexcept { return m_obj != nullptr; }
- private:
- generic_class *m_obj;
- };
+ template<typename R, typename... Targs>
+ template<typename O, typename F>
+ void mfp_helper<ppmf_type::GNUC_PMF_CONV, R, Targs...>::bind(O *object, F *mftp)
+ {
+ // nvcc still tries to compile the code below - even when shielded with a `if constexpr`
+#if !defined(__NVCC__)
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
+ 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);
+#endif
+ }
+ template<typename T>
+ template<typename O>
+ late_pmfp<T>::late_pmfp(typename traits::template specific_member_function<O> mftp)
+ : m_creator(creator<O>)
+ {
+ static_assert(sizeof(m_raw) >= sizeof(typename traits::template specific_member_function<O>), "size issue");
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
+ *reinterpret_cast<typename traits::template specific_member_function<O> *>(&m_raw) = mftp;
+ }
+
+ template<typename T>
+ template<typename O>
+ typename late_pmfp<T>::return_type late_pmfp<T>::creator(const typename late_pmfp<T>::generic_member_function *raw, mfp_generic_class *obj)
+ {
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
+ auto p = reinterpret_cast<const typename late_pmfp<T>::traits::template specific_member_function<O> *>(raw);
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
+ auto *o = reinterpret_cast<O *>(obj);
+ return return_type(*p, o);
+ }
} // namespace plib
-#endif /* PPMF_H_ */
+#endif
+#endif // PPMF_H_