gfactory
Loading...
Searching...
No Matches
gfactory.h
Go to the documentation of this file.
1#pragma once
14
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_->getOptionalScalarString("plugin_path").value_or("");
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 %1 (resolved: %2)", name, 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 %1 into factory map", name);
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 %1 into factory map", name);
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()) {
283 log->error(gfactory::ERR_FACTORYNOTFOUND, "Couldn't find factory <%1> in factory map.", name);
284 }
285 log->debug(NORMAL, "Creating instance of <%1> factory.", name);
286
287 // Type-erased creation returns void*; caller requests a Base* view.
288 return static_cast<Base*>(it->second->Create());
289}
290
291template <class T>
292std::shared_ptr<T> GManager::LoadAndRegisterObjectFromLibrary(std::string_view name,
293 const std::shared_ptr<GOptions>& gopts) {
294 registerDL(name);
295 auto pluginName = std::string{name};
296 auto pluginLib = dlMap_.at(pluginName); // shared_ptr<DynamicLib>
297
298 if (pluginLib && pluginLib->handle) {
299 // The product type performs the symbol lookup and raw allocation.
300 T* raw = T::instantiate(pluginLib->handle, gopts);
301 if (raw == nullptr) {
302 log->error(
303 gfactory::ERR_FACTORYNOTFOUND, "Plugin %1 could not instantiate its factory object.", name);
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");
318 log->error(
320 "Plugin %1.gplugin could not be loaded.\n GEMC_PLUGIN_PATH = %2\n Hint: set GEMC_PLUGIN_PATH or "
321 "use -plugin_path=<dir> to point to the directory containing *.gplugin files.", name,
322 (envPath ? envPath : "(not set)"));
323}
GBase(const std::shared_ptr< GOptions > &gopt, std::string logger_name="")
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.
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
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:292
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
constexpr const char * PLUGIN_LOGGER
Logger channel used by the gfactory module and plugins loaded through it.
NORMAL
constexpr int ERR_FACTORYNOTFOUND
Definition gdl.h:30
constexpr int ERR_DLHANDLENOTFOUND
Definition gdl.h:31
Helper that loads a shared library and holds its POSIX handle.
Definition gdl.h:56