Skip to content

Commit

Permalink
feat(reflection): add TypeRegistry
Browse files Browse the repository at this point in the history
  • Loading branch information
RiscadoA committed Nov 26, 2023
1 parent 0cf97c4 commit 1e7929e
Show file tree
Hide file tree
Showing 7 changed files with 151 additions and 1 deletion.
1 change: 1 addition & 0 deletions core/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
68 changes: 68 additions & 0 deletions core/include/cubos/core/reflection/type_registry.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/// @file
/// @brief Class @ref cubos::core::reflection::TypeRegistry.
/// @ingroup core-reflection

#pragma once

#include <string>

#include <cubos/core/memory/unordered_bimap.hpp>
#include <cubos/core/reflection/reflect.hpp>

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 <Reflectable T>
void insert()
{
this->insert(reflect<T>());
}

/// @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 <Reflectable T>
bool contains() const
{
return this->contains(reflect<T>());
}

/// @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<const Type*, std::string> mTypes{};
};
} // namespace cubos::core::reflection
2 changes: 1 addition & 1 deletion core/src/cubos/core/reflection/type.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down
37 changes: 37 additions & 0 deletions core/src/cubos/core/reflection/type_registry.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#include <cubos/core/log.hpp>
#include <cubos/core/reflection/type.hpp>
#include <cubos/core/reflection/type_registry.hpp>

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();
}
1 change: 1 addition & 0 deletions core/tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions core/tests/reflection/type.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ TEST_CASE("reflection::Type")
{
auto& anotherType = Type::create("Bar");
REQUIRE(anotherType != type);
Type::destroy(anotherType);
}

Type::destroy(type);
Expand Down
42 changes: 42 additions & 0 deletions core/tests/reflection/type_registry.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
#include <doctest/doctest.h>

#include <cubos/core/reflection/external/primitives.hpp>
#include <cubos/core/reflection/type.hpp>
#include <cubos/core/reflection/type_registry.hpp>

using cubos::core::reflection::TypeRegistry;

TEST_CASE("reflection::Type")
{
TypeRegistry registry{};

CHECK_FALSE(registry.contains("int"));
CHECK_FALSE(registry.contains<int>());
CHECK(registry.size() == 0);

SUBCASE("single insert")
{
registry.insert<int>();
CHECK(registry.size() == 1);
}

SUBCASE("double insert")
{
registry.insert<int>();
registry.insert<int>();
CHECK(registry.size() == 1);
}

SUBCASE("with other types")
{
registry.insert<short>();
registry.insert<int>();
registry.insert<long>();
registry.insert<float>();
registry.insert<double>();
CHECK(registry.size() == 5);
}

REQUIRE(registry.contains("int"));
CHECK(registry.at("int").is<int>());
}

0 comments on commit 1e7929e

Please sign in to comment.