gfactory
Loading...
Searching...
No Matches
gfactory.h
Go to the documentation of this file.
1#pragma once
15// C++
16#include <filesystem>
17#include <memory>
18#include <sstream>
19#include <string>
20#include <string_view>
21#include <unordered_map>
22
23// gfactory
24#include "gdl.h"
25#include <gemc/gbase/gbase.h>
26#include "gfactory_options.h"
27
40{
41public:
43 virtual ~GFactoryBase() = default;
44
52 [[nodiscard]] virtual void* Create() = 0;
53};
54
66template <class T>
67class GFactory final : public GFactoryBase
68{
69public:
77 explicit GFactory(const std::shared_ptr<GOptions>& gopts)
78 : gopts_(gopts) {
79 static_assert(std::is_constructible_v<T, const std::shared_ptr<GOptions>&>,
80 "T must be constructible from const std::shared_ptr<GOptions>&");
81 }
82
87 [[nodiscard]] void* Create() override { return static_cast<void*>(new T(gopts_)); }
88
89private:
91 std::shared_ptr<GOptions> gopts_;
92};
93
123class GManager : public GBase<GManager>
124{
125public:
133 explicit GManager(const std::shared_ptr<GOptions>& gopt) : GBase(gopt, PLUGIN_LOGGER), gopts_(gopt) {
134 }
135
137 GManager(const GManager&) = delete;
138 GManager& operator=(const GManager&) = delete;
139
141 GManager(GManager&&) noexcept = default;
142 GManager& operator=(GManager&&) noexcept = default;
143
149 ~GManager() override { clearDLMap(); }
150
160 template <class Derived>
161 void RegisterObjectFactory(std::string_view name);
162
170 template <class Derived>
171 void RegisterObjectFactory(std::string_view name, const std::shared_ptr<GOptions>& gopts);
172
183 template <class Base>
184 [[nodiscard]] Base* CreateObject(std::string_view name) const;
185
198 template <class T>
199 [[nodiscard]] std::shared_ptr<T> LoadAndRegisterObjectFromLibrary(std::string_view name,
200 const std::shared_ptr<GOptions>& gopts);
201
207 void clearDLMap() noexcept;
208
209private:
215 void registerDL(std::string_view name);
216
218 std::unordered_map<std::string, std::unique_ptr<GFactoryBase>> factoryMap_;
219
221 std::unordered_map<std::string, std::shared_ptr<DynamicLib>> dlMap_;
222
224 std::shared_ptr<GOptions> gopts_;
225
227 std::string gname;
228};
229
230
231inline void GManager::clearDLMap() noexcept {
232 // Clearing the map releases std::shared_ptr<DynamicLib> instances.
233 // Each DynamicLib destructor closes its dlopen handle.
234 dlMap_.clear();
235}
236
237inline void GManager::registerDL(std::string_view name) {
238 const std::string basename = std::string{name} + ".gplugin";
239
240 // Build the colon-separated search path: -plugin_path option takes
241 // precedence, then GEMC_PLUGIN_PATH env var, then CWD / system library path.
242 std::string filename = basename;
243 if (gopts_) {
244 std::string searchPath = gopts_->getScalarString("plugin_path");
245 if (searchPath.empty()) {
246 if (const char* env = std::getenv("GEMC_PLUGIN_PATH")) { searchPath = env; }
247 }
248 if (!searchPath.empty()) {
249 std::istringstream ss(searchPath);
250 std::string dir;
251 while (std::getline(ss, dir, ':')) {
252 const std::string candidate = dir + "/" + basename;
253 if (std::filesystem::exists(candidate)) {
254 filename = candidate;
255 break;
256 }
257 }
258 }
259 }
260
261 dlMap_.emplace(std::string{name},
262 std::make_shared<DynamicLib>(log, filename));
263 log->debug(NORMAL, "Loading DL ", name, " (resolved: ", filename, ")");
264}
265
266template <class Derived>
267void GManager::RegisterObjectFactory(std::string_view name) {
268 // Note: the factory is stored type-erased (GFactoryBase) but remains responsible for creating Derived.
269 factoryMap_.emplace(std::string{name}, std::make_unique<GFactory<Derived>>());
270 log->debug(NORMAL, "Registering ", name, " into factory map");
271}
272
273template <class Derived>
274void GManager::RegisterObjectFactory(std::string_view name, const std::shared_ptr<GOptions>& gopts) {
275 factoryMap_.emplace(std::string{name}, std::make_unique<GFactory<Derived>>(gopts));
276 log->debug(NORMAL, "Registering ", name, " into factory map");
277}
278
279template <class Base>
280Base* GManager::CreateObject(std::string_view name) const {
281 auto it = factoryMap_.find(std::string{name});
282 if (it == factoryMap_.end()) {
284 "Couldn't find factory <", name, "> in factory map.");
285 }
286 log->debug(NORMAL, "Creating instance of <", name, "> factory.");
287
288 // Type-erased creation returns void*; caller requests a Base* view.
289 return static_cast<Base*>(it->second->Create());
290}
291
292template <class T>
293std::shared_ptr<T> GManager::LoadAndRegisterObjectFromLibrary(std::string_view name,
294 const std::shared_ptr<GOptions>& gopts) {
295 registerDL(name);
296 auto pluginName = std::string{name};
297 auto pluginLib = dlMap_.at(pluginName); // shared_ptr<DynamicLib>
298
299 if (pluginLib && pluginLib->handle) {
300 // The product type performs the symbol lookup and raw allocation.
301 T* raw = T::instantiate(pluginLib->handle, gopts);
302 if (raw == nullptr) {
303 log->error(ERR_FACTORYNOTFOUND, "Plugin ", name, " could not instantiate its factory object.");
304 }
305
306 // Standardize logger wiring on the instance.
307 raw->set_loggers(gopts);
308
309 // Return shared_ptr<T> with a deleter that captures pluginLib so the library stays loaded
310 // until the object is destroyed.
311 return std::shared_ptr<T>(raw, [pluginLib](T* ptr) {
312 delete ptr;
313 // pluginLib keeps the dlopen handle alive until ptr is destroyed.
314 });
315 }
316
317 const char* envPath = std::getenv("GEMC_PLUGIN_PATH");
319 "Plugin ", name, ".gplugin could not be loaded.\n",
320 " GEMC_PLUGIN_PATH = ", (envPath ? envPath : "(not set)"), "\n",
321 " Hint: set GEMC_PLUGIN_PATH or use -plugin_path=<dir> to point to the directory ",
322 "containing *.gplugin files.");
323}
std::shared_ptr< GLogger > log
Type-erased factory interface used by GManager.
Definition gfactory.h:40
virtual void * Create()=0
Instantiate the concrete product.
virtual ~GFactoryBase()=default
Virtual destructor for safe deletion through base pointer.
Concrete factory that creates objects of type T.
Definition gfactory.h:68
GFactory(const std::shared_ptr< GOptions > &gopts)
Construct a factory bound to a specific configuration/options instance.
Definition gfactory.h:77
void * Create() override
Allocate a new instance of T.
Definition gfactory.h:87
void debug(debug_type type, Args &&... args) const
void error(int exit_code, Args &&... args) const
Factory registry and dynamic-library manager for run-time creation of plugin objects.
Definition gfactory.h:124
GManager(const std::shared_ptr< GOptions > &gopt)
Construct a manager instance.
Definition gfactory.h:133
GManager(GManager &&) noexcept=default
Allow move for container support.
std::shared_ptr< T > LoadAndRegisterObjectFromLibrary(std::string_view name, const std::shared_ptr< GOptions > &gopts)
Load a plugin library and instantiate an object from it.
Definition gfactory.h:293
GManager(const GManager &)=delete
No copy – the manager owns unique resources (factory objects and loaded libraries).
Base * CreateObject(std::string_view name) const
Create an instance of a previously registered factory.
Definition gfactory.h:280
GManager & operator=(const GManager &)=delete
void clearDLMap() noexcept
Release all loaded dynamic libraries.
Definition gfactory.h:231
void RegisterObjectFactory(std::string_view name)
Register a concrete factory under a string key.
Definition gfactory.h:267
std::string getScalarString(const std::string &tag) const
#define ERR_FACTORYNOTFOUND
Definition gdl.h:29
#define ERR_DLHANDLENOTFOUND
Definition gdl.h:30
constexpr const char * PLUGIN_LOGGER
Logger channel used by the gfactory module and plugins loaded through it.
NORMAL
Helper that loads a shared library and holds its POSIX handle.
Definition gdl.h:54