add module

This commit is contained in:
ouczbs 2024-07-20 18:04:19 +08:00
commit 1d96f31f52
50 changed files with 1375 additions and 0 deletions

7
.gitignore vendored Normal file
View File

@ -0,0 +1,7 @@
.vs/
.vscode/.cache/
.vscode/compile_commands.json
.xmake/
build/
vsxmake*/
/tools

View File

View File

@ -0,0 +1,5 @@
static_component("asset","engine")
add_includedirs("include/asset")
add_headerfiles("include/**.h")
add_files("src/**.cpp")
add_deps("core", {public = true})

View File

@ -0,0 +1,25 @@
namespace api {
struct IDynamicModule : public IModule {
virtual ~IDynamicModule() override
{
}
SharedLibrary mSharedLib;
};
struct IStaticModule : public IModule {
};
struct IHotfixModule : public IDynamicModule {
void* state = nullptr;
//IHotfixModule(){ mInfo.flag |= EModuleFlag::Reload; }
virtual void OnBeginLoad() = 0;
virtual void OnEndLoad() = 0;
};
}
#define IMPLEMENT_STATIC_MODULE(ModuleImplClass, ModuleName) \
inline static const api::ModuleRegistrantImpl<ModuleImplClass> __RegisterModule##ModuleName((const char*)#ModuleName);
#define IMPLEMENT_DYNAMIC_MODULE(ModuleImplClass, ModuleName) \
extern "C" api::IModule* __newDynamicModule##ModuleName() \
{ \
return new ModuleImplClass(); \
}
#define MODULE_DEPENDENCY(name, opt)

View File

@ -0,0 +1,31 @@
#pragma once
#include "moudle.h"
namespace api {
template<typename T1, typename T2, typename Hasher = std::hash<T1>>
using table = std::pmr::unordered_map<T1, T2, Hasher>;
class ModuleManager
{
friend struct IModule;
private:
SharedLibrary mProcessLib;
table<Name, IModule*> mModuleTable;
public:
ModuleManager() = default;
IModule* GetModule(Name name);
bool RegisterModule(Name name, IModule::CreatePFN fn);
static ModuleManager* Ptr();
};
struct empty {
};
static empty e;
template <typename ModuleClass>
struct ModuleRegistrantImpl {
ModuleRegistrantImpl(const char* InModuleName)
{
ModuleManager::Ptr()->RegisterModule(InModuleName, []() {
return new ModuleClass();
});
}
};
}

View File

@ -0,0 +1,58 @@
#pragma once
#include "pmr/name.h"
#include "macro.h"
#include "os/shared_library.h"
namespace api {
using pmr::Name;
enum class EModuleFlag : uint32_t {
Reload = 1,
};
ENABLE_BITMASK_OPERATORS(EModuleFlag);
struct ModuleInfo {
EModuleFlag flag;
Name name; //!< name of the plugin
Name prettyname; //!< formatted name of the plugin
Name core_version; //!< version of the engine
Name version; // !< version of the plugin
Name linking; // !< linking of the plugin
Name license; //!< license of the plugin
Name url; //!< url of the plugin
Name copyright; //!< copyright of the plugin
public:
bool IsReload() {
return !!(flag & EModuleFlag::Reload);
}
};
struct IModuleSubsystem
{
using CreatePFN = IModuleSubsystem* (*)();
virtual ~IModuleSubsystem() = default;
virtual void Initialize() = 0;
virtual void Finalize() = 0;
virtual void BeginLoad() {}
virtual void EndLoad() {}
};
struct IModule {
friend class ModuleManagerImpl;
public:
using CreatePFN = IModule * (*)();
IModule() = default;
IModule(const IModule& rhs) = delete;
IModule& operator=(const IModule& rhs) = delete;
virtual ~IModule() {};
virtual void OnLoad(int argc, char** argv) = 0;
virtual void OnUnload() = 0;
virtual const char* MetaData(void) = 0;
virtual int Main(int argc, char** argv) { return 0; }
virtual const ModuleInfo* GetModuleInfo()
{
return &mInfo;
}
protected:
ModuleInfo mInfo;
std::vector<IModuleSubsystem*> mSubSystems;
};
}
#include "module.inl"

View File

@ -0,0 +1,5 @@
#include <string>
namespace fs {
std::string GetExecutablePath();
std::string GetWorkPath();
}

View File

@ -0,0 +1,9 @@
#pragma once
namespace api {
using NativeLibHandle = void*;
class SharedLibrary {
NativeLibHandle mHandle;
public:
bool Load(const char* path = nullptr);
};
}

View File

View File

