1+ /* *
2+ * @file
3+ * @author Pavel Siska <[email protected] > 4+ *
5+ * @brief This file contains the definition of the `PluginFactory` class. The class is responsible
6+ * for registering plugins and creating instances of those plugins via generator functions. It
7+ * provides support for various types of object creation, including unique pointers, shared
8+ * pointers and in-place construction.
9+ *
10+ * @copyright Copyright (c) 2025 CESNET, z.s.p.o.
11+ */
12+
13+ #pragma once
14+
15+ #include " pluginGenerator.hpp"
16+ #include " pluginManifest.hpp"
17+
18+ #include < map>
19+ #include < memory>
20+ #include < stdexcept>
21+ #include < string_view>
22+ #include < type_traits>
23+
24+ namespace ipxp {
25+
26+ /* *
27+ * @brief Templated class `PluginFactory` is responsible for managing and creating plugin instances.
28+ *
29+ * The `PluginFactory` class provides a singleton-based interface for registering plugins
30+ * and generating their instances. It supports creating unique and shared pointers, as well as
31+ * objects constructed at pre-allocated memory. Each plugin is identified by a `PluginManifest`.
32+ *
33+ * @tparam Base The base class type that all plugins must inherit from.
34+ * @tparam Args The types of arguments that will be passed to the plugin constructors.
35+ */
36+ template <typename Base, typename ... Args>
37+ class PluginFactory {
38+ public:
39+ /* *
40+ * @brief Retrieves the singleton instance of `PluginFactory`.
41+ *
42+ * @return A reference to the singleton `PluginFactory` instance.
43+ */
44+ static PluginFactory& getInstance ()
45+ {
46+ static PluginFactory instance;
47+ return instance;
48+ }
49+
50+ /* *
51+ * @brief Registers a plugin with the factory.
52+ *
53+ * This function registers a plugin by associating its manifest with its generator functions.
54+ * The function enforces that the `Derived` type must inherit from the `Base` class.
55+ *
56+ * @tparam Derived The plugin type (class) that inherits from the `Base` class.
57+ * @param manifest The manifest containing metadata about the plugin.
58+ *
59+ * @throw std::logic_error If `Derived` is not derived from `Base`.
60+ */
61+ template <typename Derived>
62+ void registerPlugin (const PluginManifest& manifest)
63+ {
64+ static_assert (std::is_base_of<Base, Derived>::value, " Derived must be a subclass of Base" );
65+
66+ m_registeredPlugins[manifest] = createGenerators<Base, Derived, Args...>();
67+ }
68+
69+ /* *
70+ * @brief Retrieves a list of all registered plugins.
71+ *
72+ * @return A vector of `PluginManifest` objects representing the registered plugins.
73+ */
74+ [[nodiscard]] std::vector<PluginManifest> getRegisteredPlugins ()
75+ {
76+ std::vector<PluginManifest> registeredPlugins;
77+ registeredPlugins.reserve (m_registeredPlugins.size ());
78+
79+ for (const auto & [pluginManifest, _] : m_registeredPlugins) {
80+ registeredPlugins.push_back (pluginManifest);
81+ }
82+ return registeredPlugins;
83+ }
84+
85+ /* *
86+ * @brief Creates a unique pointer to a plugin instance.
87+ *
88+ * @param key The key identifying the plugin (from the manifest).
89+ * @param args The arguments passed to the plugin constructor.
90+ * @return A unique pointer to the plugin instance.
91+ * @throws std::runtime_error If the plugin identified by the key is not registered.
92+ * @throws Any exception from the plugin constructor.
93+ */
94+ [[nodiscard]] std::unique_ptr<Base> createUnique (std::string_view key, Args... args) const
95+ {
96+ const auto & generators = getGenerators (key);
97+ return generators.uniqueGenerator (std::forward<Args>(args)...);
98+ }
99+
100+ /* *
101+ * @brief Creates a shared pointer to a plugin instance.
102+ *
103+ * @param key The key identifying the plugin (from the manifest).
104+ * @param args The arguments passed to the plugin constructor.
105+ * @return A shared pointer to the plugin instance.
106+ * @throws std::runtime_error If the plugin identified by the key is not registered.
107+ * @throws Any exception from the plugin constructor.
108+ */
109+ [[nodiscard]] std::shared_ptr<Base> createShared (std::string_view key, Args... args) const
110+ {
111+ const auto & generators = getGenerators (key);
112+ return generators.sharedGenerator (std::forward<Args>(args)...);
113+ }
114+
115+ /* *
116+ * @brief Constructs a plugin instance at a pre-allocated memory location.
117+ *
118+ * @param key The key identifying the plugin (from the manifest).
119+ * @param ptr The pre-allocated memory where the instance will be constructed.
120+ * @param args The arguments passed to the plugin constructor.
121+ * @return A pointer to the constructed plugin instance.
122+ * @throws std::runtime_error If the plugin identified by the key is not registered.
123+ * @throws Any exception from the plugin constructor.
124+ */
125+ [[nodiscard]] Base* constructAt (std::string_view key, void * ptr, Args... args) const
126+ {
127+ const auto & generators = getGenerators (key);
128+ return generators.constructAtGenerator (ptr, std::forward<Args>(args)...);
129+ }
130+
131+ private:
132+ PluginFactory () = default ;
133+
134+ using Generators = BaseGenerators<Base, Args...>;
135+
136+ Generators getGenerators (std::string_view key) const
137+ {
138+ const auto iter = m_registeredPlugins.find (key);
139+ if (iter == m_registeredPlugins.end ()) {
140+ throw std::runtime_error (
141+ " PluginFactory::getGenerators() has failed. Plugin: '" + std::string (key)
142+ + " ' is not registered." );
143+ }
144+
145+ return iter->second ;
146+ }
147+
148+ std::map<PluginManifest, Generators> m_registeredPlugins;
149+ };
150+
151+ } // namespace ipxp
0 commit comments