184 lines
		
	
	
		
			4.8 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			184 lines
		
	
	
		
			4.8 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
#pragma once
 | 
						|
#include "text.h"
 | 
						|
namespace YAML
 | 
						|
{
 | 
						|
	template<typename T>
 | 
						|
	inline string TextSerialize<T>::Serialize(const Any& any)
 | 
						|
	{
 | 
						|
		if constexpr (Check_IsString<T>) {
 | 
						|
			return string(*any.CastTo<T*>());
 | 
						|
		}
 | 
						|
		else if constexpr(Check_ToString<T>){
 | 
						|
			return std::to_string(*any.CastTo<T*>());
 | 
						|
		}
 | 
						|
		else {
 | 
						|
			return string(any.cls->name.GetView());
 | 
						|
		}
 | 
						|
	}
 | 
						|
	template<typename T>
 | 
						|
	inline bool TextSerialize<T>::Unserialize(const string& val, const Any& any)
 | 
						|
	{
 | 
						|
		if constexpr (Check_IsString<T>) {
 | 
						|
			return new (any.CastTo<T*>())T(val);
 | 
						|
		}
 | 
						|
		else if constexpr (std::is_arithmetic_v<T>) {
 | 
						|
			if constexpr (std::is_integral_v<T>) {
 | 
						|
				*any.CastTo<T*>() = std::stoul(val);
 | 
						|
				return true;
 | 
						|
			}
 | 
						|
			else if constexpr (std::is_floating_point_v<T>) {
 | 
						|
				*any.CastTo<T*>() = std::stold(val);
 | 
						|
				return true;
 | 
						|
			}
 | 
						|
		}
 | 
						|
		else {
 | 
						|
			return false;
 | 
						|
		}
 | 
						|
	}
 | 
						|
	inline StringFuncMap TextArchive::BuildStringMap()
 | 
						|
	{
 | 
						|
		StringFuncMap funcMap;
 | 
						|
#define RegisterAny(T) funcMap.emplace(&TypeInfo<T>::StaticClass, std::make_pair(&TextSerialize<T>::Serialize, &TextSerialize<T>::Unserialize))
 | 
						|
#include "register.inl"
 | 
						|
#undef RegisterAny
 | 
						|
		return funcMap;
 | 
						|
	}
 | 
						|
	template<typename T>
 | 
						|
	inline void TextArchive::Register()
 | 
						|
	{
 | 
						|
		FuncMap.emplace(&TypeInfo<T>::StaticClass, std::make_pair(&TextSerialize<T>::Serialize, &TextSerialize<T>::Unserialize));
 | 
						|
	}
 | 
						|
	inline Node TextArchive::Serialize(const Any& any)
 | 
						|
	{
 | 
						|
		if (!any) {
 | 
						|
			return {};
 | 
						|
		}
 | 
						|
		auto it = FuncMap.find(any.cls);
 | 
						|
		if (it != FuncMap.end()) {
 | 
						|
			return Node{ it->second.first(any)};
 | 
						|
		}
 | 
						|
		Node result;
 | 
						|
		if (any.cls == &refl::TypeInfo<Any>::StaticClass) {
 | 
						|
			Any obj = any.CastTo<Any>();
 | 
						|
			if (obj) {
 | 
						|
				result["__class__"] = string(obj.cls->name);
 | 
						|
				result["__data__"] = Serialize(obj);
 | 
						|
			}
 | 
						|
			return result;
 | 
						|
		}
 | 
						|
		if (any.IsContainer()) {
 | 
						|
			auto docker = any.ToContainer();
 | 
						|
			bool isMap = any.IsMap();
 | 
						|
			auto fieldList = any.ContainerValue()->GetFields(refl::FIND_ALL_MEMBER, FName(""));
 | 
						|
			for (auto obj : docker) {
 | 
						|
				if (isMap) {
 | 
						|
					Any first = obj.Member(*fieldList[0]);
 | 
						|
					Any second = obj.Member(*fieldList[1]);
 | 
						|
					result[Serialize(first)] = Serialize(second);
 | 
						|
				}
 | 
						|
				else {
 | 
						|
					result.push_back(Serialize(obj));
 | 
						|
				}
 | 
						|
			}
 | 
						|
			return result;
 | 
						|
		}
 | 
						|
		if (any.IsArray()) {
 | 
						|
			int n = any.ArraySize();
 | 
						|
			for (int i = 0; i < n; i++) {
 | 
						|
				result.push_back(Serialize(any.Member(i)));
 | 
						|
			}
 | 
						|
			return result;
 | 
						|
		}
 | 
						|
		if (Any p = any.Parent()) {
 | 
						|
			result["__parent__"] = Serialize(p);
 | 
						|
		}
 | 
						|
		auto fieldList = any.cls->GetFields(refl::FIND_ALL_MEMBER, FName(""));
 | 
						|
		for (auto& field : fieldList) {
 | 
						|
			Node child = Serialize(any.Member(field));
 | 
						|
			result[field.name.GetView()] = child;
 | 
						|
		}
 | 
						|
		return result;
 | 
						|
	}
 | 
						|
	inline bool TextArchive::Unserialize(const Node& res, const Any& any)
 | 
						|
	{
 | 
						|
		if (!any) {
 | 
						|
			return false;
 | 
						|
		}
 | 
						|
		if (res.IsNull()) {
 | 
						|
			const string& str = "";
 | 
						|
			return any.Construct(Any{ &str, &TypeInfo<string>::StaticClass });
 | 
						|
		}
 | 
						|
		auto it = FuncMap.find(any.cls);
 | 
						|
		if (it != FuncMap.end()) {
 | 
						|
			return it->second.second(res.as<string>(),any);
 | 
						|
		}
 | 
						|
		if (any.cls == &refl::TypeInfo<Any>::StaticClass) {
 | 
						|
			string name = res["__class__"].as<string>();
 | 
						|
			auto cls = refl::UClass::Find(Name(name));
 | 
						|
			if (cls) {
 | 
						|
				Any obj = cls->New();
 | 
						|
				*any.CastTo<Any*>() = obj;
 | 
						|
				return Unserialize(res["__data__"], obj);
 | 
						|
			}
 | 
						|
			*any.CastTo<Any*>() = {};
 | 
						|
			return false;
 | 
						|
		}
 | 
						|
		if (any.IsContainer()) {
 | 
						|
			auto docker = any.ToContainer();
 | 
						|
			docker.construct();
 | 
						|
			char memory[STACK_MEMORY_SIZE];
 | 
						|
			Any any = docker.try_malloc(&memory, STACK_MEMORY_SIZE);
 | 
						|
			bool isMap = res.IsMap() && any.IsMap();
 | 
						|
			Any first, second;
 | 
						|
			if (isMap) {
 | 
						|
				auto fieldList = any.ContainerValue()->GetFields(refl::FIND_ALL_MEMBER, FName(""));
 | 
						|
				first = any.Member(*fieldList.at(0));
 | 
						|
				second = any.Member(*fieldList.at(1));
 | 
						|
			}
 | 
						|
			for (auto it : res) {
 | 
						|
				if (isMap) {
 | 
						|
					Unserialize(it.first, first);
 | 
						|
					Unserialize(it.second, second);
 | 
						|
				}
 | 
						|
				else {
 | 
						|
					Unserialize(it, any);
 | 
						|
				}			
 | 
						|
				docker.insert(any);
 | 
						|
				any.Destruct();
 | 
						|
			}
 | 
						|
			docker.try_free(any, STACK_MEMORY_SIZE);
 | 
						|
			return true;
 | 
						|
		}
 | 
						|
		if (res.IsSequence() && any.IsArray()) {
 | 
						|
			for (std::size_t i = 0; i < res.size(); i++) {
 | 
						|
				Unserialize(res[i], any.Member(i));
 | 
						|
			}
 | 
						|
			return true;
 | 
						|
		}
 | 
						|
		if (res.IsMap() && any.IsObject()) {
 | 
						|
			auto fieldList = any.cls->GetFields(refl::FIND_ALL_MEMBER, FName(""));
 | 
						|
			auto rt = res.begin();
 | 
						|
			int diff = res.size() - fieldList.size();
 | 
						|
			if (diff == 1 && any.CheckParent()) {
 | 
						|
				diff = 0;
 | 
						|
				Unserialize(rt++->second, any.Parent());
 | 
						|
			}
 | 
						|
			else if (diff != 0) {
 | 
						|
				return false;
 | 
						|
			}
 | 
						|
			auto ft = fieldList.begin();
 | 
						|
			for (; ft != fieldList.end() && rt != res.end(); ++ft,++rt) {
 | 
						|
				if (ft->name != Name(rt->first.as<string>())) {
 | 
						|
					return false;
 | 
						|
				}
 | 
						|
				Unserialize(rt->second, any.Member(*ft));
 | 
						|
			}
 | 
						|
			return true;
 | 
						|
		}
 | 
						|
		if (res.IsScalar() && any.IsObject()) {
 | 
						|
			const string& str = res.as<string>();
 | 
						|
			return any.Construct(Any{&str, &TypeInfo<string>::StaticClass});
 | 
						|
		}
 | 
						|
		return false;
 | 
						|
	}
 | 
						|
} |