From 1e7929eb24682c5c7279d35b1249e2d8d4a3007c Mon Sep 17 00:00:00 2001 From: Ricardo Antunes Date: Tue, 21 Nov 2023 11:17:32 +0000 Subject: [PATCH] feat(reflection): add TypeRegistry --- core/CMakeLists.txt | 1 + .../cubos/core/reflection/type_registry.hpp | 68 +++++++++++++++++++ core/src/cubos/core/reflection/type.cpp | 2 +- .../cubos/core/reflection/type_registry.cpp | 37 ++++++++++ core/tests/CMakeLists.txt | 1 + core/tests/reflection/type.cpp | 1 + core/tests/reflection/type_registry.cpp | 42 ++++++++++++ 7 files changed, 151 insertions(+), 1 deletion(-) create mode 100644 core/include/cubos/core/reflection/type_registry.hpp create mode 100644 core/src/cubos/core/reflection/type_registry.cpp create mode 100644 core/tests/reflection/type_registry.cpp diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt index 1d3ecd11e..5d02d8a44 100644 --- a/core/CMakeLists.txt +++ b/core/CMakeLists.txt @@ -32,6 +32,7 @@ set(CUBOS_CORE_SOURCE "src/cubos/core/memory/any_vector.cpp" "src/cubos/core/reflection/type.cpp" + "src/cubos/core/reflection/type_registry.cpp" "src/cubos/core/reflection/traits/constructible.cpp" "src/cubos/core/reflection/traits/fields.cpp" "src/cubos/core/reflection/traits/array.cpp" diff --git a/core/include/cubos/core/reflection/type_registry.hpp b/core/include/cubos/core/reflection/type_registry.hpp new file mode 100644 index 000000000..824ee4286 --- /dev/null +++ b/core/include/cubos/core/reflection/type_registry.hpp @@ -0,0 +1,68 @@ +/// @file +/// @brief Class @ref cubos::core::reflection::TypeRegistry. +/// @ingroup core-reflection + +#pragma once + +#include + +#include +#include + +namespace cubos::core::reflection +{ + /// @brief Stores a set of types which can be accessed by name. + /// @ingroup core-reflection + class TypeRegistry final + { + public: + /// @brief Registers the given type. + /// + /// Does nothing if the type is already registered. + /// Aborts if a different type with the same name is already registered. + /// + /// @param type Type to register. + void insert(const Type& type); + + /// @copydoc insert(const Type&) + /// @tparam T Type to register. + template + void insert() + { + this->insert(reflect()); + } + + /// @brief Checks if the given type is registered. + /// @param type Type to check. + /// @return Whether the given type is registered. + bool contains(const Type& type) const; + + /// @copydoc contains(const Type&) + /// @tparam T Type to check. + template + bool contains() const + { + return this->contains(reflect()); + } + + /// @brief Checks if a type with the given name is registered. + /// @param name Name of the type. + /// @return Whether a type with the given name is registered. + bool contains(const std::string& name) const; + + /// @brief Returns the type with the given name. + /// + /// Aborts if @ref contains(const std::string&) returns false. + /// + /// @param name Name of the type. + /// @return Type with the given name. + const Type& at(const std::string& name) const; + + /// @brief Returns the number of registered types. + /// @return Number of registered types. + std::size_t size() const; + + private: + memory::UnorderedBimap mTypes{}; + }; +} // namespace cubos::core::reflection diff --git a/core/src/cubos/core/reflection/type.cpp b/core/src/cubos/core/reflection/type.cpp index 7bc417719..c2768da04 100644 --- a/core/src/cubos/core/reflection/type.cpp +++ b/core/src/cubos/core/reflection/type.cpp @@ -65,7 +65,7 @@ bool Type::operator==(const Type& other) const return true; } - CUBOS_ASSERT(this->mName != other.mName, "Two types cannot be created with the same"); + CUBOS_ASSERT(this->mName != other.mName, "Two types should never have the same name"); return false; } diff --git a/core/src/cubos/core/reflection/type_registry.cpp b/core/src/cubos/core/reflection/type_registry.cpp new file mode 100644 index 000000000..8104413ac --- /dev/null +++ b/core/src/cubos/core/reflection/type_registry.cpp @@ -0,0 +1,37 @@ +#include +#include +#include + +using cubos::core::reflection::Type; +using cubos::core::reflection::TypeRegistry; + +void TypeRegistry::insert(const Type& type) +{ + if (mTypes.containsRight(type.name())) + { + CUBOS_ASSERT(mTypes.atRight(type.name()) == &type, "Two types should never have the same name"); + return; + } + + mTypes.insert(&type, type.name()); +} + +bool TypeRegistry::contains(const Type& type) const +{ + return mTypes.containsLeft(&type); +} + +bool TypeRegistry::contains(const std::string& name) const +{ + return mTypes.containsRight(name); +} + +const Type& TypeRegistry::at(const std::string& name) const +{ + return *mTypes.atRight(name); +} + +std::size_t TypeRegistry::size() const +{ + return mTypes.size(); +} diff --git a/core/tests/CMakeLists.txt b/core/tests/CMakeLists.txt index f0f2b82ad..8a502dc0b 100644 --- a/core/tests/CMakeLists.txt +++ b/core/tests/CMakeLists.txt @@ -10,6 +10,7 @@ add_executable( reflection/reflect.cpp reflection/type.cpp + reflection/type_registry.cpp reflection/traits/constructible.cpp reflection/traits/fields.cpp reflection/traits/nullable.cpp diff --git a/core/tests/reflection/type.cpp b/core/tests/reflection/type.cpp index 8f0a5634c..ae006bc92 100644 --- a/core/tests/reflection/type.cpp +++ b/core/tests/reflection/type.cpp @@ -44,6 +44,7 @@ TEST_CASE("reflection::Type") { auto& anotherType = Type::create("Bar"); REQUIRE(anotherType != type); + Type::destroy(anotherType); } Type::destroy(type); diff --git a/core/tests/reflection/type_registry.cpp b/core/tests/reflection/type_registry.cpp new file mode 100644 index 000000000..9751a6a94 --- /dev/null +++ b/core/tests/reflection/type_registry.cpp @@ -0,0 +1,42 @@ +#include + +#include +#include +#include + +using cubos::core::reflection::TypeRegistry; + +TEST_CASE("reflection::Type") +{ + TypeRegistry registry{}; + + CHECK_FALSE(registry.contains("int")); + CHECK_FALSE(registry.contains()); + CHECK(registry.size() == 0); + + SUBCASE("single insert") + { + registry.insert(); + CHECK(registry.size() == 1); + } + + SUBCASE("double insert") + { + registry.insert(); + registry.insert(); + CHECK(registry.size() == 1); + } + + SUBCASE("with other types") + { + registry.insert(); + registry.insert(); + registry.insert(); + registry.insert(); + registry.insert(); + CHECK(registry.size() == 5); + } + + REQUIRE(registry.contains("int")); + CHECK(registry.at("int").is()); +}