@ -0,0 +1,25 @@
#include "module/module_manager.h"
namespace api {
ModuleManager* ModuleManager::Ptr()
{
static ModuleManager* ptr;
if (ptr) {
return ptr;
}
ptr = new ModuleManager();
ptr->mProcessLib.Load();
return ptr;
}
IModule* ModuleManager::GetModule(Name name)
{
auto it = mModuleTable.find(name);
if (it == mModuleTable.end()) {
return nullptr;
}
return it->second;
}
bool ModuleManager::RegisterModule(Name name, IModule::CreatePFN fn)
{
return false;
}
}

View File

@ -0,0 +1,47 @@
#include "os/file_system.h"
#include <filesystem>
#ifdef _WIN32
#include <windows.h>
#elif __linux__
#include <unistd.h>
#include <limits.h>
#elif __APPLE__
#include <mach-o/dyld.h>
#include <limits.h>
#endif
namespace fs {
std::string _GetExecutablePath() {
#ifdef _WIN32
char path[MAX_PATH];
GetModuleFileName(NULL, path, MAX_PATH);
return std::string(path);
#elif __linux__
char result[PATH_MAX];
ssize_t count = readlink("/proc/self/exe", result, PATH_MAX);
return std::string(result, (count > 0) ? count : 0);
#elif __APPLE__
char path[PATH_MAX];
uint32_t size = sizeof(path);
if (_NSGetExecutablePath(path, &size) == 0) {
char realPath[PATH_MAX];
realpath(path, realPath);
return std::string(realPath);
}
else {
return std::string("");
}
#endif
}
std::string GetExecutablePath() {
std::string path = _GetExecutablePath();
size_t pos = path.find_last_of("\\/");
return (std::string::npos == pos) ? "" : path.substr(0, pos);
}
std::string GetWorkPath() {
auto path = std::filesystem::current_path();
return path.string();
}
}

View File

@ -0,0 +1,21 @@
#include "os/shared_library.h"
#include <Windows.h>
namespace api {
bool SharedLibrary::Load(const char* path)
{
if (path == nullptr)
{
mHandle = GetModuleHandle(nullptr);
}
else
{
mHandle = GetModuleHandle(path);
if (mHandle == NULL)
{
mHandle = LoadLibrary(path);
}
}
return mHandle;
}
}

View File

@ -0,0 +1,6 @@
static_component("core","engine")
add_includedirs("include", {public = true})
add_headerfiles("include/**.h","include/**.inl")
add_files("src/**.cpp")
add_deps("zlib", {public = true})
--add_syslinks("Kernel32")

View File

@ -0,0 +1,9 @@
#define ENABLE_BITMASK_OPERATORS(bitmask) \
inline bitmask operator|(bitmask a, bitmask b) { return static_cast<bitmask>(static_cast<std::underlying_type_t<bitmask>>(a) | static_cast<std::underlying_type_t<bitmask>>(b)); } \
inline bitmask operator&(bitmask a, bitmask b) { return static_cast<bitmask>(static_cast<std::underlying_type_t<bitmask>>(a) & static_cast<std::underlying_type_t<bitmask>>(b)); } \
inline bitmask operator^(bitmask a, bitmask b) { return static_cast<bitmask>(static_cast<std::underlying_type_t<bitmask>>(a) ^ static_cast<std::underlying_type_t<bitmask>>(b)); } \
inline bitmask operator~(bitmask a) { return static_cast<bitmask>(~static_cast<std::underlying_type_t<bitmask>>(a)); } \
inline bitmask &operator|=(bitmask &a, bitmask b) { return a = a | b; } \
inline bitmask &operator&=(bitmask &a, bitmask b) { return a = a & b; } \
inline bitmask &operator^=(bitmask &a, bitmask b) { return a = a ^ b; } \
inline bool operator!(bitmask a){return static_cast<std::underlying_type_t<bitmask>>(a) == 0;}

View File

