From ad19e439a6ea1a6adf38d8489cd1c356fbcf15fe Mon Sep 17 00:00:00 2001 From: Leonard2 Date: Tue, 1 Nov 2016 04:58:10 +0100 Subject: [PATCH] Implement a general and easy-to-use way of overriding native virtual functions --- src/dobject.h | 76 ++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 75 insertions(+), 1 deletion(-) diff --git a/src/dobject.h b/src/dobject.h index dd0d40772e..fb631c91cd 100644 --- a/src/dobject.h +++ b/src/dobject.h @@ -125,8 +125,8 @@ enum EInPlace { EC_InPlace }; public: \ virtual PClass *StaticType() const; \ static ClassReg RegistrationInfo, * const RegistrationInfoPtr; \ -private: \ typedef parent Super; \ +private: \ typedef cls ThisClass; #define DECLARE_ABSTRACT_CLASS_WITH_META(cls,parent,meta) \ @@ -151,6 +151,34 @@ protected: \ #define HAS_FIELDS \ static void InitNativeFields(); +// Templates really are powerful +#define VMEXPORTED_NATIVES_START \ + template class ExportedNatives : public ExportedNatives {}; \ + template<> class ExportedNatives { \ + protected: ExportedNatives() {} \ + public: \ + static ExportedNatives *Get() { static ExportedNatives *Instance = nullptr; if (Instance == nullptr) Instance = new ExportedNatives; return Instance; } \ + ExportedNatives(const ExportedNatives&) = delete; \ + ExportedNatives(ExportedNatives&&) = delete; + +#define VMEXPORTED_NATIVES_FUNC(func) \ + template ret func(void *ptr, args ... arglist) { return ret(); } + +#define VMEXPORTED_NATIVES_END }; + +#define VMEXPORT_NATIVES_START(cls, parent) \ + template<> class ExportedNatives : public ExportedNatives { \ + protected: ExportedNatives() {} \ + public: \ + static ExportedNatives *Get() { static ExportedNatives *Instance = nullptr; if (Instance == nullptr) Instance = new ExportedNatives; return Instance; } \ + ExportedNatives(const ExportedNatives&) = delete; \ + ExportedNatives(ExportedNatives&&) = delete; + +#define VMEXPORT_NATIVES_FUNC(func) \ + template ret func(void *ptr, args ... arglist) { return static_cast(ptr)->object::##func(arglist...); } + +#define VMEXPORT_NATIVES_END(cls) }; + #if defined(_MSC_VER) # pragma section(".creg$u",read) # define _DECLARE_TI(cls) __declspec(allocate(".creg$u")) ClassReg * const cls::RegistrationInfoPtr = &cls::RegistrationInfo; @@ -576,6 +604,52 @@ protected: } }; +template +class DVMObject : public T +{ +public: + static char *FormatClassName() + { + static char *name = nullptr; + if (name == nullptr) + { + name = new char[64]; + mysnprintf(name, 64, "DVMObject<%s>", Super::RegistrationInfo.Name); + atterm([]{ delete[] DVMObject::RegistrationInfo.Name; }); + } + return name; + } + + virtual PClass *StaticType() const + { + return RegistrationInfo.MyClass; + } + static ClassReg RegistrationInfo; + static ClassReg * const RegistrationInfoPtr; + typedef T Super; + +private: + typedef DVMObject ThisClass; + static void InPlaceConstructor(void *mem) + { + new((EInPlace *)mem) DVMObject; + } +}; + +template +ClassReg DVMObject::RegistrationInfo = +{ + nullptr, + DVMObject::FormatClassName(), + &DVMObject::Super::RegistrationInfo, + nullptr, + DVMObject::InPlaceConstructor, + nullptr, + sizeof(DVMObject), + DVMObject::MetaClassNum +}; +template _DECLARE_TI(DVMObject) + // When you write to a pointer to an Object, you must call this for // proper bookkeeping in case the Object holding this pointer has // already been processed by the GC.