Compare commits

..

2 Commits

Author SHA1 Message Date
DH
cc0688f048 Final version with full refactoring. 2026-02-27 20:30:37 -05:00
DH
6d7cfc486e Smal refactoring. 2026-02-27 20:27:30 -05:00

View File

@@ -1,119 +1,116 @@
#ifndef TYPEFACTORY_H #ifndef TYPEFACTORY_H
#define TYPEFACTORY_H #define TYPEFACTORY_H
#include <unordered_map>
#include <type_traits>
#include <memory> #include <memory>
#include <type_traits>
#include <unordered_map>
#include <utility> // std::move
/** /**
* @brief Registry-based factory for creating objects by runtime identifier. * @brief Registry-based factory for creating objects by runtime identifier.
* *
* Allows registering derived types and instantiating them * Allows registering derived types and instantiating them using a ClassId key.
* using a ClassId key.
* *
* @param ClassId - unique class identification class. For example string, or integer id. * Notes:
* @param BaseClass - all objects should have one base class. For example vehicle or parameter * - Not thread-safe. Register types during initialization phase only.
* @param Args - constructor arguments * - Re-registering the same id overwrites the previous entry ("last wins").
* - ClassId must be hashable (std::hash<ClassId> 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: * Usage example:
* @code * @code
* class Base { * #include <string>
* public:
* virtual int get() = 0;
* }
* *
* class Derived1 : public Base { * struct Base {
* public: * virtual ~Base() = default;
* Derived1 (int start) : m_start(start){} * virtual int get() = 0;
* int get() override { * };
* return m_start + 1;
* }
* private:
* int m_start = 0;
* }
* *
* class Derived2 : public Base { * struct Derived1 : Base {
* public: * explicit Derived1(int start) : m_start(start) {}
* Derived2 (int start) : m_start(start){} * int get() override { return m_start + 1; }
* int get() override { * int m_start = 0;
* return m_start + 2; * };
* }
* private:
* int m_start = 0;
* }
* .
* .
* .
* TypeFactory <std::string, Base, int> typefactory;
* typefactory.registerType<Derived1>("one");
* typefactory.registerType<Derived2>("2");
* *
* auto d1 = typefactory.create ("one")(10); * struct Derived2 : Base {
* auto d2 = typefactory.create ("2")(10); * explicit Derived2(int start) : m_start(start) {}
* int get() override { return m_start + 2; }
* int m_start = 0;
* };
* *
* d1->get(); * TypeFactory<std::string, Base, int> factory;
* d2->get(); * factory.registerType<Derived1>("one");
* factory.registerType<Derived2>("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 * @endcode
*/ */
template<class ClassId, class BaseClass, class ... Args> template <class ClassId, class BaseClass, class... Args>
class TypeFactory { class TypeFactory {
public: public:
typedef std::shared_ptr<BaseClass> BaseClass_SP; using BasePtr = std::shared_ptr<BaseClass>;
/** using CreatorFn = BasePtr (*)(Args...);
* @brief typefactoryFunction - typefactory function pointer type. Generally speaking it is pointer to constructor.
*/
typedef BaseClass_SP (*typefactoryFunction) (Args ...);
TypeFactory() = default; TypeFactory() = default;
/** /**
* @brief registerType - template function to register class in factory * @brief Registers a Derived type under the given id.
* @param Derived - registering type *
* @param id - unique class identification * Requirements (checked at compile-time):
* * - Derived must inherit from BaseClass
* Usage example: * - Derived must be constructible from Args...
* @code *
* typefactory.registerType<Derived1>("one"); * Re-registering the same id overwrites the previous entry ("last wins").
* typefactory.registerType<Derived2>("2"); */
* @endcode template <class Derived>
*/ void registerType(const ClassId& id) {
template<class Derived> static_assert(std::is_base_of_v<BaseClass, Derived>,
void registerType (const ClassId& id) { "Derived must inherit from BaseClass");
/// Register Derived type by storing its constructor wrapper static_assert(std::is_constructible_v<Derived, Args...>,
"Derived must be constructible from Args...");
classes.insert_or_assign(id, &instantiate<Derived>);
}
static_assert(std::is_base_of_v<BaseClass, Derived>, /**
"Derived must inherit from BaseClass"); * @brief Returns creator function for the given id.
static_assert(std::is_constructible_v<Derived, Args...>, * @throws std::out_of_range when id is not registered.
"Derived must be constructible from Args..."); */
classes[id] = &typefactory<Derived>; [[nodiscard]] CreatorFn creator(const ClassId& id) const {
} return classes.at(id);
}
/** /**
* @brief create - Returns creator function for id. * @brief Creates an instance for the given id using provided arguments.
* @param id - unique class identification * @throws std::out_of_range when id is not registered.
* @return shared pointer to new class. */
* @throws std::out_of_range when id not found in map [[nodiscard]] BasePtr create(const ClassId& id, Args... args) const {
*/ return creator(id)(std::move(args)...);
typefactoryFunction create (const ClassId& id) const { }
return classes.at (id);
}
protected:
/**
* @brief classes - Not thread-safe. Register types during initialization phase only.
*/
std::unordered_map<ClassId, typefactoryFunction> classes;
private: /**
/** * @brief Checks whether an id is registered.
* @brief typefactory - main functionality, create registered object */
* @param Derived - class type [[nodiscard]] bool contains(const ClassId& id) const {
* @param args - constructor arguments return classes.find(id) != classes.end();
* @return shared pointer to register Derived class }
*/
template<class Derived> protected:
static BaseClass_SP typefactory (Args ... args) { // Protected by design: derived factories may extend/inspect the registry.
return std::make_shared<Derived> (args ...); std::unordered_map<ClassId, CreatorFn> classes;
}
private:
template <class Derived>
static BasePtr instantiate(Args... args) {
return std::make_shared<Derived>(std::move(args)...);
}
}; };
#endif // TYPEFACTORY_H #endif // TYPEFACTORY_H