@ -0,0 +1,47 @@
#pragma once
#include <vector>
#include <memory_resource>
namespace pmr {
class FrameAllocator : public std::pmr::memory_resource {
private:
char* buffer;
size_t capacity;
size_t offset;
public:
// 删除拷贝构造函数
FrameAllocator(const FrameAllocator&) = delete;
FrameAllocator& operator=(const FrameAllocator&) = delete;
FrameAllocator(FrameAllocator&& o) noexcept;
FrameAllocator& operator=(FrameAllocator&& o)noexcept;
public:
FrameAllocator(size_t size) noexcept;
~FrameAllocator() noexcept;
bool empty() const { return offset == 0; }
void reset() { offset = 0; };
void* try_allocate(size_t bytes, size_t alignment);
protected:
void move_clear() { buffer = nullptr; capacity = 0; offset = 0; };
void* do_allocate(size_t bytes, size_t alignment) override;
void do_deallocate(void* p, size_t bytes, size_t alignment) override {};
bool do_is_equal(const std::pmr::memory_resource& other) const noexcept override { return this == &other; };
};
class FrameAllocatorPool : public std::pmr::memory_resource {
public:
FrameAllocatorPool(size_t allocatorSize = 1024 * 1024) noexcept : allocatorSize(allocatorSize) {}
void* allocate(size_t bytes, size_t alignment);
void reset();
void* do_allocate(size_t bytes, size_t alignment) override { return allocate(bytes, alignment); }
void do_deallocate(void* p, size_t bytes, size_t alignment) override {};
bool do_is_equal(const std::pmr::memory_resource& other) const noexcept override { return this == &other; };
private:
size_t allocatorSize;
std::vector<FrameAllocator> allocators{};
};
};
// 自定义的new操作符
inline void* operator new(size_t size, pmr::FrameAllocatorPool& pool, size_t alignment = alignof(std::max_align_t)) {
size = (size + alignment - 1) & ~(alignment - 1);
return pool.allocate(size, alignment);
}
#include "frame_allocator.inl"

View File

@ -0,0 +1,62 @@
namespace pmr {
inline FrameAllocator& FrameAllocator::operator=(FrameAllocator&& o)noexcept
{
std::construct_at(this, std::forward<FrameAllocator&&>(o));
return *this;
}
inline FrameAllocator::FrameAllocator(FrameAllocator&& o) noexcept :buffer(o.buffer),capacity(o.capacity),offset(o.offset)
{
o.move_clear();
}
inline FrameAllocator::FrameAllocator(size_t size)noexcept
{
buffer = new char[size];
capacity = size;
offset = 0;
}
inline FrameAllocator::~FrameAllocator()noexcept
{
if(buffer)
delete[] buffer;
}
inline void* FrameAllocator::try_allocate(size_t bytes, size_t alignment)
{
if (capacity - offset > bytes) {
return do_allocate(bytes, alignment);
}
return nullptr;
}
inline void* FrameAllocator::do_allocate(size_t bytes, size_t alignment)
{
size_t space = capacity - offset;
void* ptr = buffer + offset;
if (std::align(alignment, bytes, ptr, space)) {
offset = capacity - space + bytes;
return ptr;
}
throw std::bad_alloc();
}
inline void* FrameAllocatorPool::allocate(size_t bytes, size_t alignment)
{
for (auto& alllocator : allocators) {
if (auto ptr = alllocator.try_allocate(bytes, alignment)) {
return ptr;
}
}
// 如果所有现有的分配器都没有足够的空间,则创建一个新的分配器
auto& it = allocators.emplace_back(allocatorSize);
return it.allocate(bytes, alignment);
}
inline void FrameAllocatorPool::reset()
{
size_t count = 0;
for (auto& allocator : allocators) {
if (!allocator.empty()) {
allocator.reset();
count++;
}
}
count = count > 0 ? count : 1;
allocators.erase(allocators.begin() + count, allocators.end());
}
};

View File

@ -0,0 +1,88 @@
#pragma once
#include "frame_allocator.h"
#include <unordered_map>
namespace pmr
{
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 {
size_t hash;
#ifdef Z_DEBUG
std::string_view value;
#endif // Z_DEBUG
public:
Name():hash(NameID::InvalidValue()) {};
Name(const char* str)noexcept;
template<size_t N>
constexpr Name(const char(&str)[N]) 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; }
std::string ToString() const;
const std::string_view ToStringView() const;
operator std::string() const { return ToString(); }
};
constexpr inline size_t string_hash(std::string_view str) noexcept
{
constexpr size_t fnv_offset_basis = 0xcbf29ce484222325;
constexpr size_t fnv_prime = 0x100000001b3;
auto hash = fnv_offset_basis;
for (auto& elem : str)
{
hash *= fnv_prime;
hash ^= elem;
}
hash *= fnv_prime;
hash ^= 0;
return hash;
}
}
namespace std {
template<>
struct hash<::pmr::NameID>
{
size_t operator()(const ::pmr::NameID& ID) const noexcept
{
return ID.GetValue();
}
};
template<>
struct hash<::pmr::Name>
{
size_t operator()(const ::pmr::Name& ID) const noexcept
{
return ID.GetValue();
}
};
}
#include "name.inl"

View File

