serde refl rebuild

This commit is contained in:
ouczbs 2024-07-27 14:24:46 +08:00
parent 0a5cb27b27
commit 5b5c35a5ef
33 changed files with 551 additions and 274 deletions

View File

@ -4,6 +4,7 @@
#include "json/serde.inl" #include "json/serde.inl"
namespace api { namespace api {
using meta::result; using meta::result;
using std::string_view;
enum class SerializeError : char enum class SerializeError : char
{ {
EMPTY, EMPTY,
@ -11,11 +12,13 @@ namespace api {
}; };
template<typename T> template<typename T>
inline bool JsonDeserialize(string_view text, T* obj) { inline bool JsonDeserialize(string_view text, T* obj) {
if (text.empty()) return false;
yyjson_alc alc = JsonAllocatorAdapter(); yyjson_alc alc = JsonAllocatorAdapter();
yyjson_doc* doc = yyjson_read_opts((char*)text.data(), text.size(), YYJSON_READ_INSITU, &alc, nullptr); yyjson_doc* doc = yyjson_read_opts((char*)text.data(), text.size(), YYJSON_READ_INSITU, &alc, nullptr);
if (!doc) return false;
yyjson_val* root = yyjson_doc_get_root(doc); yyjson_val* root = yyjson_doc_get_root(doc);
if constexpr (has_json_specialization_v<T>) { if constexpr (has_json_specialization_v<T>) {
return JsonSerde<T>::Read(root, obj); return gen::JsonSerde<T>::Read(root, obj);
} }
else { else {
return JsonArchive::Deserialize(root, obj); return JsonArchive::Deserialize(root, obj);
@ -35,7 +38,7 @@ namespace api {
inline string_view JsonSerialize(const T& t) { inline string_view JsonSerialize(const T& t) {
yyjson_alc alc = JsonAllocatorAdapter(); yyjson_alc alc = JsonAllocatorAdapter();
yyjson_mut_doc* doc = yyjson_mut_doc_new(&alc); yyjson_mut_doc* doc = yyjson_mut_doc_new(&alc);
yyjson_mut_val* root = JsonSerde<T>::Write(doc, Any{t}); yyjson_mut_val* root = gen::JsonSerde<T>::Write(doc, &t);
yyjson_mut_doc_set_root(doc, root); yyjson_mut_doc_set_root(doc, root);
size_t len; size_t len;
const char* json_str = yyjson_mut_write_opts(doc, 0, &alc, &len, NULL); const char* json_str = yyjson_mut_write_opts(doc, 0, &alc, &len, NULL);

View File

@ -1,57 +1,58 @@
#pragma once #pragma once
#include "../type.h"
#include "refl/pch.h" #include "refl/pch.h"
#include <format> namespace gen {
#include <string_view>
namespace api {
namespace archive {
template<typename T>
concept is_string_v = requires(T t) {
{ static_cast<std::string>(t) } -> std::convertible_to<std::string>;
};
}
using std::string_view;
using refl::Any;
using refl::UClass;
using refl::type_name;
using refl::TypeInfo;
template<typename T> template<typename T>
struct JsonSerde { struct Meta {};
inline static bool Read(yyjson_val* val, Any any) { template<typename T>
concept is_string_v = requires(T t) {
{ static_cast<std::string>(t) } -> std::convertible_to<std::string>;
};
template<typename T>
concept is_serde_v = std::is_same_v<T, bool> || std::is_integral_v<T> || std::is_floating_point_v<T> || is_string_v<T> || std::is_enum_v<T>;
template<typename T, typename = void>
struct JsonSerde {};
template<typename T>
struct JsonSerde<T, std::enable_if_t<is_serde_v<T>>>{
inline static bool Read(yyjson_val* val, const void* ptr) {
if constexpr (std::is_same_v<T, bool>) { if constexpr (std::is_same_v<T, bool>) {
*any.CastTo<T*>() = (T)yyjson_get_bool(val); *(T*)(ptr) = (T)yyjson_get_bool(val);
} }
else if constexpr (std::is_integral_v<T>) { else if constexpr (std::is_integral_v<T>) {
*any.CastTo<T*>() = (T)yyjson_get_uint(val); *(T*)(ptr) = (T)yyjson_get_uint(val);
}
else if constexpr (std::is_enum_v<T>) {
*(T*)(ptr) = (T)yyjson_get_uint(val);
} }
else if constexpr (std::is_floating_point_v<T>) { else if constexpr (std::is_floating_point_v<T>) {
*any.CastTo<T*>() = (T)yyjson_get_real(val); *(T*)(ptr) = (T)yyjson_get_real(val);
} }
else if constexpr (archive::is_string_v<T>) { else if constexpr (is_string_v<T>) {
*any.CastTo<T*>() = yyjson_get_str(val); *(T*)(ptr) = yyjson_get_str(val);
} }
else { else {
throw std::runtime_error(std::format("unknown json read type {}", type_name<T>().View())); static_assert(false, "unknown json read type");
return false;
} }
return true; return true;
} }
inline static yyjson_mut_val* Write(yyjson_mut_doc* doc, Any any) { inline static yyjson_mut_val* Write(yyjson_mut_doc* doc, const void* ptr) {
if constexpr (std::is_same_v<T, bool>) { if constexpr (std::is_same_v<T, bool>) {
return yyjson_mut_bool(doc, *any.CastTo<T*>()); return yyjson_mut_bool(doc, *(T*)(ptr));
} }
else if constexpr (std::is_integral_v<T>) { else if constexpr (std::is_integral_v<T>) {
return yyjson_mut_uint(doc, *any.CastTo<T*>()); return yyjson_mut_uint(doc, *(T*)(ptr));
}
else if constexpr (std::is_enum_v<T>) {
return yyjson_mut_uint(doc, (std::underlying_type_t<T>)*(T*)(ptr));
} }
else if constexpr (std::is_floating_point_v<T>) { else if constexpr (std::is_floating_point_v<T>) {
return yyjson_mut_real(doc, *any.CastTo<T*>()); return yyjson_mut_real(doc, *(T*)(ptr));
} }
else if constexpr (archive::is_string_v<T>) { else if constexpr (is_string_v<T>) {
auto c = (any.CastTo<T*>())->data(); return yyjson_mut_str(doc, ((T*)ptr)->data());
return yyjson_mut_str(doc, "");
} }
else { else {
throw std::runtime_error(std::format("unknown json write type {}", type_name<T>().View())); static_assert(false, "unknown json write type");
return {};
} }
} }
}; };

View File

@ -1,4 +1,38 @@
#include "serde.h" #include "serde.h"
namespace gen {
#ifdef API_DEBUG
template<typename T>
inline bool JsonRead(yyjson_val* node, const T& t) {
if (!node) return false;
return JsonSerde<T>::Read(node, &t);
}
template<typename T>
inline yyjson_mut_val* JsonWrite(yyjson_mut_doc* doc, const T& t) {
return JsonSerde<T>::Write(doc, &t);
}
#else
#define JsonRead(node, t) if(node)JsonSerde<decltype(t)>::Read(node, &t)
#define JsonWrite(doc, t) JsonSerde<decltype(t)>::Write(doc, &t)
#endif
template<typename T>
struct JsonSerde<T, std::enable_if_t<refl::is_meta_v<T>>> {
inline static bool Read(yyjson_val* val, const void* ptr) {
T& v = *(T*)ptr;
for_each_field([=](std::string_view name, auto&& value) {
JsonRead(yyjson_obj_get(val, name.data()), value);
}, v);
return true;
}
inline static yyjson_mut_val* Write(yyjson_mut_doc* doc, const void* ptr) {
T& v = *(T*)ptr;
yyjson_mut_val* obj = yyjson_mut_obj(doc);
for_each_field([=](std::string_view name, auto&& value) {
yyjson_mut_obj_add_val(doc, obj, name.data(), JsonWrite(doc, value));
}, v);
return obj;
}
};
}
namespace api { namespace api {
namespace detail { namespace detail {
// 辅助结构体,用于检查特化版本 // 辅助结构体,用于检查特化版本
@ -6,21 +40,8 @@ namespace api {
struct has_json_specialization : std::false_type {}; struct has_json_specialization : std::false_type {};
// 特化辅助结构体,匹配特化版本 // 特化辅助结构体,匹配特化版本
template <typename T> template <typename T>
struct has_json_specialization<T, std::void_t<decltype(&JsonSerde<T>::Read) >> : std::true_type {}; struct has_json_specialization<T, std::void_t<decltype(gen::JsonSerde<T>::Read)>> : std::true_type {};
} }
template<typename T> template<typename T>
concept has_json_specialization_v = detail::has_json_specialization<T>::value; concept has_json_specialization_v = detail::has_json_specialization<T>::value;
#ifdef API_DEBUG
template<typename T>
inline bool JsonRead(yyjson_val* node, const T& t) {
return JsonSerde<T>::Read(node, t);
}
template<typename T>
inline yyjson_mut_val* JsonWrite(yyjson_mut_doc* doc, const T& t) {
return JsonSerde<T>::Write(doc, t);
}
#else
#define JsonRead(node, t) JsonSerde<decltype(t)>::Read(node, t)
#endif
} }

View File

@ -2,12 +2,15 @@
#include "yyjson.h" #include "yyjson.h"
#include "serde.h" #include "serde.h"
namespace api { namespace api {
using refl::Any;
using refl::UClass;
using refl::TypeInfo;
struct JsonVTable { struct JsonVTable {
bool(*Read)(yyjson_val*, Any) = nullptr; bool(*Read)(yyjson_val*, const void*) = nullptr;
yyjson_mut_val*(*Write)(yyjson_mut_doc*, Any) = nullptr; yyjson_mut_val*(*Write)(yyjson_mut_doc*, const void*) = nullptr;
template<typename T> template<typename T>
static JsonVTable Make() { static JsonVTable Make() {
return { &JsonSerde<T>::Read, &JsonSerde<T>::Write }; return { &gen::JsonSerde<T>::Read, &gen::JsonSerde<T>::Write };
} }
}; };
using JsonFuncTable = std::pmr::unordered_map<const UClass*, JsonVTable>; using JsonFuncTable = std::pmr::unordered_map<const UClass*, JsonVTable>;

View File

@ -2,7 +2,7 @@
#include "serde.h" #include "serde.h"
namespace api { namespace api {
// 定义 yyjson_alc 适配器类 // 定义 yyjson_alc 适配器类
yyjson_alc JsonAllocatorAdapter(std::pmr::memory_resource* mr = &FramePool) { inline yyjson_alc JsonAllocatorAdapter(std::pmr::memory_resource* mr = &FramePool) {
// 初始化 yyjson_alc 结构体 // 初始化 yyjson_alc 结构体
yyjson_alc alc; yyjson_alc alc;
alc.malloc = [](void* ctx, size_t size) -> void* { alc.malloc = [](void* ctx, size_t size) -> void* {
@ -30,6 +30,7 @@ namespace api {
inline JsonFuncTable JsonArchive::BuildFuncTable() inline JsonFuncTable JsonArchive::BuildFuncTable()
{ {
JsonFuncTable funcTable{ &MemPool }; JsonFuncTable funcTable{ &MemPool };
using std::string_view;
#define RegisterAny(T) funcTable.emplace(&TypeInfo<T>::StaticClass,JsonVTable::Make<T>()) #define RegisterAny(T) funcTable.emplace(&TypeInfo<T>::StaticClass,JsonVTable::Make<T>())
#include "../register.inl" #include "../register.inl"
#undef RegisterAny #undef RegisterAny
@ -47,7 +48,7 @@ namespace api {
} }
auto it = FuncTable.find(any.cls); auto it = FuncTable.find(any.cls);
if (it != FuncTable.end()) { if (it != FuncTable.end()) {
return it->second.Write(doc, any); return it->second.Write(doc, any.ptr);
} }
return {}; return {};
} }
@ -58,7 +59,7 @@ namespace api {
} }
auto it = FuncTable.find(any.cls); auto it = FuncTable.find(any.cls);
if (it != FuncTable.end()) { if (it != FuncTable.end()) {
return it->second.Read(res, any); return it->second.Read(res, any.ptr);
} }
return false; return false;
} }

View File

@ -1,7 +1,8 @@
#pragma once #pragma once
#include "pmr/name.h" #include "pmr/name.h"
#include "macro.h" #include "enum_macro.h"
#include "os/shared_library.h" #include "os/shared_library.h"
#include "refl/pch.h"
namespace api { namespace api {
using pmr::Name; using pmr::Name;
enum class EModuleFlag : uint32_t { enum class EModuleFlag : uint32_t {
@ -9,14 +10,23 @@ namespace api {
}; };
ENABLE_BITMASK_OPERATORS(EModuleFlag); ENABLE_BITMASK_OPERATORS(EModuleFlag);
struct ModuleInfo { struct ModuleInfo {
EModuleFlag flag; UPROPERTY()
EModuleFlag flag{0};
UPROPERTY()
Name name; //!< name of the plugin Name name; //!< name of the plugin
UPROPERTY()
Name prettyname; //!< formatted name of the plugin Name prettyname; //!< formatted name of the plugin
UPROPERTY()
Name core_version; //!< version of the engine Name core_version; //!< version of the engine
UPROPERTY()
Name version; // !< version of the plugin Name version; // !< version of the plugin
UPROPERTY()
Name linking; // !< linking of the plugin Name linking; // !< linking of the plugin
UPROPERTY()
Name license; //!< license of the plugin Name license; //!< license of the plugin
UPROPERTY()
Name url; //!< url of the plugin Name url; //!< url of the plugin
UPROPERTY()
Name copyright; //!< copyright of the plugin Name copyright; //!< copyright of the plugin
public: public:
bool IsReload() { bool IsReload() {
@ -55,4 +65,5 @@ namespace api {
std::vector<IModuleSubsystem*> mSubSystems; std::vector<IModuleSubsystem*> mSubSystems;
}; };
} }
#include "module.inl" #include "module.inl"
#include "module_gen.inl"

View File

@ -1,5 +1,5 @@
#pragma once #pragma once
#include "moudle.h" #include "module.h"
namespace api { namespace api {
template<typename T1, typename T2, typename Hasher = std::hash<T1>> template<typename T1, typename T2, typename Hasher = std::hash<T1>>
using table = std::pmr::unordered_map<T1, T2, Hasher>; using table = std::pmr::unordered_map<T1, T2, Hasher>;

View File

@ -1,4 +1,7 @@
static_component("core","engine") static_component("core","engine")
add_rules("c++.codegen",{
files = {"include/module/module.h"}
})
add_includedirs("include", "include/3rdparty", {public = true}) add_includedirs("include", "include/3rdparty", {public = true})
add_headerfiles("include/**.h","include/**.inl") add_headerfiles("include/**.h","include/**.inl")
add_files("src/**.cpp") add_files("src/**.cpp")

View File

@ -3,53 +3,53 @@
#include <unordered_map> #include <unordered_map>
namespace pmr namespace pmr
{ {
static consteval inline size_t InvalidValue() noexcept { return static_cast<size_t>(-1); }
constexpr inline size_t string_hash(std::string_view str) noexcept; constexpr inline size_t string_hash(std::string_view str) noexcept;
class NameID {
public:
static consteval size_t InvalidValue() noexcept { return static_cast<size_t>(-1); }
constexpr NameID() noexcept : hash{ InvalidValue() } {}
explicit constexpr NameID(size_t value) noexcept : hash{ value } {}
constexpr NameID(std::string_view str) noexcept : hash{ string_hash(str) } {}
template<size_t N>
constexpr NameID(const char(&str)[N]) noexcept : hash{ string_hash(str) } {}
constexpr size_t GetValue() const noexcept { return hash; }
constexpr bool Valid() const noexcept { return hash != InvalidValue(); }
constexpr bool Is(std::string_view str) const noexcept { return hash == NameID{ str }.GetValue(); }
explicit constexpr operator bool() const noexcept { return Valid(); }
constexpr std::strong_ordering operator<=>(const NameID& rhs) const noexcept = default;
std::string ToString() const;
const std::pmr::string& ToStringRef() const;
operator std::string() const { return ToString(); }
private:
size_t hash;
};
struct Name { struct Name {
private:
size_t hash; size_t hash;
#ifdef API_DEBUG #ifdef API_DEBUG
std::string_view value; std::string_view value;
#endif // API_DEBUG #endif // API_DEBUG
public: public:
Name():hash(NameID::InvalidValue()) {}; Name():hash(InvalidValue()) {};
Name(const char* str)noexcept;
template<size_t N> template<size_t N>
constexpr Name(const char(&str)[N]) noexcept; Name(const char(&str)[N]) noexcept;
Name(const char* str)noexcept;
Name(const std::string& str)noexcept; Name(const std::string& str)noexcept;
Name(std::string_view str)noexcept; Name(std::string_view str)noexcept;
auto operator<=>(const Name& other) const noexcept { return hash <=> other.hash; }; auto operator<=>(const Name& other) const noexcept { return hash <=> other.hash; };
bool operator==(const Name& other) const { bool operator==(const Name& other) const {return hash == other.hash;}
return hash == other.hash; const char* data()const { return ToStringView().data(); }
} constexpr size_t Hash() const noexcept { return hash; }
constexpr size_t GetValue() const noexcept { return hash; }
std::string ToString() const; std::string ToString() const;
const std::string_view ToStringView() const; const std::string_view ToStringView() const;
operator std::string() const { return ToString(); } operator std::string() const { return ToString(); }
}; };
class CName {
private:
size_t hash;
std::string_view value;
public:
constexpr CName() noexcept : hash{ InvalidValue() } {}
constexpr CName(std::string_view str) noexcept : hash{ string_hash(str) } ,value(str) {}
template<size_t N>
constexpr CName(const char(&str)[N]) noexcept : hash{ string_hash(str) }, value(str) {}
const char* data()const { return Value().data(); }
constexpr size_t Hash() const noexcept { return hash; }
constexpr std::string_view Value() const noexcept { return value; }
constexpr bool Valid() const noexcept { return hash != InvalidValue(); }
explicit constexpr operator bool() const noexcept { return Valid(); }
constexpr auto operator<=>(const CName& rhs) const noexcept { return hash <=> rhs.hash; };
bool operator==(const CName& other) const { return hash == other.hash; }
std::string ToString() const { return std::string(value); };
operator std::string() const { return ToString(); }
};
bool operator==(const CName& cname, const Name& name) {
return cname.Hash() == name.Hash();
}
constexpr inline size_t string_hash(std::string_view str) noexcept constexpr inline size_t string_hash(std::string_view str) noexcept
{ {
constexpr size_t fnv_offset_basis = 0xcbf29ce484222325; constexpr size_t fnv_offset_basis = 0xcbf29ce484222325;
@ -66,22 +66,23 @@ namespace pmr
return hash; return hash;
} }
consteval static CName FName(std::string_view view) { return CName{ view }; };
} }
namespace std { namespace std {
template<> template<>
struct hash<::pmr::NameID> struct hash<::pmr::CName>
{ {
size_t operator()(const ::pmr::NameID& ID) const noexcept size_t operator()(const ::pmr::CName& name) const noexcept
{ {
return ID.GetValue(); return name.Hash();
} }
}; };
template<> template<>
struct hash<::pmr::Name> struct hash<::pmr::Name>
{ {
size_t operator()(const ::pmr::Name& ID) const noexcept size_t operator()(const ::pmr::Name& name) const noexcept
{ {
return ID.GetValue(); return name.Hash();
} }
}; };
} }

View File

@ -32,14 +32,6 @@ namespace pmr {
} }
return it->second; return it->second;
} }
inline std::string NameID::ToString() const
{
return std::string(NameTable::Find(hash));
}
inline const std::pmr::string& NameID::ToStringRef() const
{
return NameTable::Find(hash);
}
#ifdef API_DEBUG #ifdef API_DEBUG
#define MAKE_NAME_PAIR(hash, str) value = NameTable::MakePair(hash, str) #define MAKE_NAME_PAIR(hash, str) value = NameTable::MakePair(hash, str)
#define NAME_TO_STRING value #define NAME_TO_STRING value
@ -60,7 +52,7 @@ namespace pmr {
MAKE_NAME_PAIR(hash, str); MAKE_NAME_PAIR(hash, str);
} }
template<std::size_t N> template<std::size_t N>
inline constexpr Name::Name(const char(&str)[N]) noexcept : hash(string_hash(str)) inline Name::Name(const char(&str)[N]) noexcept : hash(string_hash(str))
{ {
MAKE_NAME_PAIR(hash, str); MAKE_NAME_PAIR(hash, str);
} }

View File

@ -1,7 +1,7 @@
#include "any.h" #include "any.h"
#include "uclass.h" #include "uclass.h"
namespace refl{ namespace refl{
bool Any::Check(const UClass* parent)const inline bool Any::Check(const UClass* parent)const
{ {
if (cls == parent) { if (cls == parent) {
return true; return true;

View File

@ -4,6 +4,9 @@
#include <span> #include <span>
namespace refl { namespace refl {
using pmr::Name; using pmr::Name;
using pmr::CName;
using pmr::FName;
using pmr::string_hash;
using std::span; using std::span;
using Offset = uint32_t; using Offset = uint32_t;
using Method = void*; using Method = void*;

View File

@ -0,0 +1,44 @@
#pragma once
#include "field.h"
namespace gen {
using pmr::CName;
using pmr::FName;
using pmr::string_hash;
template<typename T, size_t hash>
struct MetaImpl {};
template<typename T>
struct Property {
std::string_view name;
T ptr;
constexpr Property(T ptr, std::string_view name) noexcept:name(name), ptr(ptr) {}
};
template<typename T>
consteval Property<T> FProperty(T ptr, std::string_view name) { return { ptr, name }; }
// 遍历所有字段值
template <typename Func, typename T, size_t hash = string_hash("Meta")>
inline void for_each_field(Func&& func, T& obj) {
constexpr auto props = MetaImpl<T, hash>::Fields();
std::apply([&](auto... field) {
((func(field.name, obj.*(field.ptr))), ...);
}, props);
}
}
namespace refl {
struct MetaHelp{
template<typename T, typename... Args>
static FieldPtr CtorField(T(*ptr)(Args...), const MethodData& data = {});
template<typename T, typename Obj>
static FieldPtr MemberField(T Obj::* ptr, CName name, const MemberData& data = {});
template<typename R, typename ...Args>
static FieldPtr MethodField(R(*ptr)(Args...), CName name, const MethodData& data = {});
template<typename T, typename R, typename ...Args>
static FieldPtr MethodField(R(T::* ptr)(Args...), CName name, const MethodData& data = {});
template<typename T, typename R, typename ...Args>
static FieldPtr MethodField(R(T::* ptr)(Args...)const, CName name, const MethodData& data = {});
};
}

View File

@ -0,0 +1 @@
#include "meta.h"

View File

@ -95,6 +95,20 @@ namespace refl {
using args_type_t = detail::args_type<std::remove_cv_t<T>>::type; using args_type_t = detail::args_type<std::remove_cv_t<T>>::type;
}; };
namespace refl { namespace refl {
template<class T>
struct Meta {};
template<class T>
concept is_meta_v = requires { typename Meta<T>::Impl; };
template <class T>
concept has_parent_v = requires { typename Meta<T>::Parent; };
template<class T>
using meta_t = Meta<T>::Impl;
template<class T>
using parent_t = typename Meta<T>::Parent;
//类型接口 //类型接口
template<typename T> template<typename T>
struct TypeInfoImpl; struct TypeInfoImpl;

View File

@ -1,8 +1,9 @@
#include "uclass.h" #include "uclass.h"
#include "name.h" #include "name.h"
#include "type.h"
namespace refl{ namespace refl{
template <class T> template <class T>
concept is_metas_v = false;//requires(const Name & name) { MetaImpl<T>::MyMetas::GetMeta(name); }; concept is_metas_v = requires(const Name & name) { Meta<T>::GetMeta(name); };
template<typename T> template<typename T>
class UClass_Auto : public UClass { class UClass_Auto : public UClass {
public: public:
@ -29,13 +30,29 @@ namespace refl{
} }
} }
}; };
template<> template<typename T, typename MetaImpl>
struct TypeInfoImpl<void> { class UClass_Meta : public UClass {
inline static UClass StaticClass{ type_name<void>().View(), 0 }; using FieldsType = decltype(MetaImpl::MakeFields());
FieldsType Fields{ MetaImpl::MakeFields() };
UClass_Meta() : UClass(type_name<T>().View(), sizeof(T)) {
if constexpr (has_parent_v<T>) {
parent = &TypeInfo<parent_t<T>>::StaticClass;
}
}
}; };
template<typename T> template<typename T>
struct TypeInfoImpl { struct TypeInfoImpl {
using MyUClass = UClass_Auto<T>; using MyUClass = UClass_Auto<T>;
inline static MyUClass StaticClass{}; inline static MyUClass StaticClass{};
}; };
template<>
struct TypeInfoImpl<void> {
inline static UClass StaticClass{ type_name<void>().View(), 0 };
};
template<is_meta_v T>
struct TypeInfoImpl<T> {
using MyUClass = UClass_Meta<T, meta_t<T>>;
inline static MyUClass StaticClass{};
};
} }

View File

@ -0,0 +1,39 @@
#pragma once
#if !defined(__cppast)
#define __cppast(...)
#endif
#define __Meta(...) __cppast(Meta=__VA_ARGS__)
#define UPROPERTY(...) __Meta(__VA_ARGS__)
#define UFUNCTION(...) __Meta(__VA_ARGS__)
#define __vkMeta(...) __cppast(vkMeta=__VA_ARGS__)
#define UPROPERTY_vk(...) __vkMeta(__VA_ARGS__)
#define UFUNCTION_vk(...) __vkMeta(__VA_ARGS__)
#define __dxMeta(...) __cppast(dxMeta=__VA_ARGS__)
#define UPROPERTY_dx(...) __dxMeta(__VA_ARGS__)
#define UFUNCTION_dx(...) __dxMeta(__VA_ARGS__)
// 辅助宏,用于实际拼接
#define CONCATENATE(arg1, arg2) CONCATENATE_IMPL(arg1, arg2)
#define CONCATENATE_IMPL(arg1, arg2) arg1##arg2
#define MY_UNIQUE_NAME(base) CONCATENATE(base, __LINE__)
#define USING_CTOR_NAME MY_UNIQUE_NAME(__Ctor)
#define USING_FUNC_NAME MY_UNIQUE_NAME(__Func)
#define USING_OVERLOAD_CTOR(Class, ...) using USING_CTOR_NAME = Class(*)(__VA_ARGS__);
#define USING_OVERLOAD_FUNC(R, ...) using USING_FUNC_NAME = R(*)(__VA_ARGS__);
#define USING_OVERLOAD_CLASS_FUNC(R, Class, ...) using USING_FUNC_NAME = R(Class::*)(__VA_ARGS__);
#define REGISTER_META_TABLE(Class) refl::UClass::MetaTable.emplace(type_name<Class>().View(), &refl::TypeInfo<Class>::StaticClass);
#define GENERATED_BODY() template <typename T, size_t hash>\
friend class gen::MetaImpl;
/*
struct vec3{
USING_OVERLOAD_CTOR(vec3)
UFUNCTION({},ref = USING_CTOR_NAME)
vec3(){}
}
*/

View File

@ -1,4 +1,6 @@
#pragma once #pragma once
#include "detail/name.inl" #include "detail/name.inl"
#include "detail/any.inl" #include "detail/any.inl"
#include "detail/uclass.inl" #include "detail/meta.inl"
#include "detail/uclass.inl"
#include "macro.h"

View File

@ -1,4 +1,4 @@
#include "module/moudle.h" #include "module/module.h"
#include "asset/asset.h" #include "asset/asset.h"
class VulkanModule : public api::IDynamicModule class VulkanModule : public api::IDynamicModule
{ {

View File

@ -0,0 +1 @@
{"flag":0,"name":"vulkan"}

View File

@ -2,5 +2,4 @@ shared_component("vulkan","engine")
add_includedirs("include/vulkan") add_includedirs("include/vulkan")
add_headerfiles("include/**.h") add_headerfiles("include/**.h")
add_files("src/**.cpp") add_files("src/**.cpp")
add_rules("engine.plugin", {file = "include/vulkan/module.h"}) add_rules("engine.plugin", {file = "include/vulkan/module.h"})
--add_deps("core", "asset", {public = true})

View File

@ -0,0 +1,94 @@
#include "macro_parse.h"
#include <string>
#include <stack>
#include <optional>
#include <iostream>
#include <fstream>
std::string_view module_macro[] = { MODULE_DEPENDENCY , IMPLEMENT_DYNAMIC_MODULE , IMPLEMENT_STATIC_MODULE };
pmr::vector<pmr::string> parseArgs(std::string_view& str) {
pmr::vector<pmr::string> args(&pool);
std::stack<char> stack;
enum EParseState {
EEmpty,
EBody,
};
EParseState state = EEmpty;
int n = 0;
char segment[1024];
for (char c : str) {
switch (state)
{
case EEmpty:
{
if (c == ' ' || c == '\t')
break;
state = EBody;
if (c == '(' && stack.empty()) {
stack.push(c);
break;
}
}
case EBody:
{
if (c == '(' || c == '{' || c == '[' || (c == '"' && stack.top() != '"')) {
stack.push(c);
}
else {
char t = stack.top();
if ((t == '(' && c == ')') || (t == '[' && c == ']') || (t == '{' && c == '}') || (t == '"' && c == '"')) {
stack.pop();
}
}
if (stack.empty()) {
std::string_view view(segment, n);
args.push_back(pmr::string(view, &pool));
return args;
}
if (c == ',' && stack.size() == 1) {
std::string_view view(segment, n);
args.push_back(pmr::string(view, &pool));
n = 0;
state = EEmpty;
}
else {
segment[n++] = c;
}
break;
}
default:
break;
}
}
return args;
}
std::optional<MacroData> parseLine(std::string_view line) {
for (auto macro : module_macro) {
size_t pos = line.find(macro);
if (pos != std::string_view::npos) {
line = line.substr(pos + macro.size());
MacroData md{ parseArgs(line) };
md.macro = macro.data();
//std::cout << line << std::endl;
return md;
}
}
return std::optional<MacroData>{};
}
// 读取文件并返回每一行内容
pmr::vector<MacroData> readMacroFile(const char* file_path) {
pmr::vector<MacroData> lines(&pool);
std::ifstream file(file_path);
if (!file.is_open()) {
//std::cerr << "Failed to open file: " << file_path << std::endl;
return lines;
}
std::string line;
while (std::getline(file, line)) {
std::string_view line_view(line);
if (auto md = parseLine(line_view)) {
lines.push_back(md.value());
}
}
file.close();
return lines;
}

View File

@ -0,0 +1,17 @@
#include <memory_resource>
namespace pmr {
using std::pmr::monotonic_buffer_resource;
using std::pmr::vector;
using std::pmr::string;
}
inline pmr::monotonic_buffer_resource pool;
inline const char* MODULE_DEPENDENCY = "MODULE_DEPENDENCY";
inline const char* IMPLEMENT_DYNAMIC_MODULE = "IMPLEMENT_DYNAMIC_MODULE";
inline const char* IMPLEMENT_STATIC_MODULE = "IMPLEMENT_STATIC_MODULE";
struct MacroData {
const char* macro{ nullptr };
pmr::vector<pmr::string> args;
MacroData() :args(&pool) {}
MacroData(const pmr::vector<pmr::string>& args) :args(args) {}
};
pmr::vector<MacroData> readMacroFile(const char* file_path);

View File

@ -1,113 +1,19 @@
#include <fstream> #include "macro_parse.h"
#include <vector>
#include <iostream>
#include <string>
#include <memory_resource>
#include <stack>
#include <optional>
#include <sstream>
#include "archive/json.h" #include "archive/json.h"
namespace pmr { #include "module/module.h"
using std::pmr::monotonic_buffer_resource; #include <iostream>
using std::pmr::vector; #include <fstream>
using std::pmr::string; #include <sstream>
} std::string_view readFile(const char* file_path) {
pmr::monotonic_buffer_resource pool; std::ifstream file(file_path, std::ios::ate);
const char* MODULE_DEPENDENCY = "MODULE_DEPENDENCY";
const char* IMPLEMENT_DYNAMIC_MODULE = "IMPLEMENT_DYNAMIC_MODULE";
const char* IMPLEMENT_STATIC_MODULE = "IMPLEMENT_STATIC_MODULE";
std::string_view module_macro[] = { MODULE_DEPENDENCY , IMPLEMENT_DYNAMIC_MODULE , IMPLEMENT_STATIC_MODULE };
struct MacroData{
const char* macro{nullptr};
pmr::vector<pmr::string> args;
MacroData() :args(&pool) {}
MacroData(const pmr::vector<pmr::string>& args):args(args) {}
};
pmr::vector<pmr::string> parseArgs(std::string_view& str) {
pmr::vector<pmr::string> args(&pool);
std::stack<char> stack;
enum EParseState {
EEmpty,
EBody,
};
EParseState state = EEmpty;
int n = 0;
char segment[1024];
for (char c : str) {
switch (state)
{
case EEmpty:
{
if (c == ' ' || c == '\t')
break;
state = EBody;
if (c == '(' && stack.empty()) {
stack.push(c);
break;
}
}
case EBody:
{
if (c == '(' || c == '{' || c == '[' || (c == '"' && stack.top() != '"')) {
stack.push(c);
}else{
char t = stack.top();
if ((t == '(' && c == ')') || (t == '[' && c == ']') || (t == '{' && c == '}') || (t == '"' && c == '"')) {
stack.pop();
}
}
if (stack.empty()) {
std::string_view view(segment, n);
args.push_back(pmr::string(view, &pool));
return args;
}
if (c == ',' && stack.size() == 1) {
std::string_view view(segment, n);
args.push_back(pmr::string(view, &pool));
n = 0;
state = EEmpty;
}
else {
segment[n++] = c;
}
break;
}
default:
break;
}
}
return args;
}
std::optional<MacroData> parseLine(std::string_view line) {
for (auto macro : module_macro) {
size_t pos = line.find(macro);
if (pos != std::string_view::npos) {
line = line.substr(pos + macro.size());
MacroData md{ parseArgs(line) };
md.macro = macro.data();
std::cout << line << std::endl;
return md;
}
}
return std::optional<MacroData>{};
}
// 读取文件并返回每一行内容
pmr::vector<MacroData> readFile(const char* file_path) {
pmr::vector<MacroData> lines(&pool);
std::ifstream file(file_path);
if (!file.is_open()) { if (!file.is_open()) {
//std::cerr << "Failed to open file: " << file_path << std::endl; return "";
return lines;
} }
std::string line; size_t size = file.tellg();
while (std::getline(file, line)) { file.seekg(0);
std::string_view line_view(line); char* ptr = new(FramePool)char[size];
if (auto md = parseLine(line_view)) { file.read(ptr, size);
lines.push_back(md.value()); return std::string_view(ptr, size);
}
}
file.close();
return lines;
} }
void writeFile(const char* file_path, std::string_view data) { void writeFile(const char* file_path, std::string_view data) {
std::ofstream file(file_path, 0); std::ofstream file(file_path, 0);
@ -134,43 +40,40 @@ void genLua(const char* file_path, const pmr::vector<MacroData>& mdList) {
oss << '}'; oss << '}';
writeFile(file_path, oss.str()); writeFile(file_path, oss.str());
} }
namespace api {
struct Guid {
int a;
float b;
};
template<>
struct JsonSerde<Guid> {
inline static bool Read(yyjson_val* node, Any any) {
Guid& v = *any.CastTo<Guid*>();
JsonRead(yyjson_obj_get(node, "a"), v.a);
JsonRead(yyjson_obj_get(node, "b"), v.b);
return true;
}
inline static yyjson_mut_val* Write(yyjson_mut_doc* doc, Any any) {
Guid& v = *any.CastTo<Guid*>();
auto obj = yyjson_mut_obj(doc);
yyjson_mut_obj_add_val(doc, obj, "a", JsonWrite(doc, v.a));
yyjson_mut_obj_add_val(doc, obj, "b", JsonWrite(doc, v.b));
return obj;
}
};
}
void genPlugin(const char* file_path, const pmr::vector<MacroData>& mdList) { void genPlugin(const char* file_path, const pmr::vector<MacroData>& mdList) {
api::Guid guid; std::string_view text = readFile(file_path);
guid.a = 1243; api::ModuleInfo info;
std::string_view data = api::JsonSerialize(guid); api::JsonDeserialize<api::ModuleInfo>(text, &info);
auto res = api::JsonDeserialize<api::Guid>(data); bool bchange = false;
if (res) { for (auto& md : mdList) {
api::Guid g2 = res.value(); if (md.macro == IMPLEMENT_DYNAMIC_MODULE || md.macro == IMPLEMENT_STATIC_MODULE) {
int a = g2.a; api::Name name = md.args[1].c_str();
int b = g2.b; bchange = info.name != name;
info.name = name;
}
else if (md.macro == MODULE_DEPENDENCY) {
for (auto& args : md.args) {
if (args[0] != '{') {
}
}
}
}
if (bchange) {
writeFile(file_path, api::JsonSerialize(info));
} }
} }
int main() { int main(int argc, char* argv[]) {
const char* file_path = R"(F:\engine\zengine\engine\modules\render\vulkan\include\vulkan\module.h)"; if (argc < 6) {
auto mdList = readFile(file_path); return -1;
genLua(R"(F:\engine\zengine\build\.gens\vulkan\windows\xmake.lua)", mdList); }
genPlugin(R"(F:\engine\zengine\build\.gens\vulkan\windows\xmake.lua)", mdList); std::string project_dir = argv[1];
std::string lua_file = project_dir + "\\" + argv[2];
std::string script_dir = argv[3];
std::string module_file = script_dir + "\\" + argv[4];
std::string plugin_file = script_dir + "\\" + argv[5];
auto mdList = readMacroFile(module_file.c_str());
genLua(lua_file.c_str(), mdList);
genPlugin(plugin_file.c_str(), mdList);
return 0; return 0;
} }

View File

@ -1,3 +1,8 @@
tool_target("make_plugin") tool_target("make_plugin")
add_files("src/main.cpp") add_includedirs("src")
add_deps("core") add_files("src/*.cpp")
add_headerfiles("src/*.h")
add_rules("engine.tool")
add_deps("core")
set_runargs([[F:\engine\zengine]], [[build\.gens\vulkan\windows\xmake.lua]],
[[F:\engine\zengine\engine\modules\render\vulkan]], [[include/vulkan/module.h]], [[vulkan.plugin]])

View File

@ -1,12 +1,21 @@
function find_exe_dir()
local os_name = os.host()
local arch_name = os.arch()
local mode_name = is_mode("debug") and "debug" or "release"
-- 构建生成目录路径
return path.join(os.projectdir(), "build", os_name, arch_name, mode_name)
end
function find_my_program(name, sdkdir, use_next) function find_my_program(name, sdkdir, use_next)
import("lib.detect.find_file") import("lib.detect.find_file")
import("lib.detect.find_program") import("lib.detect.find_program")
import("lib.detect.find_tool") import("lib.detect.find_tool")
local sdkdir = sdkdir or path.join(os.projectdir(), "tools") local sdkdir = sdkdir or path.join(os.projectdir(), "tools")
local tool = find_tool(name, {pathes = {sdkdir, "/usr/local/bin"}}) local exedir = find_exe_dir()
local prog = tool and tool.program or find_program(name, {pathes = {sdkdir, "/usr/local/bin"}}) local tool = find_tool(name, {pathes = {sdkdir, exedir, "/usr/local/bin"}})
prog = prog or find_file(name, {sdkdir}) local prog = tool and tool.program or find_program(name, {pathes = {sdkdir,exedir, "/usr/local/bin"}})
prog = prog or find_file(name, {sdkdir, exedir})
if (prog == nil) then if (prog == nil) then
if os.host() ~= "windows" then if os.host() ~= "windows" then
local outdata, errdata = os.iorun("which " .. name) local outdata, errdata = os.iorun("which " .. name)
@ -21,7 +30,7 @@ function find_my_program(name, sdkdir, use_next)
if not use_next then if not use_next then
return find_my_program(name, path.join(sdkdir, name), true) return find_my_program(name, path.join(sdkdir, name), true)
end end
print(name .. "_f not found! under " .. sdkdir) print(name .. " not found! under " .. sdkdir, exedir)
return return
end end
return {program = prog, sdkdir = sdkdir} return {program = prog, sdkdir = sdkdir}

View File

@ -0,0 +1,66 @@
import("core.project.depend")
local genList = {}
function cmd_compile(genfile, sourcefile, template, macro, define)
if genList[genfile] then
return
end
import("find_sdk")
local meta = find_sdk.find_my_program("refl")
template = template or path.join(meta.sdkdir, "template")
if not macro then --优先使用库定义
macro = path.join(os.projectdir(), "engine/modules/engine/zlib/include/refl/macro.h")
if not os.exists(macro) then
macro = path.join(os.curdir(), "macro.h")
end
end
argv = {"build", sourcefile, "-o", genfile, "-t", template, "-m", macro}
if define then
table.insert(argv, "-d")
table.insert(argv, define)
end
genList[genfile] = true
print("cmd_meta_compile", genfile)
os.execv(meta.program, argv)
return argv
end
function _listen_gen_file(target, batch, template, macro, define)
genfile, sourcefile = batch[1], batch[2]
local dependfile = target:dependfile(genfile)
depend.on_changed(
function()
cmd_compile(batch[1], batch[2], template, macro, define)
end,
{dependfile = dependfile, files = sourcefile}
)
end
function gen(target)
local gen_batch = target:data("codegen.batch")
if not gen_batch then
return
end
local template = target:extraconf("rules", "c++.codegen", "template")
local macro = target:extraconf("rules", "c++.codegen", "macro")
local define = target:extraconf("rules", "c++.codegen", "define")
for _, batch in ipairs(gen_batch) do
if batch[2] then
_listen_gen_file(target, batch, template, macro, define)
end
end
end
function main(target, headerfiles)
local sourcedir = path.join(target:autogendir({root = true}), target:plat(), "inl")
if not os.isdir(sourcedir) then
os.mkdir(sourcedir)
end
target:add("includedirs", sourcedir, {public = true})
local gen_batch = {}
for idx, headerfile in pairs(headerfiles) do
-- batch
sourcefile = path.join(sourcedir, path.basename(headerfile) .. "_gen.inl")
table.insert(gen_batch, {sourcefile, headerfile})
end
-- save unit batch
target:data_set("codegen.batch", gen_batch)
end

View File

@ -0,0 +1,19 @@
rule("c++.codegen")
set_extensions(".inl")
after_load(function (target)
if not is_mode("debug") then return end
import("make_gen")
local headerfiles = {}
local files = target:extraconf("rules", "c++.codegen", "files")
for _, file in ipairs(files) do
local p = path.join(target:scriptdir(), file)
for __, filepath in ipairs(os.files(p)) do
table.insert(headerfiles, filepath)
end
end
make_gen(target, headerfiles)
end)
on_config(function (target)
if not is_mode("debug") then return end
import("make_gen").gen(target)
end)

View File

@ -1,28 +1,30 @@
import("core.project.depend") import("core.project.depend")
function cmd_compile(target, genfile, file) function cmd_compile(target, genfile, file)
local res = [[ import("find_sdk")
{ print("find make_plugin", is_mode("debug"))
{"core", { public = true}}, local plugin = find_sdk.find_my_program("make_plugin")
{"asset", { public = true}}, if not plugin then return end
} print("cmd_compile plugin", genfile, file)
]] argv = { os.projectdir() , genfile, target:scriptdir(), file, target:name() .. ".plugin"}
io.writefile(genfile, res) os.execv(plugin.program, argv)
local dependency = io.load(genfile)
for k,v in ipairs(dependency) do
--target:add("deps", v[1], v[2])
end
end end
function main(target, file) function main(target, file)
local sourcedir = path.join(target:autogendir({root = true}), target:plat()) local sourcedir = path.join(target:autogendir({root = true}), target:plat())
if not os.isdir(sourcedir) then if not os.isdir(sourcedir) then
os.mkdir(sourcedir) os.mkdir(sourcedir)
end end
local genfile = sourcedir .. "\\xmake.lua" local genfile = path.join(sourcedir,"xmake.lua")
local dependfile = target:dependfile(genfile) local dependfile = target:dependfile(genfile)
depend.on_changed( depend.on_changed(
function() function()
cmd_compile(target, genfile, file) cmd_compile(target, genfile, file)
end, end,
{dependfile = dependfile, files = {file}} {dependfile = dependfile, files = {path.join(target:scriptdir(), file)}}
) )
if os.exists(genfile) then
local dependency = io.load(genfile)
for k,v in ipairs(dependency) do
target:add("deps", v[1], v[2])
end
end
end end

View File

@ -1,6 +1,7 @@
rule("engine.plugin") rule("engine.plugin")
set_extensions(".h") set_extensions(".h")
on_load(function (target) on_load(function (target)
if not is_mode("debug") then return end
import("make_plugin") import("make_plugin")
local file = target:extraconf("rules", "engine.plugin", "file") local file = target:extraconf("rules", "engine.plugin", "file")
make_plugin(target, file or "module.h") make_plugin(target, file or "module.h")

View File

@ -0,0 +1,5 @@
rule("engine.tool")
-- after_build(function (target)
-- -- do nothing
-- --print("after_install", target:targetfile())
-- end)