199 lines
5.3 KiB
C++
199 lines
5.3 KiB
C++
#pragma once
|
|
#include "type.h"
|
|
#include "field.h"
|
|
#include "object.h"
|
|
namespace refl {
|
|
class UClass{
|
|
using enum FieldFlag;
|
|
public:
|
|
Name name;
|
|
uint32_t size;
|
|
UClass* parent;
|
|
public:
|
|
constexpr UClass(Name name, uint32_t size, UClass* parent = nullptr)
|
|
:name(name),size(size), parent(parent){}
|
|
ObjectView New(void* ptr = nullptr) const{
|
|
if (ptr == nullptr) {
|
|
ptr = malloc(size);
|
|
InitObject(ptr);
|
|
}
|
|
return { ptr , this };
|
|
}
|
|
template<typename T>
|
|
T* New(T* ptr = nullptr) const{
|
|
if (!IsChildOf<T>()) {
|
|
return nullptr;
|
|
}
|
|
if (ptr == nullptr) {
|
|
ptr = (T*)malloc(size);
|
|
}
|
|
InitObject(ptr);
|
|
return ptr;
|
|
}
|
|
template<typename T>
|
|
bool IsChildOf(bool bthis = false) const {
|
|
constexpr UClass* cls = &TypeInfo<T>::StaticClass;
|
|
if (bthis) {
|
|
return cls == this;
|
|
}
|
|
const UClass* _parent = this;
|
|
while (_parent != nullptr) {
|
|
if (_parent == cls) {
|
|
return true;
|
|
}
|
|
_parent = _parent->parent;
|
|
}
|
|
return false;
|
|
}
|
|
//unsafe if called by other, need check class && size
|
|
virtual void InitObject(void* ptr)const {
|
|
memset(ptr, 0, size);
|
|
}
|
|
virtual const FieldPtr* GetField(const Name& name)const {
|
|
return nullptr;
|
|
}
|
|
protected:
|
|
template<uint32_t offset, typename T,typename U>
|
|
FieldPtr MakeMemberField(T U::* ptr, Name name) {
|
|
FieldPtr::Data member = { offset };
|
|
constexpr uint32_t flag = FIELD_MEMBER_FLAG | FIELD_ATTRIBUTE_FLAG;
|
|
return { name, &TypeInfo<T>::StaticClass, {member}, flag };
|
|
}
|
|
template<typename R, typename ...Args>
|
|
FieldPtr MakeMethodField(R (* ptr)(Args...), Name name) {
|
|
FieldPtr::Data member = { *(void**)&ptr };
|
|
constexpr uint32_t flag = FIELD_METHOD_FLAG;
|
|
return { name, &TypeInfo<decltype(ptr)>::StaticClass, {member},flag };
|
|
}
|
|
template<typename T, typename R, typename ...Args>
|
|
FieldPtr MakeMethodField(R(T::* ptr)(Args...), Name name) {
|
|
FieldPtr::Data member = { *(void**)&ptr };
|
|
constexpr uint32_t flag = FIELD_MEMBER_FLAG | FIELD_METHOD_FLAG;
|
|
return { name, &TypeInfo<R(*)(Args...)>::StaticClass, {member},flag };
|
|
}
|
|
};
|
|
template<_ReflCheck_Ctor T>
|
|
class UClass_Auto : public UClass{
|
|
public:
|
|
using UClass::UClass;
|
|
protected:
|
|
void InitObject(void* ptr)const override {
|
|
constexpr bool is_shallow_copyable = std::is_trivially_copyable<T>::value;
|
|
if constexpr (!is_shallow_copyable){
|
|
T obj{};
|
|
std::construct_at((T*)ptr, obj);
|
|
}
|
|
else {
|
|
memset(ptr, 0, size);
|
|
}
|
|
}
|
|
public:
|
|
static UClass_Auto<T> BuildClass() {
|
|
auto cls = UClass_Auto<T>(type_name<T>().View(), sizeof(T));
|
|
return cls;
|
|
}
|
|
};
|
|
template<_ReflCheck_Ctor_NoUClass T>
|
|
struct TypeInfo<T> {
|
|
using UClass = UClass_Auto<T>;
|
|
inline static UClass StaticClass = UClass::BuildClass();
|
|
};
|
|
template<typename R, typename... Args>
|
|
class UMethod_Auto : public UClass {
|
|
using UClass::UClass;
|
|
using MethodType = R(*)(Args...);
|
|
public:
|
|
std::array<UClass*, sizeof...(Args) + 1> UList;
|
|
public:
|
|
static UMethod_Auto<R,Args...> BuildClass() {
|
|
auto cls = UMethod_Auto<R, Args...>(type_name<MethodType>().View(), sizeof(MethodType));
|
|
if constexpr(!std::is_same<R, void>::value) {
|
|
cls.UList[0] = &TypeInfo<R>::StaticClass;
|
|
}
|
|
if (sizeof...(Args) > 0) {
|
|
auto ptr = &cls.UList[1];
|
|
(...,(*ptr = &TypeInfo<Args>::StaticClass, ptr++));
|
|
}
|
|
return cls;
|
|
}
|
|
};
|
|
// 函数指针类型的偏特化
|
|
template<typename R, typename... Args>
|
|
struct TypeInfo<R(*)(Args...)> {
|
|
using UClass = UMethod_Auto<R,Args...>;
|
|
inline static UClass StaticClass = UClass::BuildClass();
|
|
};
|
|
template<typename T>
|
|
inline bool ObjectView::Get(const Name& name, T& t)
|
|
{
|
|
if (cache && cache->name == name) {
|
|
_cache_get: bool isChild = cache->type->IsChildOf<T>(true);
|
|
if (isChild) {
|
|
t = *(T*)(ptr + std::get<uint32_t>(cache->data));
|
|
}
|
|
return isChild;
|
|
}
|
|
auto field = cls->GetField(name);
|
|
if (field) {
|
|
cache = field;
|
|
goto _cache_get;
|
|
}
|
|
return false;
|
|
}
|
|
template<typename T>
|
|
inline bool ObjectView::Set(const Name& name, const T& t)
|
|
{
|
|
if (cache && cache->name == name) {
|
|
|
|
_cache_set: bool isChild = cache->type->IsChildOf<T>(true);
|
|
if (isChild) {
|
|
*(T*)(ptr + std::get<uint32_t>(cache->data)) = t;
|
|
}
|
|
return isChild;
|
|
}
|
|
auto field = cls->GetField(name);
|
|
if (field) {
|
|
cache = field;
|
|
goto _cache_set;
|
|
}
|
|
return false;
|
|
}
|
|
template<typename ...Args>
|
|
bool ObjectView::Invoke(const Name& name, Args... args)
|
|
{
|
|
auto field = cls->GetField(name);
|
|
if (!field) {
|
|
return false;
|
|
}
|
|
if (field->flag & FIELD_MEMBER_FLAG) {
|
|
using MemberMethodType = void(*)(const void*, Args...);
|
|
MemberMethodType fptr = (MemberMethodType)std::get<void*>(field->data);
|
|
fptr(ptr, args...);
|
|
}
|
|
else {
|
|
using MethodType = void(*)(Args...);
|
|
MethodType fptr = (MethodType)std::get<void*>(field->data);
|
|
fptr(args...);
|
|
}
|
|
return true;
|
|
}
|
|
template<typename R, typename ...Args>
|
|
inline bool ObjectView::InvokeRet(const Name& name, R& ret, Args ...args)
|
|
{
|
|
auto field = cls->GetField(name);
|
|
if (!field) {
|
|
return false;
|
|
}
|
|
if (field->flag & FIELD_MEMBER_FLAG) {
|
|
using MemberMethodType = R(*)(const void*, Args...);
|
|
MemberMethodType fptr = (MemberMethodType)std::get<void*>(field->data);
|
|
ret = fptr(ptr, args...);
|
|
}
|
|
else {
|
|
using MethodType = R(*)(Args...);
|
|
MethodType fptr = (MethodType)std::get<void*>(field->data);
|
|
ret = fptr(args...);
|
|
}
|
|
return true;
|
|
}
|
|
} |