@ -0,0 +1,77 @@
namespace pmr {
using NameTable_t = std::pmr::unordered_map<size_t,const std::pmr::string>;
struct NameTable {
static const std::pmr::string& Find(size_t id);
template<typename T>
static std::string_view MakePair(size_t id, T&& str);
static NameTable_t BuildNameTable() {
static FrameAllocatorPool MemPool;
return NameTable_t(&MemPool);
}
inline static NameTable_t Table = BuildNameTable();
};
template<typename T>
inline std::string_view NameTable::MakePair(size_t id, T&& str)
{
auto it = Table.find(id);
if (it == Table.end()) {
auto it2 = Table.emplace(std::make_pair(id, std::pmr::string(str, Table.get_allocator())));
if (it2.second) {
return it2.first->second;
}
return nullptr;
}
return it->second;
}
inline const std::pmr::string& NameTable::Find(size_t id)
{
auto it = Table.find(id);
if (it == Table.end()) {
static std::pmr::string empty("", Table.get_allocator());
return empty;
}
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 Z_DEBUG
#define MAKE_NAME_PAIR(hash, str) value = NameTable::MakePair(hash, str)
#define NAME_TO_STRING value
#else
#define MAKE_NAME_PAIR(hash, str) NameTable::MakePair(hash, str)
#define NAME_TO_STRING NameTable::Find(hash)
#endif
inline std::string Name::ToString() const
{
return std::string(NAME_TO_STRING);
}
inline const std::string_view Name::ToStringView() const
{
return std::string_view(NAME_TO_STRING);
}
inline Name::Name(const char* str) noexcept: hash(string_hash(str))
{
MAKE_NAME_PAIR(hash, str);
}
template<std::size_t N>
inline constexpr Name::Name(const char(&str)[N]) noexcept : hash(string_hash(str))
{
MAKE_NAME_PAIR(hash, str);
}
inline Name::Name(const std::string& str) noexcept : hash(string_hash(str))
{
MAKE_NAME_PAIR(hash, str);
}
inline Name::Name(std::string_view str) noexcept : hash(string_hash(str))
{
MAKE_NAME_PAIR(hash, str);
}
#undef MAKE_NAME_PAIR
#undef NAME_TO_STRING
}

View File

@ -0,0 +1,42 @@
#pragma once
#include "type.h"
namespace refl {
class UClass;
struct Any {
public:
const void* ptr;
const UClass* cls;
public:
constexpr Any() : ptr(nullptr), cls(nullptr) {}
constexpr Any(const void* ptr, const UClass* cls) : ptr(ptr), cls(cls) {}
template<typename T>
constexpr Any(T&& v) : ptr(&v), cls(TypeInfo<args_type_t<T>>::StaticClass) {
if constexpr (std::is_same_v<args_type_t<T>, Any>) {
ptr = v.ptr;
cls = v.cls;
}
}
template<typename T>
constexpr Any(T* v) : ptr(v), cls(&TypeInfo<args_type_t<T>>::StaticClass) {
if constexpr (std::is_same_v<args_type_t<T>, Any>) {
ptr = v->ptr;
cls = v->cls;
}
}
template<typename T>//参数 T* => T*
constexpr inline T CastTo() const {
if constexpr (std::is_pointer_v<T>) {
return (T)ptr;
}
else if constexpr (std::is_reference_v<T>) {
using RT = std::remove_reference_t<T>;
return *(RT*)ptr;
}
else {
return *(T*)ptr;
}
}
public:
bool Check(const UClass* parent) const;
};
}

View File

@ -0,0 +1,14 @@
#include "any.h"
#include "uclass.h"
namespace refl{
bool Any::Check(const UClass* parent)const
{
if (cls == parent) {
return true;
}
if (!cls || !parent) {
return false;
}
return cls->IsChildOf(parent);
}
}

View File

@ -0,0 +1,51 @@
#pragma once
#include "pmr/name.h"
#include "any.h"
#include <span>
namespace refl {
using pmr::Name;
using std::span;
using Offset = uint32_t;
using Method = void*;
struct MemberData {
Offset offset{ 0 };
Any value;
Any meta;
constexpr MemberData() :value(), meta() {}
constexpr MemberData(const Any& value, const Any& meta = {}) : value(value), meta(meta) {}
constexpr MemberData(Offset offset, const Any& value, const Any& meta) : offset(offset), value(value), meta(meta) {}
};
struct MethodData {
Method fptr{ nullptr };
span<Any> value;
Any meta;
constexpr MethodData() :value(), meta() {}
constexpr MethodData(span<Any> value, const Any& meta = {}) : value(value), meta(meta) {}
constexpr MethodData(Method fptr, span<Any> value, const Any& meta) : fptr(fptr), value(value), meta(meta) {}
};
enum FieldFlag :uint32_t {
FIELD_NONE_FLAG = 0,
FIELD_MEMBER_FLAG = 1 << 0,
FIELD_METHOD_FLAG = 1 << 1,
FIELD_CTOR_FLAG = 1 << 2,
FIELD_VALUE_FLAG = 1 << 3,
};
using enum FieldFlag;
struct FieldPtr {
union Data
{
MemberData member;
MethodData method;
constexpr Data() : member() {};
constexpr Data(const MemberData& member) :member(member) {}
constexpr Data(const MethodData& method) : method(method) {}
constexpr Data(Offset offset) : member(offset, {}, {}) {}
constexpr Data(Offset offset, const Any& value, const Any& meta) : member(offset, value, meta) {}
constexpr Data(Method fptr, span<Any> value, const Any& meta) : method(fptr, value, meta) {}
};
Name name;
const UClass* type{};
Data data{};
uint32_t flag{};
};
}

View File

@ -0,0 +1,4 @@
#include "field.h"
namespace refl{
}

View File

@ -0,0 +1,28 @@
#pragma once
namespace refl {
template<size_t N>
struct TStr {
std::array<char, N> value;
constexpr TStr() {};
constexpr TStr(const char(&data)[N]) {
for (size_t i = 0; i < N; ++i) {
value[i] = data[i];
}
}
constexpr TStr(std::string_view data) {
for (size_t i = 0; i < N; ++i) {
value[i] = data[i];
}
}
constexpr std::string_view View()const {
return std::string_view(value.data(), N - 1);
}
};
template<size_t N>
TStr(const char(&)[N]) -> TStr<N>;
template<auto v>
constexpr auto value_name() noexcept;
template<typename T>
constexpr auto type_name() noexcept;
}

View File

@ -0,0 +1,91 @@
#include "name.h"
namespace refl {
namespace detail {
template<typename T>
constexpr auto func_signature_impl() noexcept {
# if defined(__clang__)
return std::string_view{ __PRETTY_FUNCTION__ };
# elif defined(__GNUC__)
return std::string_view{ __PRETTY_FUNCTION__ };
# elif defined(_MSC_VER)
return std::string_view{ __FUNCSIG__ };
# endif
}
template<size_t N, size_t M>
constexpr auto concat(const TStr<N>& lhs, const TStr<M>& rhs) {
constexpr size_t L = N + M - 1;
char result[L] = {};
for (size_t i = 0; i < L; ++i) {
result[i] = i < N - 1 ? lhs.value[i] : rhs.value[i - N + 1];
}
return TStr<L>{result};
}
constexpr int _num_digits(int num) {
return num < 10 ? 1 : 1 + _num_digits(num / 10);
}
template <int N, int Digits = _num_digits(N)>
constexpr auto num_name() {
char data[Digits + 1];
int n = N;
for (int i = Digits - 1; i >= 0; --i) {
data[i] = static_cast<char>('0' + n % 10);
n /= 10;
}
data[Digits] = '\0'; // null-terminated string
return TStr{ data };
}
template<typename T>
constexpr auto num_prefix_name() {
if constexpr (std::is_integral_v<T>) {
if constexpr (std::is_signed_v<T>) {
return TStr{ "S" };
}
else {
return TStr{ "U" };
}
}
else if constexpr (std::is_floating_point_v<T>) {
return TStr{ "F" };
}
else {
return TStr{ "D" };
}
}
}
template<auto v>
constexpr auto value_name()noexcept {
using T = decltype(v);
if constexpr (std::is_null_pointer_v<T>)
return TStr{ "nullptr" };
else if constexpr (std::is_pointer_v<T>) {
if constexpr (v == nullptr)
return TStr{ "nullptr" };
else
static_assert("not support");
}
else if constexpr (std::is_integral_v<T>) {
if constexpr (std::is_same_v<T, bool>) {
if constexpr (v == true)
return TStr{ "true" };
else
return TStr{ "false" };
}
else {
return TStr{ "false" };
}
}
}
template<typename T>
constexpr auto type_name() noexcept {
if constexpr (std::is_arithmetic_v<T>) {
constexpr auto prefix = detail::num_prefix_name<T>();
constexpr auto bit = detail::num_name<8 * sizeof(T)>();
return detail::concat(prefix, bit);
}
else {
static_assert("not support");
}
}
}

View File

@ -0,0 +1,104 @@
#pragma once
#include <array>
#include <string>
namespace refl {
namespace detail {
// 定义一个模板结构体用于检测是否为 数组
template<typename T>
struct is_array : std::false_type {};
template<typename T, size_t N>
struct is_array<T[N]> : std::true_type {
using type = T;
consteval static size_t size() { return N; }
};
// 部分特化用于匹配 std::array
template<typename T, size_t N>
struct is_array<std::array<T, N>> : std::true_type {
using type = T;
consteval static size_t size() { return N; }
};
// 定义一个模板结构体用于检测是否为 std::pair
template<typename T>
struct is_pair : std::false_type {};
template<typename T1, typename T2>
struct is_pair<std::pair<T1, T2>> : std::true_type {};
// 定义一个模板结构体用于检测是否为 std::pair
template<typename T>
struct is_tuple : std::false_type {};
template<typename... Types>
struct is_tuple<std::tuple<Types...>> : std::true_type {};
}
template<typename T>
concept is_array_v = detail::is_array<T>::value;
template<typename T>
using is_array_t = detail::is_array<T>::type;
template<typename T>
concept is_pair_v = detail::is_pair<T>::value;
template<typename T>
concept is_tuple_v = detail::is_tuple<T>::value;
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_container_v = !is_array_v<T> && !is_string_v<T> && requires(T a) {
{ a.begin() } -> std::input_iterator;
{ a.end() } -> std::input_iterator;
};
template<typename T>
concept is_map_v = is_pair_v<typename T::value_type> && is_container_v<T>;
template<typename T>
concept is_sequence_v = !is_pair_v<typename T::value_type> && is_container_v<T>;
};
namespace refl {
namespace detail {
template<typename T>
struct real_type {
using type = std::remove_cv_t<T>;
};
template<typename T>
struct real_type<T&> {
using type = std::remove_cv_t<T>*;
};
template<typename T>
struct real_type<T*> {
using type = std::remove_cv_t<T>*;
};
//转化为指针类型
template<typename T>
struct args_type {
using type = T;
};
template<typename T>
struct args_type<T&> {
using type = T;
};
template<typename T>
struct args_type<T*> {
using type = T;
};
}
template<typename T>
using real_type_t = detail::real_type<T>::type;
template<typename T>
using args_type_t = detail::args_type<std::remove_cv_t<T>>::type;
};
namespace refl {
//类型接口
template<typename T>
struct TypeInfoImpl;
template<typename T>
using TypeInfo = TypeInfoImpl<real_type_t<T>>;
}

View File

@ -0,0 +1,86 @@
#pragma once
#include "field.h"
namespace refl {
template<typename T>
using pmr_vector = std::pmr::vector<T>;
enum ClassFlag :uint32_t {
CLASS_NONE_FLAG = 0,
CLASS_TRIVIAL_FLAG = 1 << 0,
CLASS_POINTER_FLAG = 1 << 1,
CLASS_ARRAY_FLAG = 1 << 2,
CLASS_CONTAINER_FLAG = 1 << 3,
CLASS_SEQUENCE_FLAG = 1 << 4,
CLASS_MAP_FLAG = 1 << 5,
CLASS_PARENT_FLAG = 1 << 6,
};
enum EFieldFind :uint32_t {
FIND_ALL_FIELD = 0,
FIND_ALL_MEMBER,
FIND_ALL_METHOD,
FIND_FIELD,
FIND_CTOR,
FIND_MEMBER,
FIND_METHOD,
FIND_METHODS,//函数重载 特别是构造函数
};
struct vtable_uclass
{
//class
span<const FieldPtr>(*GetFields)(const UClass*, EFieldFind find, Name name);
//function
span<const UClass>(*GetParams)(const UClass*);
//function
void (*Call)(const FieldPtr*, span<Any> ArgsList);
//meta
const UClass* (*GetMeta)(Name);
//object
bool (*Construct)(void* ptr, const UClass* cls, span<Any> ArgsList);
void (*Destruct)(void*);
};
class UClass {
public:
Name name;
uint32_t size;
uint32_t flag{0};
const UClass* parent;
vtable_uclass* vtable{nullptr};
public:
UClass(std::string_view name, uint32_t size, const UClass* parent = nullptr)
:name(name), size(size), parent(parent) {}
bool IsChildOf(const UClass* cls, bool bthis = false) const {
const UClass* _parent = bthis ? this : parent;
while (_parent != nullptr) {
if (_parent == cls) {
return true;
}
_parent = _parent->parent;
}
return false;
}
template<typename T>
bool IsChildOf(bool bthis = false) const {
return IsChildOf(TypeInfo<T>::StaticClass, bthis);
}
public:
template<typename T>
static void Destruct(void* ptr) {
std::destroy_at((T*)ptr);
}
template<typename T>
static bool Construct(void* ptr, const UClass* cls, span<Any> ArgsList = {}) {
int argsSize = ArgsList.size();
if (argsSize == 0) {
if constexpr (std::is_constructible_v<T>) {
std::construct_at((T*)ptr);
return true;
}
return false;
}
if (argsSize == 1 && ArgsList[0].Check(cls)) {
*(T*)ptr = *(const T*)ArgsList[0].ptr;
return true;
}
return false;
}
};
}

View File

@ -0,0 +1,44 @@
#include "uclass.h"
#include "name.h"
namespace refl{
namespace detail {
inline static pmr::FrameAllocatorPool MemPool{};
}
template <class T>
concept is_metas_v = false;//requires(const Name & name) { MetaImpl<T>::MyMetas::GetMeta(name); };
template<typename T>
class UClass_Auto : public UClass {
using UClass::UClass;
using MyUClass = UClass_Auto<T>;
public:
static MyUClass* BuildClass() {
MyUClass* cls = new(detail::MemPool)MyUClass(type_name<T>().View(), sizeof(T));
if constexpr (std::is_pointer_v<T>) {
using RT = std::remove_pointer_t<T>;
cls->flag |= CLASS_POINTER_FLAG;
if constexpr (!std::is_same_v<RT, void>) {
cls->parent = TypeInfo<RT>::StaticClass;
}
}
else if constexpr (is_array_v<T>) {
using RT = is_array_t<T>;
cls->flag = CLASS_ARRAY_FLAG;
if constexpr (std::is_pointer_v<RT>) {
cls->flag |= CLASS_POINTER_FLAG;
}
cls->parent = TypeInfo<RT>::StaticClass;
}
else {
cls->vtable = new(detail::MemPool)vtable_uclass();
cls->vtable->Construct = &UClass::Construct<T>;
cls->vtable->Destruct = &UClass::Destruct<T>;
}
return cls;
}
};
template<typename T>
struct TypeInfoImpl {
using MyUClass = UClass_Auto<T>;
inline static MyUClass* StaticClass = MyUClass::BuildClass();
};
}

View File

@ -0,0 +1,4 @@
#pragma once
#include "detail/name.inl"
#include "detail/any.inl"
#include "detail/uclass.inl"

View File

@ -0,0 +1,15 @@
template <typename T>
class Singleton{
protected:
inline static T* ms_Singleton = nullptr;
public:
explicit Singleton() {
ms_Singleton = static_cast<T*>(this);
}
~Singleton() {
ms_Singleton = nullptr;
}
static constexpr T* Ptr(void) {
return ms_Singleton;
}
};

View File

@ -0,0 +1,7 @@
header_component("zlib","engine")
set_basename("myzlib")
add_headerfiles("include/**.h", "include/**.inl")
if is_mode("debug") then
add_defines("Z_DEBUG", {public = true})
end
set_pcheader("include/refl/pch.h")

View File

@ -0,0 +1,11 @@
#include "module/moudle.h"
#include "asset/asset.h"
class VulkanModule : public api::IDynamicModule
{
public:
void OnLoad(int argc, char** argv) override;
void OnUnload() override;
const char* MetaData(void) override;
};
MODULE_DEPENDENCY(core, asset, {public = true})
IMPLEMENT_DYNAMIC_MODULE(VulkanModule, vulkan)

View File

@ -0,0 +1,15 @@
#include "module.h"
void VulkanModule::OnLoad(int argc, char** argv)
{
}
void VulkanModule::OnUnload()
{
}
const char* VulkanModule::MetaData(void)
{
return nullptr;
}

View File

@ -0,0 +1,6 @@
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})

