300 lines
		
	
	
		
			7.2 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			300 lines
		
	
	
		
			7.2 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
#pragma once
 | 
						||
#include "uclass.h"
 | 
						||
#include "view.h"
 | 
						||
#include "convert.h"
 | 
						||
namespace refl {
 | 
						||
	using enum ClassFlag;
 | 
						||
	inline bool Any::CheckParent() const
 | 
						||
	{
 | 
						||
		return cls->flag & CLASS_PARENT_FLAG;
 | 
						||
	}
 | 
						||
	inline bool Any::Check(const UClass* toClass) const{
 | 
						||
		if (cls == toClass) {
 | 
						||
			return true;
 | 
						||
		}
 | 
						||
		if (!cls) {
 | 
						||
			return false;
 | 
						||
		}
 | 
						||
		return cls->IsChildOf(toClass);
 | 
						||
	}
 | 
						||
	inline constexpr int Any::Size()const
 | 
						||
	{
 | 
						||
		return cls->size;
 | 
						||
	}
 | 
						||
	inline Any Any::Parent()const
 | 
						||
	{
 | 
						||
		if (!(cls->flag & CLASS_PARENT_FLAG)) {
 | 
						||
			return {};
 | 
						||
		}
 | 
						||
		return Any{ptr, cls->parent };
 | 
						||
	}
 | 
						||
	inline const UClass* Any::ContainerValue() const
 | 
						||
	{
 | 
						||
		if (!IsContainer()) {
 | 
						||
			return nullptr;
 | 
						||
		}
 | 
						||
		return cls->parent;
 | 
						||
	}
 | 
						||
	inline Any Any::Member(const FieldPtr& field)const
 | 
						||
	{
 | 
						||
		if (field.flag & FIELD_MEMBER_FLAG) {
 | 
						||
			return { (const char*)ptr + field.data.member.offset, field.type };
 | 
						||
		}
 | 
						||
		return {};
 | 
						||
	}
 | 
						||
	inline Any Any::Member(int i) const
 | 
						||
	{
 | 
						||
		if (cls->flag & CLASS_ARRAY_FLAG) {
 | 
						||
			int offset = i * cls->parent->size;
 | 
						||
			if(offset < cls->size)
 | 
						||
				return { (const char*)ptr + offset, cls->parent };
 | 
						||
		}
 | 
						||
		return Any();
 | 
						||
	}
 | 
						||
	inline int Any::ArraySize()const
 | 
						||
	{
 | 
						||
		if (cls->flag & CLASS_ARRAY_FLAG) {
 | 
						||
			return cls->size / cls->parent->size;
 | 
						||
		}
 | 
						||
		return 0;
 | 
						||
	}
 | 
						||
	inline bool Any::IsArray() const
 | 
						||
	{
 | 
						||
		return cls->flag & CLASS_ARRAY_FLAG;
 | 
						||
	}
 | 
						||
	inline bool Any::IsObject() const
 | 
						||
	{
 | 
						||
		return !(cls->flag & CLASS_ARRAY_FLAG) && !(cls->flag & CLASS_POINTER_FLAG);
 | 
						||
	}
 | 
						||
	inline bool Any::IsContainer() const
 | 
						||
	{
 | 
						||
		return cls->flag & CLASS_CONTAINER_FLAG;
 | 
						||
	}
 | 
						||
	inline bool Any::IsSequence() const
 | 
						||
	{
 | 
						||
		return cls->flag & CLASS_SEQUENCE_FLAG;
 | 
						||
	}
 | 
						||
	inline bool Any::IsMap() const
 | 
						||
	{
 | 
						||
		return cls->flag & CLASS_MAP_FLAG;
 | 
						||
	}
 | 
						||
	inline bool Any::Construct(const sarray<Any>& ArgsList) const
 | 
						||
	{
 | 
						||
		return cls->Construct((void*)ptr, ArgsList);
 | 
						||
	}
 | 
						||
	inline void Any::Destruct() const
 | 
						||
	{
 | 
						||
		cls->Destruct((void*)ptr);
 | 
						||
	}
 | 
						||
	inline void Any::CopyTo(void* ptr)const
 | 
						||
	{
 | 
						||
		Any to{ ptr, cls };
 | 
						||
		auto fieldList = cls->GetFields(refl::FIND_ALL_MEMBER, FName(""));
 | 
						||
		for (auto field : fieldList) {
 | 
						||
			Any obj = to.Member(field);
 | 
						||
			Convert::Construct(obj, Member(field));
 | 
						||
		}
 | 
						||
	}
 | 
						||
	inline AnyArgs::AnyArgs(const sarray<Any>& args, const sarray<const UClass*>& params, void* memory)
 | 
						||
		: data(memory), num(args.size()), size(GetArgsSize(args, params))
 | 
						||
	{
 | 
						||
		assert(size > 0);
 | 
						||
		if (!memory) {
 | 
						||
			isMemoryOwner = true;
 | 
						||
			data = malloc(size);
 | 
						||
		}
 | 
						||
		Any* any = (Any*)data;
 | 
						||
		assert(any != nullptr);
 | 
						||
		char* pData = ((char*)data) + num * sizeof(Any);
 | 
						||
		auto uptr = params.at(params.size() - args.size());
 | 
						||
		for (auto& arg : args) {
 | 
						||
			any->cls = *uptr;
 | 
						||
			any->ptr = pData;
 | 
						||
			assert(Convert::Construct(*any, arg));
 | 
						||
			any++;
 | 
						||
			pData += (*uptr)->size;
 | 
						||
		}
 | 
						||
	}
 | 
						||
	inline AnyArgs::~AnyArgs()
 | 
						||
	{
 | 
						||
		if (num == 0 || !data) {
 | 
						||
			return;
 | 
						||
		}
 | 
						||
		if (isMemoryOwner) {
 | 
						||
			Any* any = (Any*)data;
 | 
						||
			for (int i = 0; i < num; i++) {
 | 
						||
				any->cls->Destruct((void*)any->ptr);
 | 
						||
				any++;
 | 
						||
			}
 | 
						||
			free(data);
 | 
						||
		}
 | 
						||
		num = 0;
 | 
						||
		data = nullptr;
 | 
						||
	}
 | 
						||
	inline int AnyArgs::Size()
 | 
						||
	{
 | 
						||
		return size;
 | 
						||
	}
 | 
						||
	inline const sarray<Any> AnyArgs::ToSArray()
 | 
						||
	{
 | 
						||
		return sarray<Any>((Any*)data, num);
 | 
						||
	}
 | 
						||
	inline constexpr Offset AnyArgs::GetArgsSize(const sarray<Any>& args,const sarray<const UClass*>& params)
 | 
						||
	{	//这里空间换时间,Any多占用了一个数据指针
 | 
						||
		if (args.size() == 0 || params.size() < args.size() + 1) {
 | 
						||
			return 0;
 | 
						||
		}
 | 
						||
		Offset offset = args.size() * sizeof(Any);
 | 
						||
		auto uptr = params.at(params.size() - args.size());
 | 
						||
		for (auto uend = params.back(); uptr < uend; uptr++) {
 | 
						||
			offset += (*uptr)->size;//数据大小
 | 
						||
		}
 | 
						||
		return offset;
 | 
						||
	}
 | 
						||
	template<typename ...Args>
 | 
						||
	inline consteval Offset AnyArgs::GetArgsSize(const sarray<Any>& args)
 | 
						||
	{
 | 
						||
		constexpr int N = sizeof...(Args);
 | 
						||
		if (args.size() == 0 || N < args.size() + 1) {
 | 
						||
			return 0;
 | 
						||
		}
 | 
						||
		int first = N - args.size();
 | 
						||
		Offset offset = args.size() * sizeof(Any);
 | 
						||
		offset += fetch_tuple_size<std::tuple<Args...>>(std::index_sequence_for<Args...>{}, first);
 | 
						||
		return 0;
 | 
						||
	}
 | 
						||
	template<typename T>
 | 
						||
	inline bool AnyView::Get(const Name& name, T& t)
 | 
						||
	{
 | 
						||
		if (cache && cache->name == name) {
 | 
						||
		_cache_get: bool isChild = cache->type->IsChildOf<T>();
 | 
						||
			if (isChild) {
 | 
						||
				t = *(T*)((const char*)ptr + cache->data.member.offset);
 | 
						||
			}
 | 
						||
			return isChild;
 | 
						||
		}
 | 
						||
		auto& fieldList = cls->GetFields(EFieldFind::FIND_MEMBER, name);
 | 
						||
		if (fieldList.valid()) {
 | 
						||
			cache = fieldList.front();
 | 
						||
			goto _cache_get;
 | 
						||
		}
 | 
						||
		if (cls->parent) {
 | 
						||
			return Parent().Get(name, t);
 | 
						||
		}
 | 
						||
		return false;
 | 
						||
	}
 | 
						||
	template<typename T>
 | 
						||
	inline bool AnyView::Set(const Name& name, const T& t)
 | 
						||
	{
 | 
						||
		if (cache && cache->name == name) {
 | 
						||
		_cache_set: bool isChild = cache->type->IsChildOf<T>();
 | 
						||
			if (isChild) {
 | 
						||
				*(T*)((const char*)ptr + cache->data.member.offset) = t;
 | 
						||
			}
 | 
						||
			return isChild;
 | 
						||
		}
 | 
						||
		auto& fieldList = cls->GetFields(EFieldFind::FIND_MEMBER, name);
 | 
						||
		if (fieldList.valid()) {
 | 
						||
			cache = fieldList.front();
 | 
						||
			goto _cache_set;
 | 
						||
		}
 | 
						||
		if (cls->parent) {
 | 
						||
			return Parent().Set(name, t);
 | 
						||
		}
 | 
						||
		return false;
 | 
						||
	}
 | 
						||
	inline bool AnyView::Invoke(const Name& name,const sarray<Any>& ArgsList)
 | 
						||
	{
 | 
						||
		auto& fieldList = cls->GetFields(EFieldFind::FIND_METHOD, name);
 | 
						||
		if (fieldList.empty()) {
 | 
						||
			if (cls->parent) {
 | 
						||
				return Parent().Invoke(name, ArgsList);
 | 
						||
			}
 | 
						||
			return false;
 | 
						||
		}
 | 
						||
		return fieldList[0]->Invoke(ArgsList);
 | 
						||
	}
 | 
						||
	inline bool AnyView::Invoke(const Name& name, svector<Any>& ArgsList)
 | 
						||
	{
 | 
						||
		auto fieldList = cls->GetFields(EFieldFind::FIND_METHOD, name);
 | 
						||
		if (fieldList.empty()) {
 | 
						||
			if (cls->parent) {
 | 
						||
				return Parent().Invoke(name, ArgsList);
 | 
						||
			}
 | 
						||
			return false;
 | 
						||
		}
 | 
						||
		return fieldList[0]->Invoke(ArgsList);
 | 
						||
	}
 | 
						||
	inline bool AnyView::Invokes(const Name& name, const sarray<Any>& ArgsList)
 | 
						||
	{
 | 
						||
		auto fieldList = cls->GetFields(EFieldFind::FIND_METHOD, name);
 | 
						||
		if (fieldList.empty()) {
 | 
						||
			if (cls->parent) {
 | 
						||
				return Parent().Invoke(name, ArgsList);
 | 
						||
			}
 | 
						||
			return false;
 | 
						||
		}
 | 
						||
		if(fieldList.size() == 1)
 | 
						||
			return fieldList[0]->Invoke(ArgsList);
 | 
						||
		for (auto& field : fieldList) {
 | 
						||
			if (field.Invokes(ArgsList)) {
 | 
						||
				return true;
 | 
						||
			}
 | 
						||
		}
 | 
						||
		return false;
 | 
						||
	}
 | 
						||
	inline bool AnyView::Invokes(const Name& name, svector<Any>& ArgsList)
 | 
						||
	{
 | 
						||
		auto fieldList = cls->GetFields(EFieldFind::FIND_METHOD, name);
 | 
						||
		if (fieldList.empty()) {
 | 
						||
			if (cls->parent) {
 | 
						||
				return Parent().Invoke(name, ArgsList);
 | 
						||
			}
 | 
						||
			return false;
 | 
						||
		}
 | 
						||
		if (fieldList.size() == 1)
 | 
						||
			return fieldList[0]->Invoke(ArgsList);
 | 
						||
		for (auto& field : fieldList) {
 | 
						||
			if (field.Invokes(ArgsList)) {
 | 
						||
				return true;
 | 
						||
			}
 | 
						||
		}
 | 
						||
		return false;
 | 
						||
	}
 | 
						||
	inline AnyView AnyView::Parent() {
 | 
						||
		return { ptr, cls ? cls->parent : nullptr };
 | 
						||
	}
 | 
						||
	inline bool UClass::Construct(void* ptr, const sarray<Any>& ArgsList) const
 | 
						||
	{
 | 
						||
		if (vtable.Construct) {
 | 
						||
			if (vtable.Construct(ptr, this, ArgsList)) {
 | 
						||
				return true;
 | 
						||
			}
 | 
						||
			auto& fieldList = GetFields(EFieldFind::FIND_CTOR, FName("Ctor"));
 | 
						||
			if (fieldList.empty()) {
 | 
						||
				return false;
 | 
						||
			}
 | 
						||
			std::array<Any, 10> ArgsArray = { Any{} , Any{ptr} };
 | 
						||
			int i = 2;
 | 
						||
			for (auto& arg : ArgsList) {
 | 
						||
				ArgsArray[i++] = arg;
 | 
						||
			}
 | 
						||
			sarray<Any> FieldArgs(&ArgsArray[0], 2 + ArgsList.size());
 | 
						||
			if (fieldList.size() == 1) {
 | 
						||
				return fieldList[0]->Invoke(FieldArgs);
 | 
						||
			}
 | 
						||
			for (auto& field : fieldList) {
 | 
						||
				if (field.Invokes(FieldArgs)) {
 | 
						||
					return true;
 | 
						||
				}
 | 
						||
			}
 | 
						||
			return false;
 | 
						||
		}
 | 
						||
		if (ArgsList.valid() && ArgsList[0]->Check(this)) {
 | 
						||
			memcpy(ptr, ArgsList[0]->ptr, size);
 | 
						||
			return true;
 | 
						||
		}
 | 
						||
		memset(ptr, 0, size);
 | 
						||
		return true;
 | 
						||
	}
 | 
						||
} |