More foundation for more reflection.

This commit is contained in:
Patrick 2024-05-21 23:44:46 +02:00
parent 433c3b4633
commit cd886cefff
9 changed files with 223 additions and 78 deletions

View File

@ -55,6 +55,7 @@ src_files = Split("""
source/shader_module.cpp
source/swapchain.cpp
source/texture.cpp
source/type_meta.cpp
source/window.cpp
source/app/vulkan_application.cpp

View File

@ -1,71 +0,0 @@
#pragma once
#if !defined(IWA_CLASS_HPP_INCLUDED)
#define IWA_CLASS_HPP_INCLUDED
#include <string>
#include <vector>
namespace iwa
{
struct Function
{
const char* name;
};
struct ClassCreationArgs
{
const class Class* parent = nullptr;
std::string name;
std::vector<Function> functions;
};
class Class
{
private:
const Class* mParent;
std::string mName;
std::vector<Function> mFunctions;
public:
explicit Class(ClassCreationArgs args) noexcept : mParent(args.parent), mName(std::move(args.name)) {}
[[nodiscard]] const std::string& getName() const noexcept { return mName; }
[[nodiscard]] const Class* getParent() const noexcept { return mParent; }
};
class ClassBuilder
{
private:
const Class* mParent = nullptr;
std::string mName;
std::vector<Function> mFunctions;
public:
explicit ClassBuilder(std::string name) noexcept : mName(std::move(name)) {}
ClassBuilder& setParent(const Class* parent) noexcept
{
mParent = parent;
return *this;
}
Class make() noexcept
{
return Class({
.parent = mParent,
.name = std::move(mName),
.functions = std::move(mFunctions)
});
}
template<typename TFunction>
ClassBuilder& addFunction(const char* name, TFunction func)
{
(void) func;
mFunctions.push_back({.name = name});
return *this;
}
};
}
#endif // !defined(IWA_CLASS_HPP_INCLUDED)

View File

@ -112,7 +112,7 @@ public:
}
// reflection
static inline void buildClass(ClassBuilder& builder) noexcept;
static inline void buildClass(ClassBuilder<Instance>& builder) noexcept;
private:
void runDeleters(bool runAll = false);
@ -156,7 +156,7 @@ mijin::FuturePtr<std::invoke_result_t<TFunction>> Instance::runOnMainThread(TFun
}(std::forward<TFunction>(function)));
}
void Instance::buildClass(ClassBuilder& builder) noexcept
void Instance::buildClass(ClassBuilder<Instance>& builder) noexcept
{
super_t::buildClass(builder);

View File

@ -15,7 +15,7 @@
#include <vector>
#include <mijin/detect.hpp>
#include <mijin/debug/assert.hpp>
#include "iwa/class.hpp"
#include "iwa/type_meta.hpp"
#if !defined(IWA_OBJECTPTR_TRACKING)
# if !defined(KAZAN_RELEASE)
@ -427,14 +427,14 @@ public:
{
static const Class myClass = [](std::string&& name)
{
ClassBuilder builder(std::move(name));
ClassBuilder<TConcrete> builder(std::move(name));
TConcrete::buildClass(builder);
return builder.make();
}(impl::getClassNameFromSourceLocation(std::source_location::current()));
return myClass;
}
static void buildClass(ClassBuilder& builder) noexcept
static void buildClass(ClassBuilder<TConcrete>& builder) noexcept
{
if constexpr (!std::is_same_v<TBase, BaseObject>)
{
@ -469,14 +469,14 @@ public:
{
static const Class myClass = [](std::string&& name)
{
ClassBuilder builder(std::move(name));
ClassBuilder<TConcrete> builder(std::move(name));
TConcrete::buildClass(builder);
return builder.make();
}(impl::getClassNameFromSourceLocation(std::source_location::current()));
return myClass;
}
static void buildClass(ClassBuilder& builder) noexcept
static void buildClass(ClassBuilder<TConcrete>& builder) noexcept
{
if constexpr (!std::is_same_v<TBase, BaseObject>)
{

186
include/iwa/type_meta.hpp Normal file
View File

@ -0,0 +1,186 @@
#pragma once
#if !defined(IWA_CLASS_HPP_INCLUDED)
#define IWA_CLASS_HPP_INCLUDED
#include <source_location>
#include <span>
#include <string>
#include <vector>
#include <mijin/util/traits.hpp>
namespace iwa
{
struct Function
{
const char* name;
};
struct Property
{
const char* name;
};
struct ClassCreationArgs
{
const class Class* parent = nullptr;
std::string name;
std::vector<Function> functions;
std::vector<Property> properties;
};
class Class
{
private:
const Class* mParent;
std::string mName;
std::vector<Function> mFunctions;
std::vector<Property> mProperties;
public:
explicit Class(ClassCreationArgs args) noexcept : mParent(args.parent), mName(std::move(args.name)),
mFunctions(std::move(args.functions)), mProperties(std::move(args.properties)) {}
[[nodiscard]] const Class* getParent() const noexcept { return mParent; }
[[nodiscard]] const std::string& getName() const noexcept { return mName; }
[[nodiscard]] const std::vector<Function>& getFunctions() const noexcept { return mFunctions; }
[[nodiscard]] const std::vector<Property>& getProperties() const noexcept { return mProperties; }
};
template<typename TObject>
class ClassBuilder
{
private:
const Class* mParent = nullptr;
std::string mName;
std::vector<Function> mFunctions;
std::vector<Property> mProperties;
public:
explicit ClassBuilder(std::string name) noexcept : mName(std::move(name)) {}
ClassBuilder& setParent(const Class* parent) noexcept
{
mParent = parent;
return *this;
}
[[nodiscard]] Class make() noexcept
{
return Class({
.parent = mParent,
.name = std::move(mName),
.functions = std::move(mFunctions),
.properties = std::move(mProperties)
});
}
template<typename TFunction>
ClassBuilder& addFunction(const char* name, TFunction func)
{
(void) func;
mFunctions.push_back({.name = name});
return *this;
}
template<typename TField>
ClassBuilder& addProperty(const char* name, TField TObject::* field)
{
(void) field;
mProperties.push_back({.name = name});
return *this;
}
};
template<typename TObject>
class ClassRegisterer
{
public:
ClassRegisterer() noexcept {
registerClass(&TObject::getClassObject());
}
};
#define IWA_REGISTER_CLASS(clazz) \
namespace \
{ \
[[maybe_unused]] ClassRegisterer<clazz> gRegisterer; \
}
struct StructCreationArgs
{
std::string name;
};
class Struct
{
private:
std::string mName;
public:
explicit Struct(StructCreationArgs args) noexcept : mName(std::move(args.name)) {}
[[nodiscard]] const std::string& getName() const noexcept { return mName; }
};
template<typename TStruct>
class StructBuilder
{
private:
std::string mName;
public:
explicit StructBuilder(std::string name) noexcept : mName(std::move(name)) {}
[[nodiscard]] Struct make() noexcept
{
return Struct({
.name = std::move(mName)
});
}
};
void registerClass(const Class* clazz) noexcept;
[[nodiscard]] std::span<const Class*> getRegisteredClasses() noexcept;
template<typename TStruct>
void buildStruct(StructBuilder<TStruct>& /* builder */) noexcept
{
static_assert(mijin::always_false_v<TStruct>, "Missing buildStruct() function.");
}
namespace impl
{
[[nodiscard]] constexpr std::string getStructNameFromSourceLocation(const std::source_location& sourceLocation) noexcept
{
const char* ERROR_NAME = "<error detecting struct name>";
#if MIJIN_COMPILER == MIJIN_COMPILER_GCC || MIJIN_COMPILER == MIJIN_COMPILER_CLANG
const std::string_view functionName = sourceLocation.function_name();
const std::size_t pos = functionName.find("TStruct = ");
if (pos == std::string_view::npos)
{
return ERROR_NAME;
}
const std::size_t begin = pos + 10;
const std::size_t end = functionName.find(']', begin);
if (end == std::string_view::npos)
{
return ERROR_NAME;
}
return std::string(functionName.substr(begin, end - begin));
#else
return "<unsupported compiler family>";
#endif
}
}
template<typename TStruct>
const Struct& reflectStruct() noexcept
{
static const Struct theStruct = [](std::string&& name)
{
StructBuilder<TStruct> builder(std::move(name));
buildStruct(builder);
return builder.make();
}(impl::getStructNameFromSourceLocation(std::source_location::current()));
return theStruct;
}
}
#endif // !defined(IWA_CLASS_HPP_INCLUDED)

View File

@ -81,6 +81,13 @@ public:
mijin::Signal<> mouseLeft;
mijin::Signal<> closeRequested;
};
// reflection
template<>
inline void buildStruct<WindowCreationArgs>(StructBuilder<WindowCreationArgs>& builder) noexcept
{
(void) builder;
}
}
#endif //IWA_WINDOW_HPP_INCLUDED

View File

@ -13,6 +13,8 @@ VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
namespace iwa
{
IWA_REGISTER_CLASS(Instance)
namespace
{
void buildDefaultInstanceExtensionList(std::vector<ExtensionInfo>& outExtensions) noexcept

18
source/type_meta.cpp Normal file
View File

@ -0,0 +1,18 @@
#include "iwa/type_meta.hpp"
namespace iwa
{
namespace
{
std::vector<const Class*> gClassRegistry;
}
void registerClass(const Class* clazz) noexcept
{
gClassRegistry.push_back(clazz);
}
std::span<const Class*> getRegisteredClasses() noexcept
{
return gClassRegistry;
}
}

View File

@ -9,6 +9,8 @@ namespace iwa
{
inline constexpr const char* WINDOW_DATA_NAME = "iwa_window";
IWA_REGISTER_CLASS(Window)
namespace
{
Window* gLastEventWindow = nullptr;