28
engine/modules/xmake.lua Normal file
View File

@ -0,0 +1,28 @@
function header_component(name, owner, opt)
target(owner)
add_deps(name, { public = opt and opt.public or true })
target_end()
target(name)
set_kind("headeronly")
set_group("Engine/"..owner.."__comp")
add_includedirs("include", {public = true})
end
function static_component(name, owner, opt)
target(owner)
add_deps(name, { public = opt and opt.public or true })
target_end()
target(name)
set_kind("static")
set_group("Engine/"..owner.."__comp")
add_includedirs("include", {public = true})
end
function shared_component(name, owner, opt)
target(owner)
add_deps(name, { public = opt and opt.public or true })
target_end()
target(name)
set_kind("shared")
set_group("Engine/"..owner.."__comp")
add_includedirs("include", {public = true})
end
includes("**/xmake.lua")

View File

@ -0,0 +1,145 @@
#include <fstream>
#include <vector>
#include <iostream>
#include <string>
#include <memory_resource>
#include <stack>
#include <optional>
#include <sstream>
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);
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;
}
void writeFile(const char* file_path, std::string_view data) {
std::ofstream file(file_path, 0);
file.write(data.data(), data.size());
file.close();
}
void genLua(const char* file_path, const pmr::vector<MacroData>& mdList) {
std::ostringstream oss;
oss << "{\n";
for (auto& md : mdList) {
if (md.macro == MODULE_DEPENDENCY) {
oss << "\t{";
for (auto& args : md.args) {
if (args[0] != '{') {
oss << '"' << args << "\", ";
}
else {
oss << args;
}
}
oss << "},\n";
}
}
oss << '}';
writeFile(file_path, oss.str());
}
void genPlugin(const char* file_path, const pmr::vector<MacroData>& mdList) {
}
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);
return 0;
}

