Helios Engine 0.1.0
A modular ECS based data-oriented C++23 game engine
 
Loading...
Searching...
No Matches
helios::app::DynamicModule Class Reference

#include <dynamic_module.hpp>

Public Types

using FileTime = std::filesystem::file_time_type
 

Public Member Functions

 DynamicModule ()=default
 
 DynamicModule (const std::filesystem::path &path, DynamicModuleConfig config={})
 Constructs and loads a module from the specified path.
 
 DynamicModule (const DynamicModule &)=delete
 
 DynamicModule (DynamicModule &&other) noexcept
 
 ~DynamicModule () noexcept=default
 Destructor that destroys the module if loaded.
 
DynamicModuleoperator= (const DynamicModule &)=delete
 
DynamicModuleoperator= (DynamicModule &&other) noexcept
 
auto Load (const std::filesystem::path &path, DynamicModuleConfig config={}) -> std::expected< void, DynamicModuleError >
 Loads a module from the specified path.
 
auto Unload () -> std::expected< void, DynamicModuleError >
 Unloads the current module.
 
auto Reload (App &app) -> std::expected< void, DynamicModuleError >
 Reloads the module from the same path.
 
auto ReloadIfChanged (App &app) -> std::expected< void, DynamicModuleError >
 Reloads the module only if the file has changed.
 
void UpdateFileTime () noexcept
 Updates the cached file modification time.
 
bool HasFileChanged () const noexcept
 Checks if the library file has been modified since last load.
 
bool Loaded () const noexcept
 Checks if a module is currently loaded.
 
ModuleGetModule () noexcept
 Gets reference to the loaded module.
 
const ModuleGetModule () const noexcept
 Gets const reference to the loaded module.
 
ModuleGetModulePtr () noexcept
 Gets pointer to the loaded module.
 
const ModuleGetModulePtr () const noexcept
 Gets const pointer to the loaded module.
 
std::unique_ptr< ModuleReleaseModule () noexcept
 Releases ownership of the module.
 
ModuleTypeId GetModuleId () const noexcept
 Gets the module type ID.
 
std::string_view GetModuleName () const noexcept
 Gets the module name.
 
const std::filesystem::path & Path () const noexcept
 Gets the path of the loaded library.
 
helios::utils::DynamicLibraryLibrary () noexcept
 Gets reference to the underlying dynamic library.
 
const helios::utils::DynamicLibraryLibrary () const noexcept
 Gets const reference to the underlying dynamic library.
 
const DynamicModuleConfigConfig () const noexcept
 Gets the configuration used for this module.
 

Detailed Description

Definition at line 154 of file dynamic_module.hpp.

Member Typedef Documentation

◆ FileTime

using helios::app::DynamicModule::FileTime = std::filesystem::file_time_type

Definition at line 156 of file dynamic_module.hpp.

Constructor & Destructor Documentation

◆ DynamicModule() [1/4]

helios::app::DynamicModule::DynamicModule ( )
default

◆ DynamicModule() [2/4]

helios::app::DynamicModule::DynamicModule ( const std::filesystem::path &  path,
DynamicModuleConfig  config = {} 
)
inlineexplicit

Constructs and loads a module from the specified path.

Parameters
pathPath to the dynamic library
configConfiguration options

Definition at line 314 of file dynamic_module.hpp.

314 {
315 auto result = Load(path, config);
316 if (!result) {
317 HELIOS_ERROR("Failed to load dynamic module '{}': {}", path.string(), DynamicModuleErrorToString(result.error()));
318 }
319}
auto Load(const std::filesystem::path &path, DynamicModuleConfig config={}) -> std::expected< void, DynamicModuleError >
Loads a module from the specified path.
#define HELIOS_ERROR(...)
Definition logger.hpp:689
constexpr std::string_view DynamicModuleErrorToString(DynamicModuleError error) noexcept
Gets a human-readable description for a DynamicModuleError.

◆ DynamicModule() [3/4]

helios::app::DynamicModule::DynamicModule ( const DynamicModule )
delete

◆ DynamicModule() [4/4]

helios::app::DynamicModule::DynamicModule ( DynamicModule &&  other)
inlinenoexcept

Definition at line 321 of file dynamic_module.hpp.

322 : library_(std::move(other.library_)),
323 module_(std::move(other.module_)),
324 module_id_(other.module_id_),
325 module_name_(std::move(other.module_name_)),
326 config_(other.config_),
327 last_write_time_(other.last_write_time_) {
328 other.module_id_ = 0;
329}

◆ ~DynamicModule()

helios::app::DynamicModule::~DynamicModule ( )
defaultnoexcept

Destructor that destroys the module if loaded.

Member Function Documentation

◆ Config()

const DynamicModuleConfig & helios::app::DynamicModule::Config ( ) const
inlinenoexcept

Gets the configuration used for this module.

Returns
Configuration struct

Definition at line 295 of file dynamic_module.hpp.

295{ return config_; }

◆ GetModule() [1/2]

const Module & helios::app::DynamicModule::GetModule ( ) const
inlinenoexcept

Gets const reference to the loaded module.

