From cc0688f048819febc571368fb9fc093ea066708c Mon Sep 17 00:00:00 2001 From: DH Date: Fri, 27 Feb 2026 20:30:37 -0500 Subject: [PATCH] Final version with full refactoring. --- typefactory/typefactory.h | 186 +++++++++++++++++++------------------- 1 file changed, 91 insertions(+), 95 deletions(-) diff --git a/typefactory/typefactory.h b/typefactory/typefactory.h index b7a0cd6..68e4dc1 100644 --- a/typefactory/typefactory.h +++ b/typefactory/typefactory.h @@ -1,120 +1,116 @@ #ifndef TYPEFACTORY_H #define TYPEFACTORY_H -#include -#include + #include +#include +#include +#include // std::move /** * @brief Registry-based factory for creating objects by runtime identifier. * - * Allows registering derived types and instantiating them - * using a ClassId key. + * Allows registering derived types and instantiating them using a ClassId key. * - * @param ClassId - unique class identification class. For example string, or integer id. - * @param BaseClass - all objects should have one base class. For example vehicle or parameter - * @param Args - constructor arguments + * Notes: + * - Not thread-safe. Register types during initialization phase only. + * - Re-registering the same id overwrites the previous entry ("last wins"). + * - ClassId must be hashable (std::hash specialization must exist). + * + * @tparam ClassId Unique class identifier type (e.g. std::string, int, enum). + * @tparam BaseClass Base type for all created objects. + * @tparam Args Constructor arguments forwarded to registered derived types (by value). * * Usage example: * @code - * class Base { - * public: - * virtual int get() = 0; - * } + * #include * - * class Derived1 : public Base { - * public: - * Derived1 (int start) : m_start(start){} - * int get() override { - * return m_start + 1; - * } - * private: - * int m_start = 0; - * } + * struct Base { + * virtual ~Base() = default; + * virtual int get() = 0; + * }; * - * class Derived2 : public Base { - * public: - * Derived2 (int start) : m_start(start){} - * int get() override { - * return m_start + 2; - * } - * private: - * int m_start = 0; - * } - * . - * . - * . - * TypeFactory typefactory; - * typefactory.registerType("one"); - * typefactory.registerType("2"); + * struct Derived1 : Base { + * explicit Derived1(int start) : m_start(start) {} + * int get() override { return m_start + 1; } + * int m_start = 0; + * }; * - * auto d1 = typefactory.creator ("one")(10); - * auto d2 = typefactory.creator ("2")(10); + * struct Derived2 : Base { + * explicit Derived2(int start) : m_start(start) {} + * int get() override { return m_start + 2; } + * int m_start = 0; + * }; * - * d1->get(); - * d2->get(); + * TypeFactory factory; + * factory.registerType("one"); + * factory.registerType("two"); + * + * auto a = factory.create("one", 10); + * auto b = factory.creator("two")(10); // advanced API: get creator function + * + * (void)a->get(); + * (void)b->get(); * @endcode */ -template +template class TypeFactory { - public: - typedef std::shared_ptr BaseClass_SP; - /** - * @brief typefactoryFunction - typefactory function pointer type. Generally speaking it is pointer to constructor. - */ - typedef BaseClass_SP (*typefactoryFunction) (Args ...); +public: + using BasePtr = std::shared_ptr; + using CreatorFn = BasePtr (*)(Args...); - TypeFactory() = default; + TypeFactory() = default; - /** - * @brief registerType - template function to register class in factory - * @param Derived - registering type - * @param id - unique class identification - * - * Usage example: - * @code - * typefactory.registerType("one"); - * typefactory.registerType("2"); - * @endcode - */ - template - void registerType (const ClassId& id) { - /// Register Derived type by storing its constructor wrapper - static_assert(std::is_base_of_v, - "Derived must inherit from BaseClass"); - static_assert(std::is_constructible_v, - "Derived must be constructible from Args..."); - classes[id] = &typefactory; - } + /** + * @brief Registers a Derived type under the given id. + * + * Requirements (checked at compile-time): + * - Derived must inherit from BaseClass + * - Derived must be constructible from Args... + * + * Re-registering the same id overwrites the previous entry ("last wins"). + */ + template + void registerType(const ClassId& id) { + static_assert(std::is_base_of_v, + "Derived must inherit from BaseClass"); + static_assert(std::is_constructible_v, + "Derived must be constructible from Args..."); - /** - * @brief creator - Returns creator function for id. - * @param id - unique class identification - * @returns creator function. - * @throws std::out_of_range when id not found in map - */ - typefactoryFunction creator (const ClassId& id) const { - return classes.at (id); - } - BaseClass_SP create(const ClassId& id, Args... args) const { - return creator(id)(args...); - } - protected: - /** - * @brief classes - Not thread-safe. Register types during initialization phase only. - */ - std::unordered_map classes; + classes.insert_or_assign(id, &instantiate); + } - private: - /** - * @brief typefactory - main functionality, creator registered object - * @param Derived - class type - * @param args - constructor arguments - * @return shared pointer to register Derived class - */ - template - static BaseClass_SP typefactory (Args ... args) { - return std::make_shared (args ...); - } + /** + * @brief Returns creator function for the given id. + * @throws std::out_of_range when id is not registered. + */ + [[nodiscard]] CreatorFn creator(const ClassId& id) const { + return classes.at(id); + } + + /** + * @brief Creates an instance for the given id using provided arguments. + * @throws std::out_of_range when id is not registered. + */ + [[nodiscard]] BasePtr create(const ClassId& id, Args... args) const { + return creator(id)(std::move(args)...); + } + + /** + * @brief Checks whether an id is registered. + */ + [[nodiscard]] bool contains(const ClassId& id) const { + return classes.find(id) != classes.end(); + } + +protected: + // Protected by design: derived factories may extend/inspect the registry. + std::unordered_map classes; + +private: + template + static BasePtr instantiate(Args... args) { + return std::make_shared(std::move(args)...); + } }; #endif // TYPEFACTORY_H