View File

@ -0,0 +1,2 @@
tool_target("make_plugin")
add_files("src/main.cpp")

6
engine/tools/xmake.lua Normal file
View File

@ -0,0 +1,6 @@
function tool_target(name)
target(name)
set_kind("binary")
set_group("Tools")
end
includes("*/xmake.lua")

9
engine/xmake.lua Normal file
View File

@ -0,0 +1,9 @@
target("editor")
set_kind("static")
set_group("Engine")
target("engine")
set_kind("static")
set_group("Engine")
includes("xmake/xmake.lua")
includes("tools/xmake.lua")
includes("modules/xmake.lua")

View File

@ -0,0 +1,28 @@
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})
if (prog == nil) then
if os.host() ~= "windows" then
local outdata, errdata = os.iorun("which " .. name)
if (errdata ~= nil or errdata ~= "") then
prog = string.gsub(outdata, "%s+", "")
end
else
prog = find_file(name .. ".exe", {sdkdir})
end
end
if (prog == nil) then
if not use_next then
return find_my_program(name, path.join(sdkdir, name), true)
end
print(name .. "_f not found! under " .. sdkdir)
return
end
return {program = prog, sdkdir = sdkdir}
end

View File

@ -0,0 +1,28 @@
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
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 dependfile = target:dependfile(genfile)
depend.on_changed(
function()
cmd_compile(target, genfile, file)
end,
{dependfile = dependfile, files = {file}}
)
end

