358 lines
10 KiB
C++
358 lines
10 KiB
C++
#include "uclass.h"
|
|
#include "name.h"
|
|
#include "type.h"
|
|
namespace refl {
|
|
template<typename T>
|
|
class UClass_Auto : public UClass {
|
|
public:
|
|
UClass_Auto() : UClass(meta_name<T>(), sizeof(T)) {
|
|
if constexpr (std::is_pointer_v<T>) {
|
|
using RT = std::remove_pointer_t<T>;
|
|
flag |= CLASS_POINTER_FLAG;
|
|
if constexpr (!std::is_same_v<RT, void>) {
|
|
parent = meta_info<RT>();
|
|
}
|
|
}
|
|
else if constexpr (is_array_v<T>) {
|
|
using RT = is_array_t<T>;
|
|
flag = CLASS_ARRAY_FLAG;
|
|
if constexpr (std::is_pointer_v<RT>) {
|
|
flag |= CLASS_POINTER_FLAG;
|
|
}
|
|
parent = meta_info<RT>();
|
|
}
|
|
else {
|
|
if constexpr (std::is_enum_v<T>) {
|
|
flag = CLASS_ENUM_FLAG;
|
|
parent = meta_info<std::underlying_type_t<T>>();
|
|
}
|
|
vtable.AddConstruct(&UClass::Construct<T>);
|
|
vtable.AddDestruct(&UClass::Destruct<T>);
|
|
}
|
|
}
|
|
};
|
|
/*
|
|
* 模板优化
|
|
* 成员参数转化为const void*
|
|
* 引用参数转化为指针
|
|
* 返回引用转化为指针
|
|
*/
|
|
template<typename R, typename... Args>
|
|
class UMethod_Auto : public UClass {
|
|
using MethodType = R(*)(Args...);
|
|
public:
|
|
std::array<const UClass*, sizeof...(Args) + 1> UList{};
|
|
UMethod_Auto() : UClass(meta_name<MethodType>(), sizeof(MethodType)) {
|
|
flag = CLASS_TRIVIAL_FLAG;
|
|
vtable.AddGetParams(&UMethod_Auto::GetParams);
|
|
vtable.AddCall(&UMethod_Auto::Call);
|
|
if constexpr (!std::is_same_v<R, void>) {
|
|
UList[0] = meta_info<R>();
|
|
}
|
|
if constexpr (sizeof...(Args) > 0) {
|
|
auto ptr = &UList[1];
|
|
(..., (*ptr = meta_info<Args>(), ptr++));
|
|
}
|
|
}
|
|
//这里顺序似乎是不确定的,但是我实际运用是对的
|
|
//如果使用make_index_sequence,会多一次函数调用
|
|
//为什么包裹一层迭代器,就不会出现警告了
|
|
static void Call(const FieldPtr* field, span<Any> ArgsList) {
|
|
assert(sizeof...(Args) < ArgsList.size());
|
|
auto param = ArgsList.end() - 1;
|
|
if constexpr (std::is_same_v<R, void>) {
|
|
MethodType fptr = (MethodType)field->data.method.fptr;
|
|
fptr((param--->CastTo<Args>())...);
|
|
}
|
|
else {
|
|
MethodType fptr = (MethodType)field->data.method.fptr;
|
|
auto& ret = ArgsList.front();
|
|
if (ret.cls == meta_info<R>()) {
|
|
*(R*)ret.ptr = fptr((param--->CastTo<Args>())...);
|
|
}
|
|
else {
|
|
fptr((param--->CastTo<Args>())...);
|
|
}
|
|
}
|
|
}
|
|
static span<const UClass*> GetParams(const UClass* cls) {
|
|
auto& UList = ((UMethod_Auto*)cls)->UList;
|
|
return span<const UClass*>{UList};
|
|
}
|
|
};
|
|
class UClass_Container_Impl : public UClass {
|
|
public:
|
|
using UClass::UClass;
|
|
struct iterator {
|
|
void* ptr;
|
|
void* val;
|
|
};
|
|
//container
|
|
using size_impl = size_t(*)(const void*);
|
|
using to_iterator_impl = void(*)(iterator&, const void*);
|
|
using insert_impl = void (*)(const void*, const void*);
|
|
//iterator
|
|
using iterator_impl = void (*)(iterator*);
|
|
public:
|
|
size_impl vsize;
|
|
to_iterator_impl vbegin;
|
|
to_iterator_impl vend;
|
|
insert_impl vinsert;
|
|
iterator_impl viterator_add;
|
|
iterator_impl viterator_sub;
|
|
template<typename T>
|
|
static void insert(const void* ptr, const void* obj) {
|
|
using value_type = typename T::value_type;
|
|
if constexpr (is_sequence_v<T>) {
|
|
((T*)ptr)->push_back(*(value_type*)obj);
|
|
}
|
|
else if constexpr (is_map_v<T>) {
|
|
((T*)ptr)->insert(*(value_type*)obj);
|
|
}
|
|
}
|
|
};
|
|
template<is_container_v T, typename value_type>
|
|
class UClass_Container : public UClass_Container_Impl {
|
|
public:
|
|
static bool construct(void* ptr, const UClass* cls, span<Any> ArgsList) {
|
|
new(ptr)T();
|
|
return true;
|
|
}
|
|
static void destruct(void* ptr) {
|
|
((T*)ptr)->~T();
|
|
}
|
|
static void begin(iterator& pit, const void* ptr) {
|
|
auto it = ((T*)ptr)->begin();
|
|
memcpy(&pit, &it, sizeof(it));
|
|
pit.val = &*it;
|
|
}
|
|
static void end(iterator& pit, const void* ptr) {
|
|
auto it = ((T*)ptr)->end();
|
|
memcpy(&pit, &it, sizeof(it));
|
|
pit.val = &*it;
|
|
}
|
|
static void add(iterator* pit) {
|
|
auto it = ++(*(typename T::iterator*)pit);
|
|
memcpy(pit, &it, sizeof(it));
|
|
pit->val = &*it;
|
|
}
|
|
static void sub(iterator* pit) {
|
|
auto it = --(*(typename T::iterator*)pit);
|
|
memcpy(pit, &it, sizeof(it));
|
|
pit->val = &*it;
|
|
}
|
|
UClass_Container() : UClass_Container_Impl(meta_name<T>(), sizeof(T)) {
|
|
parent = meta_info<value_type>();
|
|
flag = CLASS_CONTAINER_FLAG;
|
|
vtable.AddConstruct(&UClass_Container::construct);
|
|
vtable.AddDestruct(&UClass_Container::destruct);
|
|
if constexpr (is_sequence_v<T>) {
|
|
flag |= CLASS_SEQUENCE_FLAG;
|
|
}
|
|
else if constexpr (is_map_v<T>)
|
|
{
|
|
flag |= CLASS_MAP_FLAG;
|
|
}
|
|
auto p_size = &T::size;
|
|
vsize = *(size_impl*)&p_size;
|
|
vbegin = &UClass_Container::begin;
|
|
vend = &UClass_Container::end;
|
|
vinsert = &UClass_Container::insert<T>;
|
|
|
|
viterator_add = &UClass_Container::add;
|
|
viterator_sub = &UClass_Container::sub;
|
|
};
|
|
};
|
|
template<typename T, typename MetaImpl>
|
|
class UClass_Meta : public UClass {
|
|
using FieldsType = decltype(MetaImpl::MakeFields());
|
|
public:
|
|
FieldsType Fields{ MetaImpl::MakeFields() };
|
|
UClass_Meta() : UClass(meta_name<T>(), sizeof(T)) {
|
|
if constexpr (has_parent_v<T>) {
|
|
parent = meta_info<parent_t<T>>();
|
|
}
|
|
vtable.AddGetFields(&UClass_Meta::GetFields);
|
|
vtable.AddConstruct(&UClass::Construct<T>);
|
|
}
|
|
span<const FieldPtr> GetFields(EFieldFind find, const Name& name) const {
|
|
constexpr int length = std::tuple_size<FieldsType>::value;
|
|
constexpr int MemberCount = MetaImpl::MemberCount();
|
|
constexpr int AllMemberCount = MemberCount + MetaImpl::StaticMemberCount();
|
|
constexpr int CtorCount = MetaImpl::CtorCount();
|
|
switch (find) {
|
|
case EFieldFind::FIND_ALL_FIELD:
|
|
return span<const FieldPtr>(&Fields[0], length);
|
|
case EFieldFind::FIND_ALL_MEMBER:
|
|
return span<const FieldPtr>(&Fields[0], MemberCount);
|
|
case EFieldFind::FIND_ALL_MEMBER_WITH_STATIC:
|
|
return span<const FieldPtr>(&Fields[0], AllMemberCount);
|
|
case EFieldFind::FIND_ALL_METHOD:
|
|
return span<const FieldPtr>(&Fields[AllMemberCount + CtorCount], length - AllMemberCount - CtorCount);
|
|
case EFieldFind::FIND_CTOR:
|
|
return span<const FieldPtr>(&Fields[AllMemberCount], CtorCount);
|
|
case EFieldFind::FIND_FIELD:
|
|
for (int i = 0; i < length; i++) {
|
|
if (name == Fields[i].name) {
|
|
return span<const FieldPtr>(&Fields[i], 1);
|
|
}
|
|
}
|
|
return {};
|
|
case EFieldFind::FIND_MEMBER:
|
|
for (int i = 0; i < AllMemberCount; i++) {
|
|
if (name == Fields[i].name) {
|
|
return span<const FieldPtr>(&Fields[i], 1);
|
|
}
|
|
}
|
|
return {};
|
|
case EFieldFind::FIND_METHOD:
|
|
for (int i = AllMemberCount + CtorCount; i < length; i++) {
|
|
if (name == Fields[i].name) {
|
|
return span<const FieldPtr>(&Fields[i], 1);
|
|
}
|
|
}
|
|
return {};
|
|
case EFieldFind::FIND_METHODS:
|
|
{
|
|
int first = 0, count = 0;
|
|
for (int i = AllMemberCount + CtorCount; i < length; i++) {
|
|
if (name == Fields[i].name) {
|
|
if (!count) {
|
|
first = i;
|
|
}
|
|
count++;
|
|
}
|
|
else if (count) {
|
|
return span<const FieldPtr>(&Fields[first], count);
|
|
}
|
|
}
|
|
return {};
|
|
}
|
|
default:
|
|
return {};
|
|
}
|
|
}
|
|
static span<const FieldPtr> GetFields(const UClass* _cls, EFieldFind find, Name name) {
|
|
auto cls = static_cast<const UClass_Meta*>(_cls);
|
|
return cls->GetFields(find, name);
|
|
}
|
|
};
|
|
template<typename T>
|
|
struct meta_info_impl {
|
|
static UClass* create() {
|
|
return new(MetaGlobalPool()) UClass_Auto<T>{};
|
|
}
|
|
};
|
|
template<typename R, typename... Args>
|
|
struct meta_info_impl<R(*)(Args...)> {
|
|
static UClass* create() {
|
|
return new(MetaGlobalPool()) UMethod_Auto<R, Args...>{};
|
|
}
|
|
};
|
|
template<is_container_v T>
|
|
struct meta_info_impl<T> {
|
|
static UClass* create() {
|
|
return new(MetaGlobalPool()) UClass_Container<T, typename T::value_type>{};
|
|
}
|
|
};
|
|
struct MetaClasses {
|
|
size_t hash{ 0 };
|
|
const UClass* cls{nullptr};
|
|
MetaClasses* next{ nullptr };
|
|
};
|
|
using __tClassTable = table<Name, const UClass*>;
|
|
UNIQUER_INLINE(__tClassTable, ClassTable, "refl::ClassTable")
|
|
using __tMetaClassTable = table<Name, MetaClasses>;
|
|
UNIQUER_INLINE(__tMetaClassTable, MetaClassTable, "refl::MetaClassTable")
|
|
inline const UClass* find_info(Name name) {
|
|
auto& ClassTable = UNIQUER_VAL(ClassTable);
|
|
if (auto it = ClassTable.find(name); it != ClassTable.end()) {
|
|
return it->second;
|
|
}
|
|
return nullptr;
|
|
}
|
|
inline const UClass* find_info(Name name, size_t hash) {
|
|
auto& MetaClassTable = UNIQUER_VAL(MetaClassTable);
|
|
if (auto it = MetaClassTable.find(name); it != MetaClassTable.end()) {
|
|
auto meta = &it->second;
|
|
while (meta) {
|
|
if (meta->hash == hash) {
|
|
return meta->cls;
|
|
}
|
|
meta = meta->next;
|
|
}
|
|
}
|
|
return nullptr;
|
|
}
|
|
template<typename Type>
|
|
inline const UClass* meta_info()
|
|
{
|
|
using T = real_type_t<Type>;
|
|
auto name = meta_name<T>();
|
|
if (auto cls = find_info(name)) {
|
|
return cls;
|
|
}
|
|
UClass* cls;
|
|
if constexpr (is_meta_v<T>){
|
|
cls = new(MetaGlobalPool()) UClass_Meta<T, meta_t<T>>{};
|
|
}
|
|
else if constexpr (std::is_same_v<T, void>) {
|
|
cls = new(MetaGlobalPool()) UClass{ name, 0 };
|
|
}
|
|
else {
|
|
cls = meta_info_impl<T>::create();
|
|
}
|
|
auto& ClassTable = UNIQUER_VAL(ClassTable);
|
|
ClassTable[name] = cls;
|
|
return cls;
|
|
}
|
|
template<typename T, size_t hash>
|
|
inline const UClass* meta_info()
|
|
{
|
|
if constexpr (have_meta_impl_v<T, hash>) {
|
|
auto name = meta_name<T>();
|
|
const UClass* cls = find_info(name, hash);
|
|
if (cls) {
|
|
return cls;
|
|
}
|
|
cls = new(MetaGlobalPool()) UClass_Meta<T, gen::MetaImpl<T, hash>>{};
|
|
auto& MetaClassTable = UNIQUER_VAL(MetaClassTable);
|
|
if (auto it = MetaClassTable.find(name); it != MetaClassTable.end()) {
|
|
auto meta = &it->second;
|
|
while (meta) {
|
|
if (!meta->next) {
|
|
meta->next = new (MetaGlobalPool()) MetaClasses{ hash, cls };
|
|
break;
|
|
}
|
|
meta = meta->next;
|
|
}
|
|
}
|
|
else {
|
|
MetaClassTable.emplace(name, MetaClasses{hash, cls});
|
|
}
|
|
return cls;
|
|
}
|
|
else {
|
|
return meta_info<T>();
|
|
}
|
|
}
|
|
template<typename T, size_t index = 0>
|
|
inline void register_meta()
|
|
{
|
|
if constexpr (is_metas_v<T>) {
|
|
constexpr auto metaList = Meta<T>::MetaList();
|
|
meta_info<T, metaList[index]> ();
|
|
if constexpr (index + 1 < metaList.size()) {
|
|
register_meta<T, index + 1>();
|
|
}
|
|
}
|
|
meta_info<T>();
|
|
}
|
|
inline const UClass* find_meta(Name name, size_t hash) {
|
|
auto it = find_info(name);
|
|
if (it) {
|
|
return it->GetMeta(hash);
|
|
}
|
|
return nullptr;
|
|
}
|
|
} |