diff options
author | Jef <jef@targetspot.com> | 2024-09-24 08:54:57 -0400 |
---|---|---|
committer | Jef <jef@targetspot.com> | 2024-09-24 08:54:57 -0400 |
commit | 20d28e80a5c861a9d5f449ea911ab75b4f37ad0d (patch) | |
tree | 12f17f78986871dd2cfb0a56e5e93b545c1ae0d0 /Src/external_dependencies/openmpt-trunk/common/ComponentManager.cpp | |
parent | 537bcbc86291b32fc04ae4133ce4d7cac8ebe9a7 (diff) | |
download | winamp-20d28e80a5c861a9d5f449ea911ab75b4f37ad0d.tar.gz |
Initial community commit
Diffstat (limited to 'Src/external_dependencies/openmpt-trunk/common/ComponentManager.cpp')
-rw-r--r-- | Src/external_dependencies/openmpt-trunk/common/ComponentManager.cpp | 475 |
1 files changed, 475 insertions, 0 deletions
diff --git a/Src/external_dependencies/openmpt-trunk/common/ComponentManager.cpp b/Src/external_dependencies/openmpt-trunk/common/ComponentManager.cpp new file mode 100644 index 00000000..4c558ddc --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/common/ComponentManager.cpp @@ -0,0 +1,475 @@ +/* + * ComponentManager.cpp + * -------------------- + * Purpose: Manages loading of optional components. + * Notes : (currently none) + * Authors: Joern Heusipp + * OpenMPT Devs + * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. + */ + +#include "stdafx.h" +#include "ComponentManager.h" + +#include "mpt/mutex/mutex.hpp" + +#include "Logging.h" + +OPENMPT_NAMESPACE_BEGIN + + +ComponentBase::ComponentBase(ComponentType type) + : m_Type(type) + , m_Initialized(false) + , m_Available(false) +{ + return; +} + + +ComponentBase::~ComponentBase() +{ + return; +} + + +void ComponentBase::SetInitialized() +{ + m_Initialized = true; +} + + +void ComponentBase::SetAvailable() +{ + m_Available = true; +} + + +ComponentType ComponentBase::GetType() const +{ + return m_Type; +} + + +bool ComponentBase::IsInitialized() const +{ + return m_Initialized; +} + + +bool ComponentBase::IsAvailable() const +{ + return m_Initialized && m_Available; +} + + +mpt::ustring ComponentBase::GetVersion() const +{ + return mpt::ustring(); +} + + +void ComponentBase::Initialize() +{ + if(IsInitialized()) + { + return; + } + if(DoInitialize()) + { + SetAvailable(); + } + SetInitialized(); +} + + +#if defined(MODPLUG_TRACKER) + + +ComponentLibrary::ComponentLibrary(ComponentType type) + : ComponentBase(type) + , m_BindFailed(false) +{ + return; +} + + +ComponentLibrary::~ComponentLibrary() +{ + return; +} + + +bool ComponentLibrary::AddLibrary(const std::string &libName, const mpt::LibraryPath &libPath) +{ + if(m_Libraries[libName].IsValid()) + { + // prefer previous + return true; + } + mpt::Library lib(libPath); + if(!lib.IsValid()) + { + return false; + } + m_Libraries[libName] = lib; + return true; +} + + +void ComponentLibrary::ClearLibraries() +{ + m_Libraries.clear(); +} + + +void ComponentLibrary::SetBindFailed() +{ + m_BindFailed = true; +} + + +void ComponentLibrary::ClearBindFailed() +{ + m_BindFailed = false; +} + + +bool ComponentLibrary::HasBindFailed() const +{ + return m_BindFailed; +} + + +mpt::Library ComponentLibrary::GetLibrary(const std::string &libName) const +{ + const auto it = m_Libraries.find(libName); + if(it == m_Libraries.end()) + { + return mpt::Library(); + } + return it->second; +} + + +#endif // MODPLUG_TRACKER + + +#if MPT_COMPONENT_MANAGER + + +ComponentFactoryBase::ComponentFactoryBase(const std::string &id, const std::string &settingsKey) + : m_ID(id) + , m_SettingsKey(settingsKey) +{ + return; +} + + +ComponentFactoryBase::~ComponentFactoryBase() +{ + return; +} + + +std::string ComponentFactoryBase::GetID() const +{ + return m_ID; +} + + +std::string ComponentFactoryBase::GetSettingsKey() const +{ + return m_SettingsKey; +} + + +void ComponentFactoryBase::PreConstruct() const +{ + MPT_LOG_GLOBAL(LogInformation, "Components", + MPT_UFORMAT("Constructing Component {}") + ( mpt::ToUnicode(mpt::Charset::ASCII, m_ID) + ) + ); +} + + +void ComponentFactoryBase::Initialize(ComponentManager &componentManager, std::shared_ptr<IComponent> component) const +{ + if(componentManager.IsComponentBlocked(GetSettingsKey())) + { + return; + } + componentManager.InitializeComponent(component); +} + + +// Global list of component register functions. +// We do not use a global scope static list head because the corresponding +// mutex would be no POD type and would thus not be safe to be usable in +// zero-initialized state. +// Function scope static initialization is guaranteed to be thread safe +// in C++11. +// We use this implementation to be future-proof. +// MSVC currently does not exploit the possibility of using multiple threads +// for global lifetime object's initialization. +// An implementation with a simple global list head and no mutex at all would +// thus work fine for MSVC (currently). + +static mpt::mutex & ComponentListMutex() +{ + static mpt::mutex g_ComponentListMutex; + return g_ComponentListMutex; +} + +static ComponentListEntry * & ComponentListHead() +{ + static ComponentListEntry g_ComponentListHeadEmpty = {nullptr, nullptr}; + static ComponentListEntry *g_ComponentListHead = &g_ComponentListHeadEmpty; + return g_ComponentListHead; +} + +bool ComponentListPush(ComponentListEntry *entry) +{ + mpt::lock_guard<mpt::mutex> guard(ComponentListMutex()); +#if MPT_MSVC_BEFORE(2019,0) + // Guard against VS2017 compiler bug causing repeated initialization of inline variables. + // See <https://developercommunity.visualstudio.com/t/static-inline-variable-gets-destroyed-multiple-tim/297876>. + if(entry->next) + { + return false; + } +#endif + entry->next = ComponentListHead(); + ComponentListHead() = entry; + return true; +} + + +static std::shared_ptr<ComponentManager> g_ComponentManager; + + +void ComponentManager::Init(const IComponentManagerSettings &settings) +{ + MPT_LOG_GLOBAL(LogInformation, "Components", U_("Init")); + // cannot use make_shared because the constructor is private + g_ComponentManager = std::shared_ptr<ComponentManager>(new ComponentManager(settings)); +} + + +void ComponentManager::Release() +{ + MPT_LOG_GLOBAL(LogInformation, "Components", U_("Release")); + g_ComponentManager = nullptr; +} + + +std::shared_ptr<ComponentManager> ComponentManager::Instance() +{ + return g_ComponentManager; +} + + +ComponentManager::ComponentManager(const IComponentManagerSettings &settings) + : m_Settings(settings) +{ + mpt::lock_guard<mpt::mutex> guard(ComponentListMutex()); + for(ComponentListEntry *entry = ComponentListHead(); entry; entry = entry->next) + { + if(entry->reg) + { + entry->reg(*this); + } + } +} + + +void ComponentManager::Register(const IComponentFactory &componentFactory) +{ + if(m_Components.find(componentFactory.GetID()) != m_Components.end()) + { + return; + } + RegisteredComponent registeredComponent; + registeredComponent.settingsKey = componentFactory.GetSettingsKey(); + registeredComponent.factoryMethod = componentFactory.GetStaticConstructor(); + registeredComponent.instance = nullptr; + registeredComponent.weakInstance = std::weak_ptr<IComponent>(); + m_Components.insert(std::make_pair(componentFactory.GetID(), registeredComponent)); +} + + +void ComponentManager::Startup() +{ + MPT_LOG_GLOBAL(LogDebug, "Components", U_("Startup")); + if(m_Settings.LoadOnStartup()) + { + for(auto &it : m_Components) + { + it.second.instance = it.second.factoryMethod(*this); + it.second.weakInstance = it.second.instance; + } + } + if(!m_Settings.KeepLoaded()) + { + for(auto &it : m_Components) + { + it.second.instance = nullptr; + } + } +} + + +bool ComponentManager::IsComponentBlocked(const std::string &settingsKey) const +{ + if(settingsKey.empty()) + { + return false; + } + return m_Settings.IsBlocked(settingsKey); +} + + +void ComponentManager::InitializeComponent(std::shared_ptr<IComponent> component) const +{ + if(!component) + { + return; + } + if(component->IsInitialized()) + { + return; + } + component->Initialize(); +} + + +std::shared_ptr<const IComponent> ComponentManager::GetComponent(const IComponentFactory &componentFactory) +{ + std::shared_ptr<IComponent> component = nullptr; + auto it = m_Components.find(componentFactory.GetID()); + if(it != m_Components.end()) + { // registered component + if((*it).second.instance) + { // loaded + component = (*it).second.instance; + } else + { // not loaded + component = (*it).second.weakInstance.lock(); + if(!component) + { + component = (*it).second.factoryMethod(*this); + } + if(m_Settings.KeepLoaded()) + { // keep the component loaded + (*it).second.instance = component; + } + (*it).second.weakInstance = component; + } + } else + { // unregistered component + component = componentFactory.Construct(*this); + } + MPT_ASSERT(component); + return component; +} + + +std::shared_ptr<const IComponent> ComponentManager::ReloadComponent(const IComponentFactory &componentFactory) +{ + std::shared_ptr<IComponent> component = nullptr; + auto it = m_Components.find(componentFactory.GetID()); + if(it != m_Components.end()) + { // registered component + if((*it).second.instance) + { // loaded + (*it).second.instance = nullptr; + if(!(*it).second.weakInstance.expired()) + { + throw std::runtime_error("Component not completely unloaded. Cannot reload."); + } + (*it).second.weakInstance = std::weak_ptr<IComponent>(); + } + // not loaded + component = (*it).second.factoryMethod(*this); + if(m_Settings.KeepLoaded()) + { // keep the component loaded + (*it).second.instance = component; + } + (*it).second.weakInstance = component; + } else + { // unregistered component + component = componentFactory.Construct(*this); + } + MPT_ASSERT(component); + return component; +} + + +std::vector<std::string> ComponentManager::GetRegisteredComponents() const +{ + std::vector<std::string> result; + result.reserve(m_Components.size()); + for(const auto &it : m_Components) + { + result.push_back(it.first); + } + return result; +} + + +ComponentInfo ComponentManager::GetComponentInfo(std::string name) const +{ + ComponentInfo result; + result.name = name; + result.state = ComponentStateUnregistered; + result.settingsKey = ""; + result.type = ComponentTypeUnknown; + const auto it = m_Components.find(name); + if(it == m_Components.end()) + { + result.state = ComponentStateUnregistered; + return result; + } + result.settingsKey = it->second.settingsKey; + if(IsComponentBlocked(it->second.settingsKey)) + { + result.state = ComponentStateBlocked; + return result; + } + std::shared_ptr<IComponent> component = it->second.instance; + if(!component) + { + component = it->second.weakInstance.lock(); + } + if(!component) + { + result.state = ComponentStateUnintialized; + return result; + } + result.type = component->GetType(); + if(!component->IsInitialized()) + { + result.state = ComponentStateUnintialized; + return result; + } + if(!component->IsAvailable()) + { + result.state = ComponentStateUnavailable; + return result; + } + result.state = ComponentStateAvailable; + return result; +} + + +mpt::PathString ComponentManager::GetComponentPath() const +{ + return m_Settings.Path(); +} + + +#endif // MPT_COMPONENT_MANAGER + + +OPENMPT_NAMESPACE_END |