View File

@ -0,0 +1,7 @@
rule("engine.plugin")
set_extensions(".h")
on_load(function (target)
import("make_plugin")
local file = target:extraconf("rules", "engine.plugin", "file")
make_plugin(target, file or "module.h")
end)

2
engine/xmake/xmake.lua Normal file
View File

@ -0,0 +1,2 @@
includes("*/xmake.lua")
add_moduledirs(path.join(os.projectdir(), "engine/xmake/modules"))

View File

@ -0,0 +1,49 @@
#include <iostream>
#include <array>
#include <charconv>
#include "pmr/frame_allocator.h"
#include "pmr/name.h"
#include "refl/pch.h"
#include "module/module_manager.h"
void test(std::string_view str = "") {
std::cout << "test " << str << std::endl;
}
int main() {
api::ModuleManager::Ptr();
test("sss");
using namespace refl;
constexpr TStr str1{ "Hello" };
constexpr TStr str2{ " world" };
constexpr TStr str3 = detail::concat(str1, str2);
constexpr auto r1 = value_name<8 * sizeof(int)>();
constexpr int v = 12;
auto cls = refl::TypeInfo<int>::StaticClass;
//auto str4 = concat(r1, str2);
auto t1 = refl::type_name<int>();
auto v1 = refl::type_name<int>().View();
auto v2 = t1.View();
if (v1 == t1.View()) {
auto t2 = refl::type_name<int16_t>();
auto t3 = refl::type_name<int8_t>();
}
auto t2 = refl::type_name<int16_t>();
auto t3 = refl::type_name<int8_t>();
pmr::FrameAllocatorPool pool;
pmr::Name name = "hello enginehello enginehello engine\n";
pmr::Name name2("hello enginehello enginehello engine\n");
pmr::Name name3("hello enginehello enginehello engine222\n");
if (name == name2) {
std::string s1 = name.ToString();
std::string s2 = name2.ToString();
if (s1.c_str() == s2.c_str()) {
new(pool)int(1);
}
if (s1 == s2) {
new(pool)int(1);
}
}
int* a = new(pool)int(1);
int* b = new(pool)int(2);
int* c = new(pool)int(3);
std::cout << "hello engine\n";
}

View File

@ -0,0 +1,5 @@
#include "zworld.h"
void hello() {
}

1
game/zworld/src/zworld.h Normal file
View File

@ -0,0 +1 @@
void hello();

11
game/zworld/xmake.lua Normal file
View File

@ -0,0 +1,11 @@
target("zworld")
set_kind("shared")
set_group("Games")
add_deps("engine", "editor", "vulkan", {public = true})
add_files("src/*.cpp")
add_headerfiles("src/*.h")
target("zworld-editor")
set_kind("binary")
set_group("Games")
add_deps("zworld")
add_files("editor/main.cpp")

10
xmake.lua Normal file
View File

@ -0,0 +1,10 @@
add_rules("mode.debug", "mode.release")
set_arch("x64")
set_languages("cxx20")
set_project("zengine")
set_toolchains("clang")
set_runtimes("MD","c++_shared")
includes("engine")
includes("game/*/xmake.lua")
--xmake project -k vsxmake2022 -a x64
--xmake project -k vsxmake2022 -m "debug;release"