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"
namespace api {
using meta::result;
using std::string_view;
enum class SerializeError : char
{
EMPTY,
@ -11,11 +12,13 @@ namespace api {
};
template<typename T>
inline bool JsonDeserialize(string_view text, T* obj) {
if (text.empty()) return false;
yyjson_alc alc = JsonAllocatorAdapter();
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);
if constexpr (has_json_specialization_v<T>) {
return JsonSerde<T>::Read(root, obj);
return gen::JsonSerde<T>::Read(root, obj);
}
else {
return JsonArchive::Deserialize(root, obj);
@ -35,7 +38,7 @@ namespace api {
inline string_view JsonSerialize(const T& t) {
yyjson_alc alc = JsonAllocatorAdapter();
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);
size_t len;
const char* json_str = yyjson_mut_write_opts(doc, 0, &alc, &len, NULL);

View File

@ -1,57 +1,58 @@
#pragma once
#include "../type.h"
#include "refl/pch.h"
#include <format>
#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;
namespace gen {
template<typename T>
struct JsonSerde {
inline static bool Read(yyjson_val* val, Any any) {
struct Meta {};
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>) {
*any.CastTo<T*>() = (T)yyjson_get_bool(val);
*(T*)(ptr) = (T)yyjson_get_bool(val);
}
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>) {
*any.CastTo<T*>() = (T)yyjson_get_real(val);
*(T*)(ptr) = (T)yyjson_get_real(val);
}
else if constexpr (archive::is_string_v<T>) {
*any.CastTo<T*>() = yyjson_get_str(val);
else if constexpr (is_string_v<T>) {
*(T*)(ptr) = yyjson_get_str(val);
}
else {
throw std::runtime_error(std::format("unknown json read type {}", type_name<T>().View()));
return false;
static_assert(false, "unknown json read type");
}
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>) {
return yyjson_mut_bool(doc, *any.CastTo<T*>());
return yyjson_mut_bool(doc, *(T*)(ptr));
}
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>) {
return yyjson_mut_real(doc, *any.CastTo<T*>());
return yyjson_mut_real(doc, *(T*)(ptr));
}
else if constexpr (archive::is_string_v<T>) {
auto c = (any.CastTo<T*>())->data();
return yyjson_mut_str(doc, "");
else if constexpr (is_string_v<T>) {
return yyjson_mut_str(doc, ((T*)ptr)->data());
}
else {
throw std::runtime_error(std::format("unknown json write type {}", type_name<T>().View()));
return {};
static_assert(false, "unknown json write type");
}
}
};

View File

@ -1,4 +1,38 @@
#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 detail {
// 辅助结构体,用于检查特化版本
@ -6,21 +40,8 @@ namespace api {
struct has_json_specialization : std::false_type {};
// 特化辅助结构体,匹配特化版本
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>
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 "serde.h"
namespace api {
using refl::Any;
using refl::UClass;
using refl::TypeInfo;
struct JsonVTable {
bool(*Read)(yyjson_val*, Any) = nullptr;
yyjson_mut_val*(*Write)(yyjson_mut_doc*, Any) = nullptr;
bool(*Read)(yyjson_val*, const void*) = nullptr;
yyjson_mut_val*(*Write)(yyjson_mut_doc*, const void*) = nullptr;
template<typename T>
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>;

View File

@ -2,7 +2,7 @@
#include "serde.h"
namespace api {
// 定义 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 alc;
alc.malloc = [](void* ctx, size_t size) -> void* {
@ -30,6 +30,7 @@ namespace api {
inline JsonFuncTable JsonArchive::BuildFuncTable()
{
JsonFuncTable funcTable{ &MemPool };
using std::string_view;
#define RegisterAny(T) funcTable.emplace(&TypeInfo<T>::StaticClass,JsonVTable::Make<T>())
#include "../register.inl"
#undef RegisterAny
@ -47,7 +48,7 @@ namespace api {
}
auto it = FuncTable.find(any.cls);
if (it != FuncTable.end()) {
return it->second.Write(doc, any);
return it->second.Write(doc, any.ptr);
}
return {};
}
@ -58,7 +59,7 @@ namespace api {
}
auto it = FuncTable.find(any.cls);
if (it != FuncTable.end()) {
return it->second.Read(res, any);
return it->second.Read(res, any.ptr);
}
return false;
}

View File

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

View File

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

View File

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

View File

@ -3,53 +3,53 @@
#include <unordered_map>
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;
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 {
private:
size_t hash;
#ifdef API_DEBUG
std::string_view value;
#endif // API_DEBUG
public:
Name():hash(NameID::InvalidValue()) {};
Name(const char* str)noexcept;
Name():hash(InvalidValue()) {};
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(std::string_view str)noexcept;
auto operator<=>(const Name& other) const noexcept { return hash <=> other.hash; };
bool operator==(const Name& other) const {
return hash == other.hash;
}
constexpr size_t GetValue() const noexcept { return hash; }
bool operator==(const Name& other) const {return hash == other.hash;}
const char* data()const { return ToStringView().data(); }
constexpr size_t Hash() const noexcept { return hash; }
std::string ToString() const;
const std::string_view ToStringView() const;
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 size_t fnv_offset_basis = 0xcbf29ce484222325;
@ -66,22 +66,23 @@ namespace pmr
return hash;
}
consteval static CName FName(std::string_view view) { return CName{ view }; };
}
namespace std {
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<>
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;
}
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
#define MAKE_NAME_PAIR(hash, str) value = NameTable::MakePair(hash, str)
#define NAME_TO_STRING value
@ -60,7 +52,7 @@ namespace pmr {
MAKE_NAME_PAIR(hash, str);
}
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);
}

View File

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

View File

@ -4,6 +4,9 @@
#include <span>
namespace refl {
using pmr::Name;
using pmr::CName;
using pmr::FName;
using pmr::string_hash;
using std::span;
using Offset = uint32_t;
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;
};
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>
struct TypeInfoImpl;

View File

@ -1,8 +1,9 @@
#include "uclass.h"
#include "name.h"
#include "type.h"
namespace refl{
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>
class UClass_Auto : public UClass {
public:
@ -29,13 +30,29 @@ namespace refl{
}
}
};
template<>
struct TypeInfoImpl<void> {
inline static UClass StaticClass{ type_name<void>().View(), 0 };
template<typename T, typename MetaImpl>
class UClass_Meta : public UClass {
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>
struct TypeInfoImpl {
using MyUClass = UClass_Auto<T>;
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
#include "detail/name.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"
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_headerfiles("include/**.h")
add_files("src/**.cpp")
add_rules("engine.plugin", {file = "include/vulkan/module.h"})
--add_deps("core", "asset", {public = true})
add_rules("engine.plugin", {file = "include/vulkan/module.h"})

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 <vector>
#include <iostream>
#include <string>
#include <memory_resource>
#include <stack>
#include <optional>
#include <sstream>
#include "macro_parse.h"
#include "archive/json.h"
namespace pmr {
using std::pmr::monotonic_buffer_resource;
using std::pmr::vector;
using std::pmr::string;
}
pmr::monotonic_buffer_resource pool;
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);
#include "module/module.h"
#include <iostream>
#include <fstream>
#include <sstream>
std::string_view readFile(const char* file_path) {
std::ifstream file(file_path, std::ios::ate);
if (!file.is_open()) {
//std::cerr << "Failed to open file: " << file_path << std::endl;
return lines;
return "";
}
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;
size_t size = file.tellg();
file.seekg(0);
char* ptr = new(FramePool)char[size];
file.read(ptr, size);
return std::string_view(ptr, size);
}
void writeFile(const char* file_path, std::string_view data) {
std::ofstream file(file_path, 0);
@ -134,43 +40,40 @@ void genLua(const char* file_path, const pmr::vector<MacroData>& mdList) {
oss << '}';
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) {
api::Guid guid;
guid.a = 1243;
std::string_view data = api::JsonSerialize(guid);
auto res = api::JsonDeserialize<api::Guid>(data);
if (res) {
api::Guid g2 = res.value();
int a = g2.a;
int b = g2.b;
std::string_view text = readFile(file_path);
api::ModuleInfo info;
api::JsonDeserialize<api::ModuleInfo>(text, &info);
bool bchange = false;
for (auto& md : mdList) {
if (md.macro == IMPLEMENT_DYNAMIC_MODULE || md.macro == IMPLEMENT_STATIC_MODULE) {
api::Name name = md.args[1].c_str();
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() {
const char* file_path = R"(F:\engine\zengine\engine\modules\render\vulkan\include\vulkan\module.h)";
auto mdList = readFile(file_path);
genLua(R"(F:\engine\zengine\build\.gens\vulkan\windows\xmake.lua)", mdList);
genPlugin(R"(F:\engine\zengine\build\.gens\vulkan\windows\xmake.lua)", mdList);
int main(int argc, char* argv[]) {
if (argc < 6) {
return -1;
}
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;
}

View File

@ -1,3 +1,8 @@
tool_target("make_plugin")
add_files("src/main.cpp")
add_deps("core")
add_includedirs("src")
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)
import("lib.detect.find_file")
import("lib.detect.find_program")
import("lib.detect.find_tool")
local sdkdir = sdkdir or path.join(os.projectdir(), "tools")
local tool = find_tool(name, {pathes = {sdkdir, "/usr/local/bin"}})
local prog = tool and tool.program or find_program(name, {pathes = {sdkdir, "/usr/local/bin"}})
prog = prog or find_file(name, {sdkdir})
local exedir = find_exe_dir()
local tool = find_tool(name, {pathes = {sdkdir, exedir, "/usr/local/bin"}})
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 os.host() ~= "windows" then
local outdata, errdata = os.iorun("which " .. name)
@ -21,7 +30,7 @@ function find_my_program(name, sdkdir, use_next)
if not use_next then
return find_my_program(name, path.join(sdkdir, name), true)
end
print(name .. "_f not found! under " .. sdkdir)
print(name .. " not found! under " .. sdkdir, exedir)
return
end
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")
function cmd_compile(target, genfile, file)
local res = [[
{
{"core", { public = true}},
{"asset", { public = true}},
}
]]
io.writefile(genfile, res)
local dependency = io.load(genfile)
for k,v in ipairs(dependency) do
--target:add("deps", v[1], v[2])
end
import("find_sdk")
print("find make_plugin", is_mode("debug"))
local plugin = find_sdk.find_my_program("make_plugin")
if not plugin then return end
print("cmd_compile plugin", genfile, file)
argv = { os.projectdir() , genfile, target:scriptdir(), file, target:name() .. ".plugin"}
os.execv(plugin.program, argv)
end
function main(target, file)
local sourcedir = path.join(target:autogendir({root = true}), target:plat())
if not os.isdir(sourcedir) then
os.mkdir(sourcedir)
end
local genfile = sourcedir .. "\\xmake.lua"
local genfile = path.join(sourcedir,"xmake.lua")
local dependfile = target:dependfile(genfile)
depend.on_changed(
function()
cmd_compile(target, genfile, file)
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

View File

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