Warning
Triggers assertion if module is not loaded.
Returns
Const reference to the module

Definition at line 471 of file dynamic_module.hpp.

471 {
472 HELIOS_ASSERT(Loaded(), "Failed to get module: Module is not loaded!");
473 return *module_;
474}
#define HELIOS_ASSERT(condition,...)
Assertion macro that aborts execution in debug builds.
Definition assert.hpp:140
bool Loaded() const noexcept
Checks if a module is currently loaded.

◆ GetModule() [2/2]

Module & helios::app::DynamicModule::GetModule ( )
inlinenoexcept

Gets reference to the loaded module.

Warning
Triggers assertion if module is not loaded.
Returns
Reference to the module

Definition at line 466 of file dynamic_module.hpp.

466 {
467 HELIOS_ASSERT(Loaded(), "Failed to get module: Module is not loaded!");
468 return *module_;
469}

◆ GetModuleId()

ModuleTypeId helios::app::DynamicModule::GetModuleId ( ) const
inlinenoexcept

Gets the module type ID.

Returns
Module type ID, or 0 if not loaded

Definition at line 265 of file dynamic_module.hpp.

265{ return module_id_; }

◆ GetModuleName()

std::string_view helios::app::DynamicModule::GetModuleName ( ) const
inlinenoexcept

Gets the module name.

Returns
Module name, or empty string if not loaded

Definition at line 271 of file dynamic_module.hpp.

271{ return module_name_; }

◆ GetModulePtr() [1/2]

const Module * helios::app::DynamicModule::GetModulePtr ( ) const
inlinenoexcept

Gets const pointer to the loaded module.

Returns
Const pointer to module, or nullptr if not loaded

Definition at line 251 of file dynamic_module.hpp.

251{ return module_.get(); }

◆ GetModulePtr() [2/2]

Module * helios::app::DynamicModule::GetModulePtr ( )
inlinenoexcept

Gets pointer to the loaded module.

Returns
Pointer to module, or nullptr if not loaded

Definition at line 245 of file dynamic_module.hpp.

245{ return module_.get(); }

◆ HasFileChanged()

bool helios::app::DynamicModule::HasFileChanged ( ) const
inlinenoexcept

Checks if the library file has been modified since last load.

Returns
True if the file modification time has changed

Definition at line 452 of file dynamic_module.hpp.

452 {
453 if (!library_.Loaded()) {
454 return false;
455 }
456
457 std::error_code ec;
458 auto current_time = std::filesystem::last_write_time(library_.Path(), ec);
459 if (ec) {
460 return false;
461 }
462
463 return current_time != last_write_time_;
464}
bool Loaded() const noexcept
Checks if a library is currently loaded.
const std::filesystem::path & Path() const noexcept
Gets the path of the loaded library.

◆ Library() [1/2]

const helios::utils::DynamicLibrary & helios::app::DynamicModule::Library ( ) const
inlinenoexcept

Gets const reference to the underlying dynamic library.

Returns
Const reference to helios::utils::DynamicLibrary

Definition at line 289 of file dynamic_module.hpp.

289{ return library_; }

◆ Library() [2/2]

helios::utils::DynamicLibrary & helios::app::DynamicModule::Library ( )
inlinenoexcept

Gets reference to the underlying dynamic library.

Returns
Reference to helios::utils::DynamicLibrary

Definition at line 283 of file dynamic_module.hpp.

283{ return library_; }

◆ Load()

auto helios::app::DynamicModule::Load ( const std::filesystem::path &  path,
DynamicModuleConfig  config = {} 
) -> std::expected<void, DynamicModuleError>
inline

Loads a module from the specified path.

Parameters
pathPath to the dynamic library
configConfiguration options
Returns
Expected with void on success, or error on failure

Definition at line 346 of file dynamic_module.hpp.

347 {
348 config_ = config;
349
350 // Load the library
351 const auto load_result = library_.Load(path);
352 if (!load_result) {
353 return std::unexpected(DynamicModuleError::LibraryLoadFailed);
354 }
355
356 // Load module symbols and create instance
357 auto module_result = LoadModuleInstance();
358 if (!module_result) {
359 [[maybe_unused]] auto _ = library_.Unload();
360 return module_result;
361 }
362
363 // Cache the file modification time
365
366 HELIOS_INFO("Loaded dynamic module '{}' from: {}", module_name_, path.string());
367 return {};
368}
void UpdateFileTime() noexcept
Updates the cached file modification time.
auto Load(const std::filesystem::path &path) -> std::expected< void, DynamicLibraryError >
Loads a dynamic library from the specified path.
auto Unload() -> std::expected< void, DynamicLibraryError >
Unloads the currently loaded library.
#define HELIOS_INFO(...)
Definition logger.hpp:685
@ LibraryLoadFailed
Failed to load the dynamic library.

◆ Loaded()

bool helios::app::DynamicModule::Loaded ( ) const
inlinenoexcept

Checks if a module is currently loaded.

Returns
True if a module is loaded

Definition at line 225 of file dynamic_module.hpp.

225{ return module_ != nullptr && library_.Loaded(); }

◆ operator=() [1/2]

