From aef49e7f11a78b2c340cd849bf8a765f0741a46d Mon Sep 17 00:00:00 2001 From: Romain BOULLARD Date: Tue, 8 Sep 2026 22:31:28 +0200 Subject: [PATCH] Add factory --- Bigfoot/Libs/Utils/Include/Utils/Factory.hpp | 75 ++++++++++++++++ Bigfoot/Tests/Utils/Factory.cpp | 95 ++++++++++++++++++++ 2 files changed, 170 insertions(+) create mode 100644 Bigfoot/Libs/Utils/Include/Utils/Factory.hpp create mode 100644 Bigfoot/Tests/Utils/Factory.cpp diff --git a/Bigfoot/Libs/Utils/Include/Utils/Factory.hpp b/Bigfoot/Libs/Utils/Include/Utils/Factory.hpp new file mode 100644 index 0000000..75cfd88 --- /dev/null +++ b/Bigfoot/Libs/Utils/Include/Utils/Factory.hpp @@ -0,0 +1,75 @@ +/********************************************************************* + * \file Factory.hpp + * + * \author Romain BOULLARD + * \date September 2026 + *********************************************************************/ +#ifndef BIGFOOT_UTILS_FACTORY_HPP +#define BIGFOOT_UTILS_FACTORY_HPP +#include +#include +#include + +namespace Bigfoot +{ +template +class Factory +{ + public: + /** + * Register a key inside the factory + * + * \param p_key The key + * \param p_function The create function + * \return True if the key has been registered, false if it was already registered + */ + [[nodiscard]] + bool Register(const KEY p_key, CREATEFUNCTION&& p_function) + { + if (m_createFunctions.find(p_key) == m_createFunctions.end()) + { + m_createFunctions.emplace(p_key, eastl::move(p_function)); + return true; + } + + return false; + } + + /** + * Create an instance from the factory + * + * \param p_key The key to create. Needs to have been registered with Register() + * \param p_args Arguments for the creation + * \return The created instance. nullptr is returned if the key has not been registered + */ + template + [[nodiscard]] + eastl::unique_ptr Create(const KEY p_key, ARGS&&... p_args) const + { + if (const auto createFunction = m_createFunctions.find(p_key); createFunction != m_createFunctions.end()) + { + return createFunction->second(eastl::forward(p_args)...); + } + + return nullptr; + } + + /** + * Remove a key and its associated create function from the factory + * + * \param p_key The key to remove + */ + void Remove(const KEY p_key) + { + m_createFunctions.erase(p_key); + } + + private: + /** + * The mapping between keys and create functions + */ + ankerl::unordered_dense::map m_createFunctions; +}; +} // namespace Bigfoot + +#endif diff --git a/Bigfoot/Tests/Utils/Factory.cpp b/Bigfoot/Tests/Utils/Factory.cpp new file mode 100644 index 0000000..289fc2b --- /dev/null +++ b/Bigfoot/Tests/Utils/Factory.cpp @@ -0,0 +1,95 @@ +/********************************************************************* + * \file Factory.cpp + * + * \author Romain BOULLARD + * \date September 2026 + *********************************************************************/ +#include + +#include +#include +#include + +namespace Bigfoot +{ +class Widget +{ + public: + virtual ~Widget() = default; + + [[nodiscard]] + virtual std::uint32_t GetValue() const = 0; +}; + +class WidgetA final: public Widget +{ + public: + explicit WidgetA(const std::uint32_t p_value): + m_value(p_value) + { + } + + [[nodiscard]] + std::uint32_t GetValue() const override + { + return m_value; + } + + private: + std::uint32_t m_value; +}; + +enum class WidgetKeys +{ + WidgetA +}; + +using WidgetFactory = Factory(std::uint32_t)>>; + +/****************************************************************************************/ + +class FactoryFixture: public ::testing::Test +{ + protected: + static eastl::unique_ptr CreateWidgetA(const std::uint32_t p_value) + { + return eastl::make_unique(p_value); + } + + WidgetFactory m_factory; +}; + +/****************************************************************************************/ + +TEST_F(FactoryFixture, Register_ShouldReturnTrueOnSuccess) +{ + EXPECT_TRUE(m_factory.Register(WidgetKeys::WidgetA, &CreateWidgetA)); +} + +/****************************************************************************************/ + +TEST_F(FactoryFixture, Register_ShouldReturnFalseOnKeyDuplication) +{ + std::ignore = m_factory.Register(WidgetKeys::WidgetA, &CreateWidgetA); + + EXPECT_FALSE(m_factory.Register(WidgetKeys::WidgetA, &CreateWidgetA)); +} + +/****************************************************************************************/ + +TEST_F(FactoryFixture, Create_ShouldReturnAValidInstanceIfKeyIsRegistered) +{ + std::ignore = m_factory.Register(WidgetKeys::WidgetA, &CreateWidgetA); + + const eastl::unique_ptr widget = m_factory.Create(WidgetKeys::WidgetA, 42); + + EXPECT_EQ(widget->GetValue(), 42); +} + +/****************************************************************************************/ + +TEST_F(FactoryFixture, Create_ShouldReturnNullptrIfKeyIsNotRegistered) +{ + EXPECT_EQ(m_factory.Create(WidgetKeys::WidgetA, 42), nullptr); +} +} // namespace Bigfoot