diff --git a/include/iwa/class.hpp b/include/iwa/class.hpp new file mode 100644 index 0000000..a80d4b2 --- /dev/null +++ b/include/iwa/class.hpp @@ -0,0 +1,71 @@ + +#pragma once + +#if !defined(IWA_CLASS_HPP_INCLUDED) +#define IWA_CLASS_HPP_INCLUDED + +#include +#include + +namespace iwa +{ +struct Function +{ + const char* name; +}; + +struct ClassCreationArgs +{ + const class Class* parent = nullptr; + std::string name; + std::vector functions; +}; + +class Class +{ +private: + const Class* mParent; + std::string mName; + std::vector 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 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 + ClassBuilder& addFunction(const char* name, TFunction func) + { + (void) func; + mFunctions.push_back({.name = name}); + return *this; + } +}; +} + +#endif // !defined(IWA_CLASS_HPP_INCLUDED) diff --git a/include/iwa/instance.hpp b/include/iwa/instance.hpp index 8ac6d09..174d2cf 100644 --- a/include/iwa/instance.hpp +++ b/include/iwa/instance.hpp @@ -110,6 +110,9 @@ public: } return static_cast(*extensionPtr); } + + // reflection + static inline void buildClass(ClassBuilder& builder) noexcept; private: void runDeleters(bool runAll = false); @@ -152,6 +155,13 @@ mijin::FuturePtr> Instance::runOnMainThread(TFun } }(std::forward(function))); } + +void Instance::buildClass(ClassBuilder& builder) noexcept +{ + super_t::buildClass(builder); + + builder.addFunction("isQuitRequested", &Instance::isQuitRequested); +} } #endif // IWA_VULKAN_INSTANCE_HPP_INCLUDED diff --git a/include/iwa/object.hpp b/include/iwa/object.hpp index 8dcfe68..c699c76 100644 --- a/include/iwa/object.hpp +++ b/include/iwa/object.hpp @@ -9,10 +9,13 @@ #include #include #include +#include #include #include #include +#include #include +#include "iwa/class.hpp" #if !defined(IWA_OBJECTPTR_TRACKING) # if !defined(KAZAN_RELEASE) @@ -305,6 +308,25 @@ namespace impl void registerObject(BaseObject* object) noexcept; void unregisterObject(BaseObject* object) noexcept; [[nodiscard]] ObjectPtr getRegisteredObject(object_id_t objectId) noexcept; +[[nodiscard]] constexpr std::string getClassNameFromSourceLocation(const std::source_location& sourceLocation) noexcept +{ + const char* ERROR_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("TConcrete = "); + if (pos == std::string_view::npos) { + return ERROR_NAME; + } + const std::size_t begin = pos + 12; + 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 ""; +#endif +} } class BaseObject @@ -339,6 +361,8 @@ public: [[nodiscard]] inline object_id_t getId() const noexcept { return mId; } [[nodiscard]] inline ObjectPtr getPointer(bool skipCheck = false) noexcept; [[nodiscard]] inline WeakObjectPtr getWeakPointer() noexcept; + + [[nodiscard]] virtual const Class& getClass() const = 0; protected: inline void increaseReferenceCount() noexcept { @@ -393,6 +417,30 @@ public: #endif return child; } + + const Class& getClass() const override + { + return getClassObject(); + } + + static const Class& getClassObject() noexcept + { + static const Class myClass = [](std::string&& name) + { + ClassBuilder builder(std::move(name)); + TConcrete::buildClass(builder); + return builder.make(); + }(impl::getClassNameFromSourceLocation(std::source_location::current())); + return myClass; + } + + static void buildClass(ClassBuilder& builder) noexcept + { + if constexpr (!std::is_same_v) + { + builder.setParent(&TBase::getClassObject()); + } + } public: template static ObjectPtr create(TArgs&&... args); @@ -411,6 +459,30 @@ public: [[nodiscard]] TOwner* getOwner() const noexcept { return static_cast(TBase::mOwner.getRaw()); } [[nodiscard]] ObjectPtr getPointer(bool skipCheck = false) noexcept { return static_cast>(BaseObject::getPointer(skipCheck)); } [[nodiscard]] WeakObjectPtr getWeakPointer() noexcept { return static_cast>(BaseObject::getWeakPointer()); } + + const Class& getClass() const override + { + return getClassObject(); + } + + static const Class& getClassObject() noexcept + { + static const Class myClass = [](std::string&& name) + { + ClassBuilder builder(std::move(name)); + TConcrete::buildClass(builder); + return builder.make(); + }(impl::getClassNameFromSourceLocation(std::source_location::current())); + return myClass; + } + + static void buildClass(ClassBuilder& builder) noexcept + { + if constexpr (!std::is_same_v) + { + builder.setParent(&TBase::getClassObject()); + } + } }; template @@ -543,6 +615,7 @@ struct std::hash> // NOLINT false positive std::size_t operator()(const iwa::ObjectPtr& ptr) const noexcept { return std::hash()(ptr.getRaw()); + } };