DynamicModule & helios::app::DynamicModule::operator= ( const DynamicModule )
delete

◆ operator=() [2/2]

DynamicModule & helios::app::DynamicModule::operator= ( DynamicModule &&  other)
inlinenoexcept

Definition at line 331 of file dynamic_module.hpp.

331 {
332 if (this != &other) {
333 module_.reset();
334 library_ = std::move(other.library_);
335 module_ = std::move(other.module_);
336 module_id_ = other.module_id_;
337 module_name_ = std::move(other.module_name_);
338 config_ = other.config_;
339 last_write_time_ = other.last_write_time_;
340
341 other.module_id_ = 0;
342 }
343 return *this;
344}

◆ Path()

const std::filesystem::path & helios::app::DynamicModule::Path ( ) const
inlinenoexcept

Gets the path of the loaded library.

Returns
Path to the library, or empty if not loaded

Definition at line 277 of file dynamic_module.hpp.

277{ return library_.Path(); }

◆ ReleaseModule()

std::unique_ptr< Module > helios::app::DynamicModule::ReleaseModule ( )
inlinenoexcept

Releases ownership of the module.

After this call, the DynamicModule no longer owns the module. The caller is responsible for the module's lifetime.

Returns
Unique pointer to the module

Definition at line 259 of file dynamic_module.hpp.

259{ return std::move(module_); }

◆ Reload()

auto helios::app::DynamicModule::Reload ( App app) -> std::expected<void, DynamicModuleError>
inline

Reloads the module from the same path.

Calls Destroy on the old module, unloads the library, loads it again, and calls Build on the new module.

Parameters
appReference to the app for Build/Destroy calls
Returns
Expected with void on success, or error on failure

Definition at line 388 of file dynamic_module.hpp.

388 {
389 if (!Loaded()) {
390 return std::unexpected(DynamicModuleError::NotLoaded);
391 }
392
393 // Call Destroy on the old module
394 HELIOS_INFO("Reloading dynamic module '{}': {}", module_name_, library_.Path().string());
395 module_->Destroy(app);
396
397 // Save the path and config before unloading
398 auto saved_path = library_.Path();
399 auto saved_config = config_;
400
401 // Release module and unload library
402 module_.reset();
403 module_id_ = 0;
404 module_name_.clear();
405
406 auto unload_result = library_.Unload();
407 if (!unload_result) {
408 return std::unexpected(DynamicModuleError::ReloadFailed);
409 }
410
411 // Reload the library
412 auto load_result = library_.Load(saved_path);
413 if (!load_result) {
414 return std::unexpected(DynamicModuleError::ReloadFailed);
415 }
416
417 // Load module symbols and create new instance
418 config_ = saved_config;
419 auto module_result = LoadModuleInstance();
420 if (!module_result) {
421 [[maybe_unused]] auto _ = library_.Unload();
422 return std::unexpected(DynamicModuleError::ReloadFailed);
423 }
424
425 // Call Build on the new module
426 module_->Build(app);
427
428 // Update file time
430
431 HELIOS_INFO("Successfully reloaded dynamic module '{}': {}", module_name_, saved_path.string());
432 return {};
433}
@ ReloadFailed
Failed to reload module.
@ NotLoaded
Module is not loaded.

◆ ReloadIfChanged()

auto helios::app::DynamicModule::ReloadIfChanged ( App app) -> std::expected<void, DynamicModuleError>
inline

Reloads the module only if the file has changed.

Parameters
appReference to the app for Build/Destroy calls
Returns
Expected with void on success, FileNotChanged if not modified, or error on failure

Definition at line 435 of file dynamic_module.hpp.

435 {
436 if (!HasFileChanged()) {
437 return std::unexpected(DynamicModuleError::FileNotChanged);
438 }
439
440 return Reload(app);
441}
auto Reload(App &app) -> std::expected< void, DynamicModuleError >
Reloads the module from the same path.
bool HasFileChanged() const noexcept
Checks if the library file has been modified since last load.
@ FileNotChanged
File has not been modified.

◆ Unload()

auto helios::app::DynamicModule::Unload ( ) -> std::expected<void, DynamicModuleError>
inline

Unloads the current module.

Releases the module and unloads the library.

Returns
Expected with void on success, or error on failure

Definition at line 370 of file dynamic_module.hpp.

370 {
371 if (!Loaded()) {
372 return std::unexpected(DynamicModuleError::NotLoaded);
373 }
374
375 // Release module before unloading library
376 module_.reset();
377 module_id_ = 0;
378 module_name_.clear();
379
380 auto unload_result = library_.Unload();
381 if (!unload_result) {
382 return std::unexpected(DynamicModuleError::LibraryLoadFailed);
383 }
384
385 return {};
386}

◆ UpdateFileTime()

void helios::app::DynamicModule::UpdateFileTime ( )
inlinenoexcept

Updates the cached file modification time.

Call this after detecting a change to reset the tracking.

Definition at line 443 of file dynamic_module.hpp.

443 {
444 if (!library_.Loaded()) {
445 return;
446 }
447
448 std::error_code ec;
449 last_write_time_ = std::filesystem::last_write_time(library_.Path(), ec);
450}